From f37c715508b6806a16a49dcdf39c32efd2d013ef Mon Sep 17 00:00:00 2001 From: CrazyMax Date: Thu, 20 Aug 2020 15:59:36 +0200 Subject: [PATCH] Add support for AWS Elastic Container Registry (ECR) Add example for Google Container Registry (GCR) --- .github/workflows/ci.yml | 26 ++++++++++++++++ README.md | 66 ++++++++++++++++++++++++++++++++++++++-- dist/index.js | 58 +++++++++++++++++++++++++++++------ src/ecr.ts | 7 +++++ src/main.ts | 35 ++++++++++++++------- 5 files changed, 169 insertions(+), 23 deletions(-) create mode 100644 src/ecr.ts diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 06eee13..e88befa 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -83,3 +83,29 @@ jobs: if: always() run: | rm -f ${HOME}/.docker/config.json + + ecr: + runs-on: ubuntu-latest + strategy: + fail-fast: false + matrix: + logout: + - true + - false + steps: + - + name: Checkout + uses: actions/checkout@v2.3.1 + - + name: Login to ECR + uses: ./ + with: + registry: ${{ secrets.AWS_ACCOUNT_NUMBER }}.dkr.ecr.${{ secrets.AWS_REGION }}.amazonaws.com + username: ${{ secrets.AWS_ACCESS_KEY_ID }} + password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + logout: ${{ matrix.logout }} + - + name: Clear + if: always() + run: | + rm -f ${HOME}/.docker/config.json diff --git a/README.md b/README.md index eb19f7f..a3f0712 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,8 @@ ___ * [DockerHub](#dockerhub) * [GitHub Package Registry](#github-package-registry) * [GitLab](#gitlab) + * [Google Container Registry (GCR)](#gitlab) + * [AWS Elastic Container Registry (ECR)](#gitlab) * [Customizing](#customizing) * [inputs](#inputs) * [Limitation](#limitation) @@ -34,7 +36,6 @@ name: ci on: push: branches: master - tags: jobs: login: @@ -59,7 +60,6 @@ name: ci on: push: branches: master - tags: jobs: login: @@ -85,7 +85,6 @@ name: ci on: push: branches: master - tags: jobs: login: @@ -103,6 +102,67 @@ jobs: password: ${{ secrets.GITLAB_PASSWORD }} ``` +### Google Container Registry (GCR) + +Use a service account with the ability to push to GCR and [configure access control](https://cloud.google.com/container-registry/docs/access-control). +Then create and download the JSON key for this service account and save content of `.json` file +[as a secret](https://docs.github.com/en/actions/configuring-and-managing-workflows/creating-and-storing-encrypted-secrets#creating-encrypted-secrets-for-a-repository) +called `GCR_JSON_KEY` in your GitHub repo. Ensure you set the username to `_json_key`. + +```yaml +name: ci + +on: + push: + branches: master + +jobs: + login: + runs-on: ubuntu-latest + steps: + - + name: Checkout + uses: actions/checkout@v2 + - + name: Login to GCR + uses: crazy-max/ghaction-docker-login@v1 + with: + registry: gcr.io + username: _json_key + password: ${{ secrets.GCR_JSON_KEY }} +``` + +### AWS 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: Checkout + uses: actions/checkout@v2 + - + name: Login to ECR + uses: crazy-max/ghaction-docker-login@v1 + with: + registry: .dkr.ecr..amazonaws.com + username: ${{ secrets.AWS_ACCESS_KEY_ID }} + password: ${{ secrets.AWS_SECRET_ACCESS_KEY }} +``` + +> Replace `` and `` with their respective values. + ## Customizing ### inputs diff --git a/dist/index.js b/dist/index.js index 297dee2..7e033a1 100644 --- a/dist/index.js +++ b/dist/index.js @@ -953,6 +953,32 @@ class ExecState extends events.EventEmitter { /***/ }), +/***/ 34: +/***/ (function(__unusedmodule, exports) { + +"use strict"; + +var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) { + function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); } + return new (P || (P = Promise))(function (resolve, reject) { + function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } + function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } + function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); } + step((generator = generator.apply(thisArg, _arguments || [])).next()); + }); +}; +Object.defineProperty(exports, "__esModule", { value: true }); +exports.getRegion = exports.isECR = void 0; +exports.isECR = (registry) => __awaiter(void 0, void 0, void 0, function* () { + return registry.includes('amazonaws'); +}); +exports.getRegion = (registry) => __awaiter(void 0, void 0, void 0, function* () { + return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); +}); +//# sourceMappingURL=ecr.js.map + +/***/ }), + /***/ 87: /***/ (function(module) { @@ -1048,6 +1074,7 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge Object.defineProperty(exports, "__esModule", { value: true }); const os = __importStar(__webpack_require__(87)); const core = __importStar(__webpack_require__(470)); +const ecr = __importStar(__webpack_require__(34)); const exec = __importStar(__webpack_require__(807)); const stateHelper = __importStar(__webpack_require__(153)); function run() { @@ -1062,17 +1089,30 @@ function run() { stateHelper.setLogout(core.getInput('logout')); const username = core.getInput('username'); const password = core.getInput('password', { required: true }); - let loginArgs = ['login', '--password', password]; - if (username) { - loginArgs.push('--username', username); + if (yield ecr.isECR(registry)) { + const ecrRegion = yield ecr.getRegion(registry); + process.env.AWS_ACCESS_KEY_ID = username; + process.env.AWS_SECRET_ACCESS_KEY = password; + yield exec.exec('aws', ['ecr', 'get-login', '--region', ecrRegion, '--no-include-email'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + core.info('🎉 Login Succeeded!'); + }); } - loginArgs.push(registry); - yield exec.exec('docker', loginArgs, true).then(res => { - if (res.stderr != '' && !res.success) { - throw new Error(res.stderr); + else { + let loginArgs = ['login', '--password', password]; + if (username) { + loginArgs.push('--username', username); } - core.info('🎉 Login Succeeded!'); - }); + loginArgs.push(registry); + yield exec.exec('docker', loginArgs, true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + core.info('🎉 Login Succeeded!'); + }); + } } catch (error) { core.setFailed(error.message); diff --git a/src/ecr.ts b/src/ecr.ts new file mode 100644 index 0000000..00d0bda --- /dev/null +++ b/src/ecr.ts @@ -0,0 +1,7 @@ +export const isECR = async (registry: string): Promise => { + return registry.includes('amazonaws'); +}; + +export const getRegion = async (registry: string): Promise => { + return registry.substring(registry.indexOf('ecr.') + 4, registry.indexOf('.amazonaws')); +}; diff --git a/src/main.ts b/src/main.ts index 5f8473e..a64fdab 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import * as os from 'os'; import * as core from '@actions/core'; +import * as ecr from './ecr'; import * as exec from './exec'; import * as stateHelper from './state-helper'; @@ -17,18 +18,30 @@ async function run(): Promise { const username: string = core.getInput('username'); const password: string = core.getInput('password', {required: true}); - let loginArgs: Array = ['login', '--password', password]; - if (username) { - loginArgs.push('--username', username); - } - loginArgs.push(registry); - - await exec.exec('docker', loginArgs, true).then(res => { - if (res.stderr != '' && !res.success) { - throw new Error(res.stderr); + if (await ecr.isECR(registry)) { + const ecrRegion = await ecr.getRegion(registry); + process.env.AWS_ACCESS_KEY_ID = username; + process.env.AWS_SECRET_ACCESS_KEY = password; + await exec.exec('aws', ['ecr', 'get-login', '--region', ecrRegion, '--no-include-email'], true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + core.info('🎉 Login Succeeded!'); + }); + } else { + let loginArgs: Array = ['login', '--password', password]; + if (username) { + loginArgs.push('--username', username); } - core.info('🎉 Login Succeeded!'); - }); + loginArgs.push(registry); + + await exec.exec('docker', loginArgs, true).then(res => { + if (res.stderr != '' && !res.success) { + throw new Error(res.stderr); + } + core.info('🎉 Login Succeeded!'); + }); + } } catch (error) { core.setFailed(error.message); }