CDKで定義したインフラをGithub Actionsを使ってAWSにデプロイする方法についてまとめました。
新しくCDKでインフラを定義するとなると、最初は開発したコードをローカルPCでCLIを使ってデプロイすると思います。 しかし、継続的に開発をしていると環境のデプロイをローカルでやっていると変更をGithubにプッシュし忘れたり、そもそもコミットしていなかったりなど管理しているコードと実際の環境に乖離が発生しやすくなってきます。
Githubのコードと実際の環境を一致させる方法の一つとしてCICDでレポジトリへのコードのプッシュをトリガーとして、自動的にCDKをデプロイするようにする方法があります。 CIツールの選択肢はいろいろとありますが、Github ActionsはGithubを使用していればすぐ使うことができるし、Actionとして再利用可能なタスクが公開されているため使いやすいです。 今回はGithub Actionsを使用します。
Github ActionsはGithubが管理するRunner上でワークフローを実行します。AWSにリソースをデプロイするにはこのRunnerに適切なAWSへのアクセス権限を与える必要があります。
AWSの権限をGithub Actionsに渡す方法の一つとしてOpenID Connect (OIDC)を利用する方法があります。
Credentialを利用しないため、Credentialの流出などのリスクを考慮しないでよいため使いやすいです。
まずはAWS IAMにGithubのOIDC providerを作成します。 作成方法はGithub ActionsのドキュメントとAWSのドキュメントに書いてありますが、今回はCloudformationでささっと作ります。
使用するのは以下のTemplateです。
Parameters:
GithubOrg: # can also be a regular user
Type: String
Resources:
GithubOidc:
Type: AWS::IAM::OIDCProvider
Properties:
Url: https://token.actions.githubusercontent.com
ThumbprintList: [6938fd4d98bab03faadb97b34396831e3780aea1]
ClientIdList:
- !Sub https://github.com/${GithubOrg}
- sts.amazonaws.com
Outputs:
GithubOidcPrincipal:
Value: !Ref GithubOidc
Export:
Name: GithubOidcPrincipal
ParameterのGithubOrgにはコードを管理するGithub Repositoryのユーザー名またはOrganization名を入力してください。 ここで指定した名前配下のRepositoryから起動されたGithub ActionsにAWSの権限を与えることができます。
次にGithub Actionsから利用するIAM RoleをCloudformationで作成します。
OIDCによる認証の設定は AssumeRolePolicyDocument
で定義されています。
このRoleは cdk bootstrap
で作成されるIAM Role cdk-*
をAssumeする権限をもっているので cdk deploy
を実行することができます。
ParameterのGithubFullRepoName
は権限を与えるGithub Repositoryを特定するためのものです。自身が所有するレポジトリをして下さい。
GithubRef
は権限を与える対象をより限定するために使用しています。
たとえばrefs/heads/main
を指定するとGithubFullRepoName
のmain
ブランチをトリガーに起動したGithub ActionsのワークフローだけがこのIAM RoleをAssume Roleできるようになります。
Parameters:
GithubFullRepoName:
Description: Github repo full name (e.g. brabra/brabra)
Type: String
GithubRef:
Description: Ref allowed to assume role. (e.g. refs/heads/main, refs/tags/v*)
Type: String
Default: refs/heads/main
Resources:
GithubRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Join
- ""
- - github-actions-cdk-deploy-role-
- !Join ["-", !Split ["/", !Ref GithubFullRepoName]]
AssumeRolePolicyDocument:
Statement:
- Effect: Allow
Action: sts:AssumeRoleWithWebIdentity
Principal:
Federated: !Sub arn:aws:iam::${AWS::AccountId}:oidc-provider/token.actions.githubusercontent.com
Condition:
StringLike:
token.actions.githubusercontent.com:sub:
- !Sub repo:${GithubFullRepoName}:ref:${GithubRef}
Policies:
- PolicyName: AssumeCdkRole
PolicyDocument:
Version: "2012-10-17"
Statement:
Effect: "Allow"
Action: sts:AssumeRole
Resource: !Join
- ""
- - "arn:aws:iam::"
- !Ref "AWS::AccountId"
- ":role/cdk-*"
Sid: AssumeRole
Outputs:
GithubRole:
Value: !GetAtt GithubRole.Arn
このCloudformationのOutputであるGithubRole
をGithub ActionsのWorkflowに設定することで、作成したIAM RoleをAssume Roleします。
Workflowを定義するYAMLファイルをGithub Repositoryの .github/workflows/
に配置すると、トリガー条件にマッチするイベントが発生したときGithub Actionsが起動します。
今回配置するYAMLファイルは以下のものです。
DEPLOY_ROLE
は前項で作成したIAM ROLEのARN、AWS_REGION
はCDKでStackを作成するAWSのリージョンを指定してください。
name: Deploy CDK
on:
push:
branches:
- main
env:
NODE_VERSION: "18"
DEPLOY_ROLE: "arn:aws:iam::xxxxxxxxxxxx:role/github-actions-cdk-deploy-role-xxxxxxxx"
AWS_REGION: "us-west-2"
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ env.DEPLOY_ROLE }}
aws-region: ${{ env.AWS_REGION }}
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- name: NPM install
run: |
npm ci
- name: CDK Build
run: |
npm run build
- name: Deploy
run: |
npx cdk deploy --require-approval never
このWorkflow定義ではシンプルにmain
ブランチが更新されたらWorkflowが実行されます。
この条件を変更することで様々な応用が可能です。例えば以下のように設定すると新しいReleaseをpublishしたときWorkflowが実行されます。
on:
release:
types: [published]
Github ActionsでCDKで定義したインフラをAWSへデプロイする方法についてまとめました。
今回はシンプルにCDKをデプロイしただけですが、よりかっちりと運用する場合は npm run test
を実行したり cdk diff
でインフラの変更内容を出力するなど考慮すべきことは他にもありますが基本は同じです。