From 1e75de0e0e895a81684ca34b3f3093d2fabd5cff Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Fri, 11 Dec 2020 07:15:35 +0100 Subject: [PATCH] Add support for public ECR Signed-off-by: CrazyMax --- .github/workflows/ci.yml | 2 +- README.md | 69 +++++++++++++++++++++++++++++++++++++--- __tests__/aws.test.ts | 26 +++++++++++---- dist/index.js | 24 ++++++++++---- src/aws.ts | 14 ++++++-- src/docker.ts | 9 ++++-- 6 files changed, 121 insertions(+), 23 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index a32e27c..ee13e6b 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -50,7 +50,7 @@ jobs: name: Checkout uses: actions/checkout@v2 - - name: Login to DockerHub + name: Login to Docker Hub uses: ./ with: username: ${{ secrets.DOCKERHUB_USERNAME }} diff --git a/README.md b/README.md index 10dd13f..667e1d5 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ GitHub Action to login against a Docker registry. ___ * [Usage](#usage) - * [DockerHub](#dockerhub) + * [Docker Hub](#docker-hub) * [GitHub Packages Docker Registry](#github-packages-docker-registry) * [GitHub Container Registry](#github-container-registry) * [GitLab](#gitlab) @@ -26,6 +26,7 @@ ___ * [Google Container Registry (GCR)](#google-container-registry-gcr) * [Google Artifact Registry (GAR)](#google-artifact-registry-gar) * [AWS Elastic Container Registry (ECR)](#aws-elastic-container-registry-ecr) + * [AWS Public Elastic Container Registry (ECR)](#aws-public-elastic-container-registry-ecr) * [OCI Oracle Cloud Infrastructure Registry (OCIR)](#oci-oracle-cloud-infrastructure-registry-ocir) * [Customizing](#customizing) * [inputs](#inputs) @@ -34,9 +35,9 @@ ___ ## Usage -### DockerHub +### Docker Hub -To authenticate against [DockerHub](https://hub.docker.com) it's strongly recommended to create a +To authenticate against [Docker Hub](https://hub.docker.com) it's strongly recommended to create a [personal access token](https://docs.docker.com/docker-hub/access-tokens/) as an alternative to your password. ```yaml @@ -51,7 +52,7 @@ jobs: runs-on: ubuntu-latest steps: - - name: Login to DockerHub + name: Login to Docker Hub uses: docker/login-action@v1 with: username: ${{ secrets.DOCKERHUB_USERNAME }} @@ -280,6 +281,66 @@ jobs: > Replace `` and `` with their respective values. +### AWS Public Elastic Container Registry (ECR) + +Use an IAM user with the [ability to push to ECR](https://docs.aws.amazon.com/AmazonECR/latest/userguide/ecr_managed_policies.html). +Then create and download access keys and save `AWS_ACCESS_KEY_ID` and `AWS_SECRET_ACCESS_KEY` [as secrets](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository) +in your GitHub repo. + +```yaml +name: ci + +on: + push: + branches: master + +jobs: + login: + runs-on: ubuntu-latest + steps: + - + name: Login to Public ECR + uses: docker/login-action@v1 + with: + registry: public.ecr.aws + username: ${{ secrets.AWS_ACCESS_KEY_ID }} + password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + env: + AWS_REGION: +``` + +> Replace `` with its respective value (default `us-east-1`). + +You can also use the [Configure AWS Credentials](https://github.com/aws-actions/configure-aws-credentials) action in +combination with this action: + +```yaml +name: ci + +on: + push: + branches: master + +jobs: + login: + runs-on: ubuntu-latest + steps: + - + name: Configure AWS Credentials + uses: aws-actions/configure-aws-credentials@v1 + with: + aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }} + aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + aws-region: + - + name: Login to Public ECR + uses: docker/login-action@v1 + with: + registry: public.ecr.aws +``` + +> Replace `` with its respective value. + ### OCI Oracle Cloud Infrastructure Registry (OCIR) To push into OCIR in specific tenancy the [username](https://www.oracle.com/webfolder/technetwork/tutorials/obe/oci/registry/index.html#LogintoOracleCloudInfrastructureRegistryfromtheDockerCLI) must be placed in format `/` (in case of federated tenancy use the format `/oracleidentitycloudservice/`). diff --git a/__tests__/aws.test.ts b/__tests__/aws.test.ts index a1b53f1..07bf272 100644 --- a/__tests__/aws.test.ts +++ b/__tests__/aws.test.ts @@ -5,12 +5,24 @@ describe('isECR', () => { test.each([ ['registry.gitlab.com', false], ['gcr.io', false], - ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true] + ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', true], + ['public.ecr.aws', true] ])('given registry %p', async (registry, expected) => { expect(await aws.isECR(registry)).toEqual(expected); }); }); +describe('isPubECR', () => { + test.each([ + ['registry.gitlab.com', false], + ['gcr.io', false], + ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', false], + ['public.ecr.aws', true] + ])('given registry %p', async (registry, expected) => { + expect(await aws.isPubECR(registry)).toEqual(expected); + }); +}); + describe('getCLI', () => { it('exists', async () => { const awsPath = await aws.getCLI(); @@ -45,10 +57,10 @@ describe('parseCLIVersion', () => { }); describe('getRegion', () => { - test.each([['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3']])( - 'given registry %p', - async (registry, expected) => { - expect(await aws.getRegion(registry)).toEqual(expected); - } - ); + test.each([ + ['012345678901.dkr.ecr.eu-west-3.amazonaws.com', 'eu-west-3'], + ['public.ecr.aws', 'us-east-1'] + ])('given registry %p', async (registry, expected) => { + expect(await aws.getRegion(registry)).toEqual(expected); + }); }); diff --git a/dist/index.js b/dist/index.js index 8d45f5a..0b7bfa5 100644 --- a/dist/index.js +++ b/dist/index.js @@ -3072,7 +3072,7 @@ function loginStandard(registry, username, password) { core.info(`🔑 Logging into ${registry}...`); } else { - core.info(`🔑 Logging into DockerHub...`); + core.info(`🔑 Logging into Docker Hub...`); } yield execm.exec('docker', loginArgs, true, password).then(res => { if (res.stderr != '' && !res.success) { @@ -3088,7 +3088,12 @@ function loginECR(registry, username, password) { const cliPath = yield aws.getCLI(); const cliVersion = yield aws.getCLIVersion(); const region = yield aws.getRegion(registry); - core.info(`💡 AWS ECR detected with ${region} region`); + if (yield aws.isPubECR(registry)) { + core.info(`💡 AWS Public ECR detected with ${region} region`); + } + else { + core.info(`💡 AWS ECR detected with ${region} region`); + } process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID; process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY; core.info(`⬇️ Retrieving docker login command through AWS CLI ${cliVersion} (${cliPath})...`); @@ -4155,14 +4160,20 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge }); }; Object.defineProperty(exports, "__esModule", { value: true }); -exports.getDockerLoginCmd = exports.parseCLIVersion = exports.getCLIVersion = exports.execCLI = exports.getCLI = exports.getRegion = exports.isECR = void 0; +exports.getDockerLoginCmd = exports.parseCLIVersion = exports.getCLIVersion = exports.execCLI = exports.getCLI = exports.getRegion = exports.isPubECR = exports.isECR = void 0; const semver = __importStar(__webpack_require__(383)); const io = __importStar(__webpack_require__(436)); const execm = __importStar(__webpack_require__(757)); exports.isECR = (registry) => __awaiter(void 0, void 0, void 0, function* () { - return registry.includes('amazonaws'); + return registry.includes('amazonaws') || (yield exports.isPubECR(registry)); +}); +exports.isPubECR = (registry) => __awaiter(void 0, void 0, void 0, function* () { + return registry === 'public.ecr.aws'; }); exports.getRegion = (registry) => __awaiter(void 0, void 0, void 0, function* () { + if (yield exports.isPubECR(registry)) { + return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1'; + } return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); }); exports.getCLI = () => __awaiter(void 0, void 0, void 0, function* () { @@ -4192,13 +4203,14 @@ exports.parseCLIVersion = (stdout) => __awaiter(void 0, void 0, void 0, function return semver.clean(matches[1]); }); exports.getDockerLoginCmd = (cliVersion, registry, region) => __awaiter(void 0, void 0, void 0, function* () { + let ecrCmd = (yield exports.isPubECR(registry)) ? 'ecr-public' : 'ecr'; if (semver.satisfies(cliVersion, '>=2.0.0')) { - return exports.execCLI(['ecr', 'get-login-password', '--region', region]).then(pwd => { + return exports.execCLI([ecrCmd, 'get-login-password', '--region', region]).then(pwd => { return `docker login --username AWS --password ${pwd} ${registry}`; }); } else { - return exports.execCLI(['ecr', 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { + return exports.execCLI([ecrCmd, 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { return dockerLoginCmd; }); } diff --git a/src/aws.ts b/src/aws.ts index bab461f..c6aa9c7 100644 --- a/src/aws.ts +++ b/src/aws.ts @@ -3,10 +3,17 @@ import * as io from '@actions/io'; import * as execm from './exec'; export const isECR = async (registry: string): Promise => { - return registry.includes('amazonaws'); + return registry.includes('amazonaws') || (await isPubECR(registry)); +}; + +export const isPubECR = async (registry: string): Promise => { + return registry === 'public.ecr.aws'; }; export const getRegion = async (registry: string): Promise => { + if (await isPubECR(registry)) { + return process.env.AWS_REGION || process.env.AWS_DEFAULT_REGION || 'us-east-1'; + } return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); }; @@ -39,12 +46,13 @@ export const parseCLIVersion = async (stdout: string): Promise => { }; export const getDockerLoginCmd = async (cliVersion: string, registry: string, region: string): Promise => { + let ecrCmd = (await isPubECR(registry)) ? 'ecr-public' : 'ecr'; if (semver.satisfies(cliVersion, '>=2.0.0')) { - return execCLI(['ecr', 'get-login-password', '--region', region]).then(pwd => { + return execCLI([ecrCmd, 'get-login-password', '--region', region]).then(pwd => { return `docker login --username AWS --password ${pwd} ${registry}`; }); } else { - return execCLI(['ecr', 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { + return execCLI([ecrCmd, 'get-login', '--region', region, '--no-include-email']).then(dockerLoginCmd => { return dockerLoginCmd; }); } diff --git a/src/docker.ts b/src/docker.ts index a5de9ea..fd3f773 100644 --- a/src/docker.ts +++ b/src/docker.ts @@ -30,7 +30,7 @@ export async function loginStandard(registry: string, username: string, password if (registry) { core.info(`🔑 Logging into ${registry}...`); } else { - core.info(`🔑 Logging into DockerHub...`); + core.info(`🔑 Logging into Docker Hub...`); } await execm.exec('docker', loginArgs, true, password).then(res => { if (res.stderr != '' && !res.success) { @@ -44,7 +44,12 @@ export async function loginECR(registry: string, username: string, password: str const cliPath = await aws.getCLI(); const cliVersion = await aws.getCLIVersion(); const region = await aws.getRegion(registry); - core.info(`💡 AWS ECR detected with ${region} region`); + + if (await aws.isPubECR(registry)) { + core.info(`💡 AWS Public ECR detected with ${region} region`); + } else { + core.info(`💡 AWS ECR detected with ${region} region`); + } process.env.AWS_ACCESS_KEY_ID = username || process.env.AWS_ACCESS_KEY_ID; process.env.AWS_SECRET_ACCESS_KEY = password || process.env.AWS_SECRET_ACCESS_KEY;