All Articles

Github ActionsでCDKをDeployする

はじめに

CDKで定義したインフラをGithub Actionsを使ってAWSにデプロイする方法についてまとめました。

新しくCDKでインフラを定義するとなると、最初は開発したコードをローカルPCでCLIを使ってデプロイすると思います。 しかし、継続的に開発をしていると環境のデプロイをローカルでやっていると変更をGithubにプッシュし忘れたり、そもそもコミットしていなかったりなど管理しているコードと実際の環境に乖離が発生しやすくなってきます。

Githubのコードと実際の環境を一致させる方法の一つとしてCICDでレポジトリへのコードのプッシュをトリガーとして、自動的にCDKをデプロイするようにする方法があります。 CIツールの選択肢はいろいろとありますが、Github ActionsはGithubを使用していればすぐ使うことができるし、Actionとして再利用可能なタスクが公開されているため使いやすいです。 今回はGithub Actionsを使用します。

目次

OICD Providerの設定

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の権限を与えることができます。

IAM Role

次にGithub Actionsから利用するIAM RoleをCloudformationで作成します。

OIDCによる認証の設定は AssumeRolePolicyDocument で定義されています。

このRoleは cdk bootstrap で作成されるIAM Role cdk-* をAssumeする権限をもっているので cdk deploy を実行することができます。

ParameterのGithubFullRepoNameは権限を与えるGithub Repositoryを特定するためのものです。自身が所有するレポジトリをして下さい。

GithubRefは権限を与える対象をより限定するために使用しています。 たとえばrefs/heads/mainを指定するとGithubFullRepoNamemainブランチをトリガーに起動した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します。

Github ActionsのWorkflowの設定

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でインフラの変更内容を出力するなど考慮すべきことは他にもありますが基本は同じです。

Published Apr 2, 2024

スタートアップで働くデータエンジニア兼データサイエンティスト。興味の範囲はデータパイプラインの構築、データ分析、機械学習、クラウドなどなど。