GitHub Actions でAmazonECRにdockerイメージをpushする

#はじめに
Amazon ECRにGitHubActionsからdockerイメージをPushしてみたので記事にします。

#目次
[1. 最終的なコード](#1-最終的なコード)
[2. secret機能の利用](#2-secret機能の利用)
[3. assume-roleで認証](#3-assume-roleで認証)
[4. $GITHUB_ENVで環境変数を定義](#4-$GITHUB_ENVで環境変数を定義)
[5. latestの利用](#5-latestの利用)

##1. 最終的なコード
```yaml:~/.github/workflows/build.yaml
name: Build and push image to Amazon ECR

on:
  push:
    branches:
      - feature_actions
  workflow_dispatch:

jobs:
  verification-and-build:
    runs-on: ubuntu-latest
    env:
      ECR_REPOSITORY: actions-ecr-demo
    steps:
      - name: Checkout
        uses: actions/checkout@v2
      - name: Setup java
        uses: actions/setup-java@v2
        with:
          distribution: 'adopt'
          java-version: '11'
      - name: Verification
        run: ./gradlew check
      - name: Build
        run: ./gradlew build -x test
      - 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: ap-northeast-1
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
      - name: Login to Amazon ECR
        id: login-ecr
        uses: aws-actions/amazon-ecr-login@v1
      - name: Set environment variables
        run: |
          echo "IMAGE_TAG=$(echo ${{ github.sha }} | head -c 8)" >> $GITHUB_ENV
          echo "ECR_REGISTRY=${{ steps.login-ecr.outputs.registry }}/$ECR_REPOSITORY" >> $GITHUB_ENV
      - name: Build Docker images
        run: docker build -t $ECR_REGISTRY:$IMAGE_TAG -t $ECR_REGISTRY:latest .
      - name: Push image to Amazon ECR
        run: docker push --all-tags $ECR_REGISTRY

```

##2. secret機能の利用
以下の部分はgitのsecrets機能を利用し、コード上で管理したくないアクセスキーなどをマスクするために利用します。

```yaml
          aws-access-key-id: ${{ secrets.AWS_ACCESS_KEY_ID }}
          aws-secret-access-key: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
          ...
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
```

GitHubの `Settings -> Secrets`から設定します。
![スクリーンショット 2021-08-17 23.10.35.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756249/e05dc8d8-0a86-56b0-9a2b-70b198406113.png)

##3. assume-roleで認証
スイッチロール下でIAMユーザを利用している場合は以下のドキュメントにあるようにassume-roleを利用して認証します。
["Configure AWS Credentials" Action For GitHub Actions](https://github.com/marketplace/actions/configure-aws-credentials-action-for-github-actions)

```yaml
  role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
```

注意点として、スイッチ先の信頼ポリシーとスイッチ元の自身のIAMユーザにセッションタグへのアクセスを許可する必要があります。

```json:スイッチ先の信頼ポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": {
        "AWS": "arn:aws:iam::<acountId>:root"
      },
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"  # "sts:TagSession"を追加
      ],
      "Condition": {}
    }
  ]
}
```

```json:IAMユーザに付与するポリシー
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "sts:AssumeRole",
        "sts:TagSession"  # "sts:TagSession"をIAMユーザにも追加
      ],
      "Resource": "arn:aws:iam::{スイッチ先のアカウントID}:role/{付与するrole}"
    }
  ]
}
```

以下のエラーが発生し、セッションタグの利用について特に必要でなければセッションタグの設定をスキップすることもできます。


```
User: arn:aws:iam::***:user/{userName} is not authorized to perform: sts:TagSession on resource: ***
```

```yaml
  role-skip-session-tagging: true
```

##4. $GITHUB_ENVで環境変数を定義
特定のstepで`$GITHUB_ENV`に使用したい値をリダイレクトすることで以降のstepで使用可能となります。（`$GITHUB_ENV`にリダイレクトしたstep内では使用できないので注意して下さい）
用途としては、以下の場合は考えられます。

- 後続のstepで何度も使用したい
- jobの環境変数のように静的な値ではなく、step実行時に生成される動的は値を環境変数として使用したい

##5. latestの利用
dockerイメージのイメージタグをlatestとして設定したい場合は、commitのshaハッシュ値を同時に設定すると良いです。
以下の画像のようにlatestのみの場合は新しくlatestタグを設定した時にイメージタグが設定されていない状態になるのを回避できます。

![スクリーンショット 2021-08-17 23.58.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/756249/83f680fd-8251-8a43-b4b4-9d86dadbe499.png)