本日のお題
- CD/CDなどでGitHub Actionからcdk deployコマンドを実施する際に、OIDCを使用して(IAM Userのアクセスキー&シークレットアクセスキーではなく)IAM RoleでAWSと認証を行う方法
- 上記をAWS CDKで実装する方法
上記を実施する際に必要な手順
- IAM OIDC IDプロバイダーを作成する
- 認証用のIAM Roleを作成する
- 上記IAM Roleに必要なポリシーをアタッチする
- GitHub Actionsにてconfigure-aws-credentialsを使用してAWSと認証する
AWS CDKのコード
今回は、いきなりAWS CDKのコードを掲載します。(多分その方がわかりやすいので)
import * as cdk from 'aws-cdk-lib'; import { aws_iam } from 'aws-cdk-lib'; import { Construct } from 'constructs'; export class OIDCSampleStack extends cdk.Stack { constructor(scope: Construct, id: string) { super(scope, id); // cdk deployAWSを実施するAWSアカウントとリージョン const accountId = this.account; const region = this.region; const user = '<対象のGitHubユーザー名>'; const repo = '<対象のリポジトリ名>'; const branch = '<対象のブランチ名>'; // 1. IAM OIDC IDプロバイダーを作成する const oidcProvider = new aws_iam.OpenIdConnectProvider( this, 'GitHubOIDCProvider', { url: 'https://token.actions.githubusercontent.com', clientIds: ['sts.amazonaws.com'], } ); // 2. 認証用のIAM Roleを作成する const oidcDeployRole = new aws_iam.Role(this, 'GitHubOidcRole', { roleName: 'github-oidc-role', assumedBy: new aws_iam.FederatedPrincipal( oidcProvider.openIdConnectProviderArn, { StringLike: { 'token.actions.githubusercontent.com:sub': `repo:${user}/${repo}:ref:refs/heads/${branch}`, }, }, 'sts:AssumeRoleWithWebIdentity' //これを忘れるとStatementのActionが'sts:AssumeRole'となりOIDCでのAssumeRoleで使えなくなる。 ), }); // 3. 上記IAM Roleに必要なポリシーをアタッチする const deployPolicy = new aws_iam.Policy(this, 'deployPolicy', { policyName: 'deployPolicy', statements: [ new aws_iam.PolicyStatement({ effect: aws_iam.Effect.ALLOW, actions: ['sts:AssumeRole'], resources: [ `arn:aws:iam::${accountId}:role/cdk-hnb659fds-deploy-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-file-publishing-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-image-publishing-role-${accountId}-${region}`, `arn:aws:iam::${accountId}:role/cdk-hnb659fds-lookup-role-${accountId}-${region}`, ], }), ], }); oidcDeployRole.attachInlinePolicy(deployPolicy); } }
1. IAM OIDC IDプロバイダーを作成する
IAM OIDC IDプロバイダーを作成し、そのURLに https://token.actions.githubusercontent.com
(このホスト名は固定)、クライアントIDにAWS Security Token Service (AWS STS)を指定します。
2. 認証用のIAM Roleを作成する
IAM OIDC IDプロバイダーに対し、GitHub Actionsからのフェデレーション認証の場合にAssume Roleをを許可するIAM Roleを作成します。
そしてそのURLに https://token.actions.githubusercontent.com
、クライアントIDにAWS Security Token Service (AWS STS)を指定します。
またその際にGitHubのユーザー名、リポジトリ名、ブランチ名を指定し、対象のブランチでのみ認証を行うようにします。
なおこの時assumeRoleAction
引数に「sts:AssumeRoleWithWebIdentity」を指定しないとOIDCでのAssumeRoleが出来ないので注意です。(「sts:AssumeRole」ではダメ)
3. 上記IAM Roleに必要なポリシーをアタッチする
上記IAM ポリシーを作成し、上記IAM Roleにアタッチします。
今回はcdk deploy
を実施する用のポリシーをインラインポリシーとしてアタッチしています。
ちなみに上記ポリシーの内容&sts:AssumeRole元のリソースの内容については、下記をご参照ください。(事前に cdk bootstrap
が実施済であることが前提です)
GitHub Enterprise(GHE) の場合
もちろん今回の方法はGHEでも使用できますが、GHEの場合、GitHubと以下の点が異なります。
- ユーザー名を指定していた箇所は、GHEではorganization名を指定する
- ホスト名は
token.actions.githubusercontent.com
ではなく、 「<GHEのドメイン名>/_services/token」になる
例えばorganizationが「my_org」、GHEのドメイン名が「github.hogehoge.com」の場合、CDKのソースはこうなります。(差分だけ記載)
const oidcProvider = new aws_iam.OpenIdConnectProvider( this, 'GitHubOIDCProvider', { url: 'https://github.hogehoge.com/_services/token', clientIds: ['sts.amazonaws.com'], } ); // 2. 認証用のIAM Roleを作成する const oidcDeployRole = new aws_iam.Role(this, 'GitHubOidcRole', { roleName: 'github-oidc-role', assumedBy: new aws_iam.FederatedPrincipal( oidcProvider.openIdConnectProviderArn, { StringLike: { 'github.hogehoge.com/_services/token:sub': `repo:my_org/${repo}:ref:refs/heads/${branch}`, }, }, 'sts:AssumeRoleWithWebIdentity' ), }); } }
OIDC IDプロバイダーのサムプリントについて
今までIAM OIDC IDプロバイダーを使用する場合、OIDC IDプロバイダーの検証用にサムプリント(thumbprint)を設定する必要がありましたが、今年の7/6よりサムプリントが検証に必要なくなりました。
なおAWS CDKではサムプリントは任意項目で、CloudFormationでは必須項目ですが、適当な値を入れておけば良いみたいです。
GitHub Actions
# トリガ設定は適宜変更 # 最低限しか書いてないです(cache処理などは省略) on: push: branches: - 'develop' - 'main' jobs: deploy: runs-on: ubuntu-latest env: # 今回は直接記載しているが、必要に応じてsecretsに登録する AWS_ACCOUNT_ID: "<AWSアカウント番号>" AWS_REGION: "ap-northeast-1" # ここでpermissionを設定するのが大事 permissions: id-token: write contents: read steps: - name: Checkout uses: actions/checkout@v3 - name: Install CDK Dependency run: npm ci # 4. GitHubにてconfigure-aws-credentialsを使用してAWSと認証する - name: Assume Role uses: aws-actions/configure-aws-credentials@v2 with: role-to-assume: "arn:aws:iam::${{ env.AWS_ACCOUNT_ID }}:role/github-oidc-role" aws-region: ${{ env.AWS_REGION }} # npm scriptに登録しておいたcdk deployコマンドを実施する - name: Deploy run: npm run deploy
ポイントは下記2点です
permissionsにid-token: write、contents: readを設定する
これを設定しないとOIDCを使用してcdk deploy
が実施できない
aws-actions/configure-aws-credentials@v2を使用して、「2. 認証用のIAM Roleを作成する」で作成したIAM Roleで認証を行う
role-to-assume
に該当IAM RoleのArnを指定する
ちなみにロール名だと「credential情報がない」みたいなエラーになった。(secretsにアクセスキー&シークレットアクセスキーを登録すればOKかも)
ただ、それをしたくないからOIDCを使用しているのに、それやったら意味がない...
まとめ
以上、AWS CDKでGitHubでOIDCを使用してAWSと認証する方法でした。
アクセスキー&シークレットアクセスキーはセキュリティ的な観点からも、発行しないで済むならそれに越したことはないので、今回のような手法を積極的に取り入れて、よりセキュアになればと思います。
なお、GitHub側で「特定のIPアドレスからしか接続を許可していない」ような設定をしている場合、この方法が使えないので、その場合は残念ながらこの方法は使えません。(GHEでありがち)
では、今回はこの辺で。