CDKでGitHub ActionsのOIDCを作ってみた
目次
はじめに
こんにちは、CloudBuildersのsugawaraです。
先日、GitHub Actionsに入門しましたーという記事を書きました。こちらはGitHub Actionsってなんだ?なにで学べばいいんだ?という紹介記事でした。ご興味のある方はご一読ください!
さて、今回はCDKでGitHub ActionsのOIDC用のIAMロールとIAMのIDプロバイダーを作成してみたというお話です。
OIDCってなに?
そもそもOIDCとは、OpenID Connectの略となります。アイデンティティ連携(Identity federation)を可能にするプロトコルであり、一度ログインするだけで複数のサービスにアクセスできるようになります。
OIDCを利用すると、GitHub ActionsからAWSにリソースをデプロイする際にIAMロールの一時的なクレデンシャルを使うことができます。これにより、クレデンシャル情報が一時的なものになるため、セキュリティリスクを減らすことができます。
OIDCが登場する以前は、IAMユーザのクレデンシャルであるアクセスキーとシークレットアクセスキーをGitHubのシークレットに登録しました。しかし、この方法ではクレデンシャル情報を永続的に登録することになるため、セキュリティ上の問題があります。
したがって、GitHub Actionsを利用する際には永続的なクレデンシャル情報を登録するのではなく、OIDCによる一時的なクレデンシャル情報によるデプロイを用いるようにしましょう。
実装
OIDCをCDKで実装する方法は下記の3種類+αになります。作成するリソースはGitHub Actionsが利用するIAMロールとIAM IDプロバイダーの2つです。
※実際に利用するためには。GitHub Actions側でもIAMロールのARN登録とワークフローの作成が必要です。
L2クラスを利用する
AWS CDKの公式ドキュメントのIAMにOpenIDConnectorクラスというものがあります。こちらを利用することによって、シンプルに実装が可能です。
import * as iam from 'aws-cdk-lib/aws-iam';
import { Duration } from 'aws-cdk-lib';
...
const idProvider = new iam.OpenIdConnectProvider(this, 'IDProvider', {
url: 'https://token.actions.githubusercontent.com',
clientIds: [ 'sts.amazonaws.com' ],
});
const role = new iam.Role(this, 'Role', {
roleName: 'GitHubActionsRole',
maxSessionDuration: Duration.hours(2),
assumedBy: new iam.WebIdentityPrincipal(idProvider.openIdConnectProviderArn, {
StringEquals: {
['token.actions.githubusercontent.com:aud']: 'sts.amazonaws.com',
},
StringLike: {
['token.actions.githubusercontent.com:sub']: 'repo:{ORGANIZATION_NAME}/{REPO_NAME}:*',
},
}),
});
role.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
なお、こちらでデプロイすると、下記のようにカスタムリソースが自動で作成されます。このカスタムリソースで任意のプロパティであるthumbprints(SSL証明書のハッシュ)リストを設定しています。
※元々はthumbprintsも必須プロパティだったようですが、現在は任意となっています。しかし、デプロイ後は設定自体はされるようです。
デフォルトのCDKライブラリで十分なら、この実装方法で良さそうです。
Construct Hubを利用する
次はConstruct Hubに公開されているaws-cdk-github-oidc パッケージです。GithubActionsIdentityProviderクラスと GithubActionsRoleクラスを使用することで、L2利用よりも設定が多少簡素化されています。
利用するにはまず下記のコマンドを実行します。
$ npm i -D aws-cdk-github-oidc
下記のようにコードを書いてデプロイします。
import * as iam from 'aws-cdk-lib/aws-iam';
import { Duration } from 'aws-cdk-lib';
import { GithubActionsIdentityProvider, GithubActionsRole } from "aws-cdk-github-oidc";
...
const idProvider = new GithubActionsIdentityProvider(scope, "IDProvider");
const githubActionsRole = new GithubActionsRole(scope, "GitHubActionsRole", {
description:'IAM Role for GitHub Actions',
provider: idProvider,
owner: "{OWER_NAME}",
repo: "{REPO_NAME}",
maxSessionDuration: Duration.hours(2),
});
githubActionsRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
こちらの実装方法でも、L2のときと同様にカスタムリソースは作成されます。
よりシンプルな設定で実装する場合には、Construct Hubを利用するのが良さそうです。
L1(Cfn)クラスを利用する
3つ目はL1(Cfn)利用する方法です。IAMのCfnOIDCProviderクラスを使用してOIDCプロバイダを設定します。
L2やConstruct Hubでの実装との違いは、thumbprintリストを設定する必要があることです。GitHub ActionsではSSL証明書のthumbprintを設定する必要がなくなったため、現在は16進数で40文字のダミー値を設定するだけでOKのようです。
下記のようにダミー値を入れているため、メリット(?)はCDKが裏でthumbprintについてゴニョゴニョとよしなにやらない=勝手にカスタムリソースが作成されない、ということが言えるかも。
import * as iam from 'aws-cdk-lib/aws-iam';
import { Duration } from 'aws-cdk-lib';
import { CfnOIDCProvider } from 'aws-cdk-lib/aws-iam';
.....
// GitHub Actionsの設定
const idProvider = new CfnOIDCProvider(this, 'MyOIDCProvider', {
url: 'https://token.actions.githubusercontent.com',
clientIdList: ['sts.amazonaws.com'],
thumbprintList: ['0123456789012345678901234567890123456789'], // ダミー値を設定する
});
const githubActionsRole = new iam.Role(this, 'GitHubActionsRole', {
roleName: 'GitHubActionsRole',
maxSessionDuration: cdk.Duration.hours(2),
assumedBy: new iam.WebIdentityPrincipal(idProvider.attrArn, {
StringEquals: {
['token.actions.githubusercontent.com:aud']: 'sts.amazonaws.com',
},
StringLike: {
['token.actions.githubusercontent.com:sub']: 'repo:{OWNER_NAME}/{REPO_NAME}:*',
},
}),
});
githubActionsRole.addManagedPolicy(iam.ManagedPolicy.fromAwsManagedPolicyName('AdministratorAccess'));
L1でカスタマイズしたい、カスタムリソースは作成してほしくない場合には、これで実装するのが良さそうです。
CloudFormationを利用する(番外編)
番外編として、同様の設定がデプロイできるCloudFormationテンプレートも載せておきます。スタック名、GitHub Organization、リポジトリ名、環境を入力するだけで簡単にすぐに使えるものとなります。
※出力されたIAMロールのARNをGitHub側へ登録する必要あり
Parameters:
GitHubOrg:
Description: Name of GitHub Organization/User
Type: String
RepositoryName:
Description: Name of GitHub repository
Type: String
OIDCAudience:
Description: Audience supplied to configure-aws-credentials.
Default: "sts.amazonaws.com"
Type: String
Env:
Description: Environment for the resources
Type: String
AllowedValues:
- dev
- staging
- prod
Default: dev
Resources:
Role:
Type: AWS::IAM::Role
Properties:
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRoleWithWebIdentity
Principal:
Federated: !Ref GitHubActionsOidc
Condition:
StringEquals:
token.actions.githubusercontent.com:aud: !Ref OIDCAudience
StringLike:
token.actions.githubusercontent.com:sub: !Sub repo:${GitHubOrg}/${RepositoryName}:*
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
GitHubActionsOidc:
Type: AWS::IAM::OIDCProvider
Properties:
Url: https://token.actions.githubusercontent.com
ClientIdList:
- sts.amazonaws.com
ThumbprintList:
- 0123456789012345678901234567890123456789
Outputs:
Role:
Value: !GetAtt Role.Arn
おわりに
今回はGitHub Actionsで利用するOIDCのIAMロールとIDプロバイダーをCDKで作成する方法をいくつか確認してみました。色々な方法があるので、プロジェクトに合わせて使い分けたいと思います。
なお、当初はCDKでインフラなどといっしょにコード化したいと思いましたが、そうすると初回のプッシュではGitHub Actionsを利用できないことに気づきました。となると、上記のCloudFormationテンプレートでまずは簡単に作成する方法でもいいかなーと感じました。