APC 技術ブログ

株式会社エーピーコミュニケーションズの技術ブログです。

株式会社 エーピーコミュニケーションズの技術ブログです。

【AWS】GithubActionsでCDKデプロイをやってみる

目次

はじめに

こんにちは、クラウド事業部の上村です。
GithubActionsを使ってCDKをデプロイする機会があったので試してみます。

どんなひとに読んで欲しい

  • GithubActionsでとりあえずCICDを試したい人
  • CDKでCICDを利用したい人

事前準備

Githubアカウント CDK環境の準備 リポジトリの作成

CDK 初期セットアップ

mkdir cdk-githubactions-test && cd cdk-githubactions-test
cdk init app --language typescript
cdk boostrap 

Boostrapで生成されるロールについて

Boostrapで生成される4つのロールは各役割があります。
デプロイ時の権限移譲は下記のようになります。 1.アクターがcdk-deploy-roleを引き受け(AssumeRole)を行います
2.cdk-deploy-role は、管理者権限を持つ cfn-exec-role を iam:PassRole で CloudFormation サービスに渡します。
3.CloudFormation サービスが cfn-exec-role を引き受け (AssumeRole)、実際のデプロイ処理を実行します。

https://user-images.githubusercontent.com/43035978/205697462-465685b6-e08c-4989-a2fb-1a6c0bfca703.png

セキュリティを向上させたい場合は、Boostrapで生成されるデフォルト修飾子(hnb659fds)の変更や
Permissions BoundaryやSCPを利用してガードレールで担保しておくことも有効かと思います。

詳細は下記リンクを参照してください。
https://github.com/aws/aws-cdk/wiki/Security-And-Safety-Dev-Guide

GithubActions用のロール/ポリシーの作成

今回はシンプルにBoostrapで生成したロールを利用します。
またmainブランチを対象とします。
branchに制限を行う場合は、oidcDeployRole及びworkflowの調整が必要となります。
注意点としてプロバイダーURLはアカウント内でユニークである必要があり、既に存在する場合はエラーとなるので注意してください。

lib/cdk-githubactions-test-stack.ts

import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3 from 'aws-cdk-lib/aws-s3';


export class CdkGithubactionsTestStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    
    const accountId = this.account;
    const region = this.region;
    // 各gihhub情報を入力してください。
    const user = 'userName';
    const repo = 'repoName';
    const branch = 'main';
    
    const oidcProvider = new iam.OpenIdConnectProvider(this,'GithubOIDCProvider',
       {
         url: 'https://token.actions.githubusercontent.com',
         clientIds: ['sts.amazonaws.com'],
       }
    );
        
    const oidcDeployRole = new iam.Role(this, 'GithubOidcRole',{
      roleName: 'github-oidc-role',
      assumedBy: new iam.FederatedPrincipal(
        oidcProvider.openIdConnectProviderArn,
        {
          StringLike: {
            'token.actions.githubusercontent.com:sub': `repo:${user}/${repo}:*`,
            // 'token.actions.githubusercontent.com:sub': `repo:${user}/${repo}:ref:refs/heads/${branch}`,
          },
        },
        'sts:AssumeRoleWithWebIdentity'
      ),
    });
    
    const deployPolicy = new iam.Policy(this, 'deployPolicy', {
      policyName: 'deployPolicy',
      statements: [
        new iam.PolicyStatement({
          effect: 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);
  } 
  // RoleArn Output
  new cdk.CfnOutput(this, 'RoleArn', {
    value: oidcDeployRole.roleArn,
  });

}

bin/cdk-githubactions-test.ts

import * as cdk from 'aws-cdk-lib';
import { CdkGithubactionsTestStack } from '../lib/cdk-githubactions-test-stack';
import 'source-map-support/register';

const app = new cdk.App();
const env = {
  account: process.env.CDK_DEFAULT_ACCOUNT,
  region: process.env.CDK_DEFAULT_REGION,
};

new CdkGithubactionsTestStack(app, 'CdkGithubactionsTestStack', {
  env: env  
});

ロールやOIDCプロバイダーをデプロイします。

cdk deploy

githubActions workflow用ファイルの作成

workflow用のファイルを作成します。
Push実行時には cdk deploy が実行され、PR実行時には cdk diff が実行されるように設定します。

.github/workflows/deploy.yml

name: CDK

# mainブランチにプッシュ時にトリガー
on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main
  workflow_dispatch:

# OIDC設定
permissions:
  id-token: write
  contents: read
  pull-requests: write
    
jobs:
  cdk-deploy:
    runs-on: ubuntu-latest
    if: github.ref == 'refs/heads/main' && github.event_name == 'push'
    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
              
      - name: Install dependencies
        run: npm ci
            
      - name: CDK Deploy
        run: npx cdk deploy --all --require-approval never           
            
  cdk-diff: 
    runs-on: ubuntu-latest
    if: github.event_name == 'pull_request'
    steps:
      - uses: actions/checkout@v4
    
      - name: Configure AWS Credentials
        uses: aws-actions/configure-aws-credentials@v4
        with:
          role-to-assume: ${{ secrets.AWS_ROLE_TO_ASSUME }}
          aws-region: ${{ secrets.AWS_REGION }}

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'
      
      - name: Install dependencies
        run: npm ci
      
      - name: CDK Diff
        run: npx cdk diff --all

Secretの設定

workflowが環境変数を参照できるように設定を行います。
今回はシークレットに下記を登録して利用するようにします。
ロールARNは、コンソール又はCDKデプロイ時に出力されたものを登録してください。

AWS_REGION: ap-northeast-1
AWS_ROLE_TO_ASSUME: arn:aws:xxx


動作確認

Push時の動作確認を進めていきます。
S3を作成するコードを追加して、githubにPushします。

lib/cdk-githubactions-test-stack.ts

  // RoleArn Output
  new cdk.CfnOutput(this, 'RoleArn', {
    value: oidcDeployRole.roleArn,
  });
  //add s3
  const s3bucket = new s3.Bucket(this, 'testBucket', {
  });

Githubから確認するとDeployが実行されていることが確認できました。
CDK Deployの箇所を確認するとログを確認することができます。

次はPR作成時の動作確認をします。
今回はコンソールで進めていきます。
ブランチの作成を行います。

先程追加したS3バケット作成部分を削除します。

変更後にPRリクエスト作成を行うとcdk diff が実行されていることが確認できます。

おわりに

初めてGithubActionsを利用しましたが簡単に設定できました。
cdk-nagやtrivyなどを組み込んだケースも試してみようかと思います。

お知らせ

私達クラウド事業部はクラウド技術を活用したSI/SESのご支援をしております。

www.ap-com.co.jp

また、一緒に働いていただける仲間も募集中です!
今年もまだまだ組織規模拡大中なので、ご興味持っていただけましたらぜひお声がけください。

www.ap-com.co.jp