とことんDevOps | 日本仮想化技術のDevOps技術情報メディア

DevOpsに関連する技術情報を幅広く提供していきます。

日本仮想化技術がお届けする「とことんDevOps」では、DevOpsに関する技術情報や、日々のDevOps業務の中での検証結果、TipsなどDevOpsのお役立ち情報をお届けします。
主なテーマ: DevOps、CI/CD、コンテナ開発、IaCなど
読者登録と各種SNSのフォローもよろしくお願いいたします。

GitHub ActionsでOIDCを使ってみる

GitHub ActionsがOpenID Connect(OIDC)をサポートしたのは結構前の話なんですが、未だ検証できていませんでした。社内でもSecretにクレデンシャル持つのはそろそろ辞めたいよねっという話が出ていますので、検証がてら記録を残しておきます。

ゴール

GitHub ActionsからAWS ECRにコンテナイメージをPushするところまでをゴールとします。

AWSの設定

IDプロバイダの作成

GitHub ActionsからAWSにOIDCで接続するには、AWS側にIDプロバイダの設定が必要です。以下のドキュメント通りにやればうまくいきます。

https://docs.github.com/ja/actions/deployment/security-hardening-your-deployments/configuring-openid-connect-in-amazon-web-services#adding-the-identity-provider-to-aws

  • プロバイダの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が成功していると思います。