Github上のASLファイルの変更をトリガーにしてStepFunctionsを自動デプロイする(Github Actions + AWS CDK)

2022.10.11

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

「ASLファイルの変更をトリガーにStepFunctionsを自動デプロイしたい」

GitHub等ででASLファイルを管理している環境で、ASLファイルの変更があった際に自動でStepFunctionの設定も更新できるようにしたいことがありました。

今回は以下の構成でやってみました。

  • IaCツール: AWS CDK
  • CI/CDツール: Github Actions

IaCツールやCI/CDツールが異なる場合も、基本的には同じような流れで実行できるかと思います。 (例えば、IaCツールがTerraformだったらcdk deployの部分をterraform applyに変える等。)

概要

  1. AWS CDKでStep Functionsを作成
  2. ASLファイルの変更をトリガーにGithub Actionsを実行
  3. Github Acitions上でAWS CDKを使用して環境を更新(cdk deploy)

StepFunctionsはIaCツール(AWS CDK)で作成します。

IaCツールでStepFunctionsを作成するメリットとしては、複数のステートマシンを作成したい場合もCI/CDパイプラインを組むのが容易だからです。

ASLファイルの変更をトリガーにCI/CDツール上で、「aws stepfunctions update-state-machine」コマンドを実行してステートマシンを更新することも可能かと思います。

しかし、ワークフローの数が増えていくとその分コマンドを増やす・または何かしらのスクリプト作成の必要があります。

CIツールで実行するコマンド(awscliで更新するパターン)

aws stepfunctions update-state-machine --state-machine-arn <state-machine AのARN> --definition <state-machin A definition>
aws stepfunctions update-state-machine --state-machine-arn <state-machine BのARN> --definition <state-machin B definition>
aws stepfunctions update-state-machine --state-machine-arn <state-machine CのARN> --definition <state-machin C definition>
# 数が増えると追加が必要

IaCツールで作成する場合は、ステートマシンが増えてもコマンドを変更する必要はありません。 (IaCツール内で作成するステートマシンの記述は必要です)

CIツールで実行するコマンド(cdkで更新するパターン)

npm ci
npm run cdk deploy "*" --require-approval never

やってみた

コードは以下にあります。

msato0731/cdk-stepfunctions-asl

AWS CDKで環境を用意する

CDKのコードでは既存のASLファイルを使うため、今回はL1 Constructを使用しています。 Github Actionsで使うIAMロールも同じスタックで作成しています。

lib/StepFunctionsStack.ts

import * as cdk from 'aws-cdk-lib'
import * as iam from 'aws-cdk-lib/aws-iam'
import * as stepfunctions from 'aws-cdk-lib/aws-stepfunctions'
import { GithubActionsIdentityProvider, GithubActionsRole } from 'aws-cdk-github-oidc';
import * as fs from 'fs'
import { Construct } from 'constructs'

export class StepfunctionsStack extends cdk.Stack {
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props)

    // すでにProvider作成済みのため
    const provider = GithubActionsIdentityProvider.fromAccount(this, this.account)

    // Provider存在しない場合は、以下の記述が必要
    // const provider = new GithubActionsIdentityProvider(this, 'GithubProvider');

    const githubActionsRole = new GithubActionsRole(this, 'GithubActionsRole', {
      provider: provider,
      owner: 'msato0731', // 書き換え必要
      repo: 'cdk-stepfunctions-asl',
      roleName: 'stepfunctions-gh-deploy-test',
      maxSessionDuration: cdk.Duration.hours(2),
    });

    // デプロイ検証用のため強めの権限付与
    githubActionsRole.addManagedPolicy( iam.ManagedPolicy.fromAwsManagedPolicyName("AdministratorAccess") )

    new cdk.CfnOutput(this, "GithubActionsRoleArn", {
      value: githubActionsRole.roleArn
    })

    //  ステートマシン作成にIAM Role必須のため、今回の検証ではポリシーは不要
    const stepFunctionsRole = new iam.Role(this, "StepFunctionsRole", {
      assumedBy: new iam.ServicePrincipal('states.amazonaws.com')
    })

    //  ステートマシン作成
    const file = fs.readFileSync('./step-functions/HelloWorld.asl.json')

    new stepfunctions.CfnStateMachine(this, 'HelloWorldStateMachine', {
      definitionString: file.toString(),
      stateMachineName: 'HelloWorld-CDK',
      roleArn: stepFunctionsRole.roleArn
    })

  }
}

補足: ステートマシン追加

「CfnStateMachine」を以下のように追加することで、ステートマシンを追加できます。

lib/StepFunctionsStack.ts

    // 省略

    const file = fs.readFileSync('./step-functions/HelloWorld.asl.json')

    new stepfunctions.CfnStateMachine(this, 'HelloWorldStateMachine', {
      definitionString: file.toString(),
      stateMachineName: 'HelloWorld-CDK',
      roleArn: stepFunctionsRole.roleArn
    })

    // ステートマシン追加
    const file2 = fs.readFileSync('./step-functions/HelloWorld2.asl.json')

    new stepfunctions.CfnStateMachine(this, 'HelloWorldStateMachine2', {
      definitionString: file.toString(),
      stateMachineName: 'HelloWorld-CDK2',
      roleArn: stepFunctionsRole.roleArn
    })

Github ActionsのシークレットにIAMロールをセット

「cdk deploy」を実行して作成されたCloudFormationスタックの出力を確認します。 IAMロールARNが出力されるため、これをコピーしておきます。

GithubActionsのシークレットに以下を追加します。

  • シークレット名: AWS_IAM_ROLE_ARN
  • 値: [コピーしたIAMロールARN]

Github Actionsのワークフローファイルを用意

CDKデプロイ用のワークフローファイルを用意します。

mainブランチにPR時に、cdk diffを実施します。 mainブランチでpushしたタイミング(PR マージ)時に、cdk deployが実行されます。

deploy-cdk.yml

name: deploy-cdk

on:
  pull_request:
    branches:
      - main
  push:
    branches:
      - main

jobs:
  deploy-cdk:
    runs-on: ubuntu-latest
    permissions:
      id-token: write
      contents: read
    steps:
      - uses: actions/checkout@v2
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
        with:
          role-to-assume: ${{ secrets.AWS_IAM_ROLE_ARN }}
          aws-region: ap-northeast-1

      - name: Setup Node
        uses: actions/setup-node@v1
        with:
          node-version: '16'

      - name: CDK package install
        run: npm ci

      - name: CDK Diff Check
        if: contains(github.event_name, 'pull_request')
        run: |
          npm run cdk -- diff "*"

      - name: CDK Deploy
        if: contains(github.event_name, 'push')
        run: |
          npm run cdk -- deploy --require-approval never "*"

動作確認

修正前は、以下の状態です。

ASLファイルを修正して、PRを作成します。 「StepFunctions」という名前で、Pass Stateを追加しました。

PR時にはGithub Actionsによってcdk diffが実行されるため変更差分を確認します。

変更差分が問題なければ、マージします。 Github Actionsによって、「cdk deploy」が自動で実行されます。

マネジメントコンソール上からも、変更が適用されたことが確認できました

おわりに

CIツールにGithub Actions・IaCツールにAWS CDKを使用して、ASLファイルの変更があった際にステートマシンに変更を自動反映させる方法でした。

誰かの参考になれば幸いです。

以上、AWS事業本部の佐藤(@chari7311)でした。

参考