GitHub ActionsがOpenID Connect(OIDC)をサポートしたのは結構前の話なんですが、未だ検証できていませんでした。社内でもSecretにクレデンシャル持つのはそろそろ辞めたいよねっという話が出ていますので、検証がてら記録を残しておきます。
ゴール
GitHub ActionsからAWS ECRにコンテナイメージをPushするところまでをゴールとします。
AWSの設定
IDプロバイダの作成
GitHub ActionsからAWSにOIDCで接続するには、AWS側にIDプロバイダの設定が必要です。以下のドキュメント通りにやればうまくいきます。
- プロバイダのURLに「https://token.actions.githubusercontent.com」を入力
- サムプリントを取得をポチ
- 対象者に「sts.amazonaws.com」を入力
- 作成されたIDプロバイダをクリックすると詳細が見られるのでArnをコピー
aws-cliからやる場合は少し面倒です。IDプロバイダを追加するには「サムプリント」というものが必要で、詳しいことはココに書いてあります。要するにCA証明書のハッシュ値=サムプリントのようです。
macな人はopensslをインストールしてください。
brew install openssl
CLIからはこれで作成できます。Arnが表示されるのでコピーしておいてください。
url=https://token.actions.githubusercontent.com thumbprint=$(curl -Ssf $url/.well-known/openid-configuration | grep -oE '"jwks_uri":"[^"]+"' | sed -E 's/^.*:\/\/([^/]*)\/.*$/\1/' | xargs -rd\\n -I%s openssl s_client -servername %s -showcerts -connect %s:443 < /dev/null 2>/dev/null | awk '/BEGIN/,/END/{if (/BEGIN/) {a++}; if (a==2) print}' | openssl x509 -fingerprint -noout | cut -d= -f2 | tr -d :) aws iam create-open-id-connect-provider --url $url --thumbprint-list $thumbprint --client-id-list sts.amazonaws.com
コンソールからやった方がシンプルですね。
ロールの作成
以下のJSONを「assume-role-policy.json」というファイルに保存してください。
<<ID-PROVIDER-ARN>>
はIDプロバイダの作成でコピーしたArnに置き換えてください。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "", "Effect": "Allow", "Principal": { "Federated": "<<ID-PROVIDER-ARN>>" }, "Action": "sts:AssumeRoleWithWebIdentity" } ] }
ロールを作成します。
aws iam create-role --role-name role-with-oidc --assume-role-policy-document file://assume-role-policy.json
次に権限を付与していきます。以下のJSONを「policy.json」というファイルに保存してください。
{ "Version": "2012-10-17", "Statement": [ { "Sid": "AllowPushPull", "Effect": "Allow", "Action": [ "ecr:BatchGetImage", "ecr:BatchCheckLayerAvailability", "ecr:CompleteLayerUpload", "ecr:GetAuthorizationToken", "ecr:GetDownloadUrlForLayer", "ecr:InitiateLayerUpload", "ecr:PutImage", "ecr:UploadLayerPart" ], "Resource": "*" } ] }
ロールにインラインポリシーを作成します。
aws iam put-role-policy --role-name role-with-oidc --policy-name AllowPushPull --policy-document file://policy.json
Push先のリポジトリを東京リージョンに作成します。
aws ecr create-repository --repository-name myapp --region ap-northeast-1
以上でAWS側の設定は完了です。
GitHubの設定
Actionsを実行するためにリポジトリが1つ必要になります。作成して手元にCloneしておいてください。ちなみに私はaws-github-oidcでリポジトリを作成しました。
リポジトリの用意ができたらシークレットを登録します。
Settings > Secrets > Actions > New repository secretの順に進み、Nameが「ASSUME_ROLE_ARN」、Secretは以下のコマンドで取得した値を入力してください。
aws iam list-roles --query 'Roles[?RoleName==`role-with-oidc`].Arn' --output text
ghコマンドがインストール済みであれば、以下のように登録してもいいです。
aws iam list-roles --query 'Roles[?RoleName==`role-with-oidc`].Arn' --output text | gh secret set ASSUME_ROLE_ARN
ワークフローを作成します。
install -Dd .github/workflows
以下のYAMLを.github/workflows/main.yml
に保存してください。
on: push jobs: deploy: name: Upload to Amazon ECR runs-on: ubuntu-latest permissions: id-token: write contents: read steps: - name: Checkout uses: actions/checkout@v2 - name: Configure AWS credentials uses: aws-actions/configure-aws-credentials@v1 with: role-to-assume: ${{ secrets.ASSUME_ROLE_ARN }} aws-region: ap-northeast-1 - name: Login to Amazon ECR Public id: login-ecr uses: aws-actions/amazon-ecr-login@v1 - name: Shorten hash id: shorten_hash shell: bash run: echo "##[set-output name=hash;]${GITHUB_SHA::7}" - name: Build, tag, and push docker image to Amazon ECR Public env: REGISTRY: ${{ steps.login-ecr.outputs.registry }} REPOSITORY: myapp IMAGE_TAG: ${{ steps.shorten_hash.outputs.hash }} run: | docker buildx build -t "$REGISTRY/$REPOSITORY:$IMAGE_TAG" . docker push "$REGISTRY/$REPOSITORY:$IMAGE_TAG" working-directory: app
このワークフロー内でコンテナイメージのビルドも行っています。リポジトリルートに以下のDockerfileを設置しておいてください。
FROM nginx:1.23
ここまでで作ったファイルをリポジトリ含めてmainにPushします。
git add --all git commit -am 'add files' git push origin main
Actionsの画面をご確認ください。ここまでの設定に不備がなければ、ECRにPushが成功していると思います。