完成物
今回の記事ではこれの左側の部分の説明をします。
今後似たような認証機構を構築する時のために備忘録として残しておくための記事です。
間違いや、もっとこうしたら良いなどがあったらコメントしていただけると幸いです。
OIDC認証とは
会社の同期がめっちゃわかりやすい記事を書いてくれていたのでそれを参考しました。
ものすごくざっくり言うと、
OIDC = 「トークンを使用した短期認証のプロトコル」
と言えそうです
AWS Credentialsのような長期的な認証ではないのでセキュリティ的にも推奨されます。
今回は、
AWS側にOIDCプロバイダーを設置して、GitHubActionsから送られてくるトークンを検証、識別して必要なロールを渡す
という機構を構築していきます。
1. CDKでOIDCプロバイダーと必要なロールをデプロイ
パイプライン用に先にデプロイしていたpipeline-stack.tsにOIDCに関する部分を追加します
最終的にはこのようなコードになります
lib/stacks/pipeline-stack.ts
~~~~
// 元々定義していたバケットのARNを変数に格納
const bucketArn = bucket.bucketArn;
// GitHubのOAuthトークンを取得するためのOpenID Connectプロバイダーを作成
const idProvider = new iam.OpenIdConnectProvider(this, 'IdProvider', {
url: 'https://token.actions.githubusercontent.com',
clientIds: ['sts.amazonaws.com'],
});
// GitHub Actionsの特定のワークフローに対してS3への権限を与えるためのロール
const role = new iam.Role(this, 'Role', {
roleName: 'GitHubActionRole',
maxSessionDuration: Duration.hours(1),
assumedBy: new iam.WebIdentityPrincipal(idProvider.openIdConnectProviderArn, {
StringLike: {
'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com',
},
StringEquals: {
'token.actions.githubusercontent.com:sub': 'repo:orgnize/project:ref:refs/heads/main',
},
}),
});
// 作成したロールにS3への権限を与える
role.addToPolicy(new iam.PolicyStatement({
actions: ['s3:PutObject'],
resources: [bucketArn + '/*'],
}));
ひとつずつ解説していきます。
AWS側にOIDCプロバイダーを設置する
lib/stacks/pipeline-stack.ts
// GitHubのOAuthトークンを取得するためのOpenID Connectプロバイダーを作成
const idProvider = new iam.OpenIdConnectProvider(this, 'IdProvider', {
url: 'https://token.actions.githubusercontent.com',
clientIds: ['sts.amazonaws.com'],
});
この'token.actions.githubusercontent.com'は
GitHub Actions が OIDC トークンを取得する際に内部的に使用するエンドポイント
です。
GitHub Actions のジョブが実行されると、GitHub はこのエンドポイントを介して AWS に送信される OIDC トークンを発行します。
このトークンには、リポジトリ、ブランチ、その他の関連情報が含まれています。
AWS の Security Token Service (STS) をclient(受信者)として定義
つまり、このようなフローでトークンが届くので、
「発行元がURL通りで受信者がSTSならOKを出すプロバイダー」
を定義したことになります。この段階だとゆるゆるです。
OpenIdConnectProviderの公式APIリファレンスドキュメントはこちら
GitHubActionsで使用するためのロールを定義
lib/stacks/pipeline-stack.ts
// GitHub Actionsの特定のワークフローに対してS3への権限を与えるためのロール
const role = new iam.Role(this, 'Role', {
roleName: 'GitHubActionRole',
maxSessionDuration: Duration.hours(1), // 有効な時間
assumedBy: new iam.WebIdentityPrincipal(idProvider.openIdConnectProviderArn, {
StringLike: {
'token.actions.githubusercontent.com:aud': 'sts.amazonaws.com',
},
StringEquals: {
'token.actions.githubusercontent.com:sub': 'repo:orgnize/project:ref:refs/heads/main',
},
}),
});
// 作成したロールにS3への権限を与える
role.addToPolicy(new iam.PolicyStatement({
actions: ['s3:PutObject'],
resources: [bucketArn + '/*'],
}));
Web Identity (サードパーティをPrincipalとすることができる)にassumeするIAMロールを定義しています。
assumedByの条件でプロバイダーの基本条件に加え、特定のリポジトリやブランチに限定した条件を追加することで、ロールを引き受けることができるトークンをさらに絞り込んでいます。
先ほどと重複しますが、発行されたトークンは、リポジトリ、ブランチ、その他の関連情報が含まれているので、その情報を使用している感じです。
このような流れで、GitHubActionsに対して、同じスタックに定義したS3へPUTする権限を与える準備ができました。
GitHubActionsのワークフローを実装
.github/workflows/infra-deploy.yml
name: infra-deploy
on: #mainへのプッシュをトリガーに起動
push:
branches:
- main
permissions: #ワークフローがリポジトリにアクセス、OIDCトークンを利用しての認証とロールの引き受けを許可
id-token: write
contents: read
jobs:
upload-source:
runs-on: ubuntu-latest
steps:
- name: Checkout source
uses: actions/checkout@v4
- name: Configure AWS credentials # IAMロールの引き受けと、CLIを実行できるように設定
uses: aws-actions/configure-aws-credentials@v4 #ここが一番重要
with:
aws-region: ${{ secrets.AWS_REGION }}
role-to-assume: ${{ secrets.AWS_ROLE_ARN }} # 先に定義した'GitHubActionRole'のARNをシークレットに入れておく
- name: Install AWS CLI
run: |
sudo apt-get update
sudo apt-get install -y awscli
- name: Zip source code
run: zip -r source-code.zip .
- name: Upload source code
run: aws s3 cp source-code.zip s3://bucket-name-${{ secrets.ENV_NAME }}
uses: aws-actions/configure-aws-credentials@v4
このアクションが、GitHub Actions ジョブが AWS の OIDC プロバイダーとやりとりし、トークンを取得し、そのトークンを使って指定された IAM ロールを引き受けるためのプロセスを担当してます。
GitHubのシークレットの使い方
以上の工程でOIDCを使用した短期認証によってGitHubActionsからS3へのソースコードのプッシュが実装できました
参考にした記事まとめ