AWS CDK を使用して Lambda と Step Functions を作成する

AWS CDK を使用して Lambda と Step Functions を作成する

はじめに

本記事では、AWS CDK (Cloud Development Kit) を使用して AWS Lambda 関数と AWS Step Functions ステートマシンを作成します。AWS CDKは、クラウドリソースを定義するためのオープンソースのソフトウェア開発フレームワークで、本記事では TypeScript を使用しています。

ディレクトリ構造

本プロジェクトのディレクトリ構造は以下の通りです:

.
├── bin
│   └── cdk_sfn.ts
├── cdk.json
├── jest.config.js
├── lambda
│   └── lambda_function.py
├── lib
│   └── cdk_sfn-stack.ts
├── node_modules
├── package.json
├── stepfunctions
│   └── asl.json
├── test
└── tsconfig.json

環境

本記事では以下のバージョンの AWS CDK を使用しています。

$ cdk version
2.80.0 (build bbdb16a)

Lambda 関数

デプロイする Lambda 関数は以下です。Python で記述しています。

import boto3

def update_cloudfront_distribution(event):
 try:
 distribution_id = event["distribution_id"]
 new_acl_id = event["new_acl_id"]
 except KeyError as e:
 return {"statusCode": 400, "body": f"Missing key in event: {e}"}

 client = boto3.client("cloudfront")

 try:
 dist_config_response = client.get_distribution_config(Id=distribution_id)
 dist_config = dist_config_response["DistributionConfig"]
 e_tag = dist_config_response["ETag"]

 dist_config["WebACLId"] = new_acl_id

 client.update_distribution(Id=distribution_id, IfMatch=e_tag, DistributionConfig=dist_config)
 except Exception as e:
 return {"statusCode": 500, "body": f"Failed to update distribution config: {e}"}

 return {"statusCode": 200, "body": f"Updated WAF ACL for distribution {distribution_id} to {new_acl_id}"}

def lambda_handler(event, context):
 print(event)
 response = update_cloudfront_distribution(event)
 return response

CDK のコード

以下に CDK のコードを示します。

  • Lambda のコードで CloudFront や WAF に操作を行っているため、

  • Escape Hatch を利用して、既存のASLを使用してステートマシンを作成します。Escape Hatch を使用することで、低レベルの CloudFormation リソースを直接操作することが可能になります。

import * as cdk from 'aws-cdk-lib';
import { ManagedPolicy, Role, IRole, ServicePrincipal } from "aws-cdk-lib/aws-iam";
import { Code, Function, Runtime } from "aws-cdk-lib/aws-lambda";
import { CfnStateMachine, Pass, StateMachine } from 'aws-cdk-lib/aws-stepfunctions';
import * as fs from 'fs';

const POLICY_ARN_WAF = "arn:aws:iam::aws:policy/AWSWAFFullAccess";
const POLICY_ARN_LAMBDA = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole";
const POLICY_ARN_CLOUDFRONT = "arn:aws:iam::aws:policy/CloudFrontFullAccess";

export class CdkSfnStack extends cdk.Stack {
 constructor(scope: cdk.App, id: string, props?: cdk.StackProps) {
 super(scope, id, props);

 const environment = this.node.tryGetContext('environment')
 const contextValues = this.node.tryGetContext(environment)

 const stepFunctionFile = fs.readFileSync(`./stepfunctions/asl.json`)

 const lambdaRole = this.createLambdaRole();
 const lambdaFunction = this.createLambdaFunction(lambdaRole);

 const commonRole = Role.fromRoleArn(this, 'CommonRole', `arn:aws:iam::${contextValues['account']}:role/stepfunctions-common-role`);
 this.createStateMachine(stepFunctionFile, commonRole);
 }

 private createLambdaRole(): Role {
 return new Role(this, "lambdaRole", {
 assumedBy: new ServicePrincipal("lambda.amazonaws.com"),
 managedPolicies: [
 ManagedPolicy.fromManagedPolicyArn(this, "wafPolicy", POLICY_ARN_WAF),
 ManagedPolicy.fromManagedPolicyArn(this, "lambdaPolicy", POLICY_ARN_LAMBDA),
 ManagedPolicy.fromManagedPolicyArn(this, "cloudfrontPolicy", POLICY_ARN_CLOUDFRONT),
 ],
 description: "Basic Lambda Role",
 });
 }

 private createLambdaFunction(lambdaRole: Role): Function {
 return new Function(this, "python-function", {
 functionName: "switch_acl",
 runtime: Runtime.PYTHON_3_9,
 code: Code.fromAsset("lambda"),
 handler: "lambda_function.lambda_handler",
 role: lambdaRole,
 timeout: cdk.Duration.seconds(30)
 });
 }

 private createStateMachine(stepFunctionFile: Buffer, commonRole: IRole): StateMachine {
 const stateMachine = new StateMachine(this, 'MyStateMachine', {
 definition: new Pass(this, 'StartState'),
 role: commonRole,
 stateMachineName: "SwitchWafAcl"
 });

 const cfnStateMachine = stateMachine.node.defaultChild as CfnStateMachine;
 cfnStateMachine.definitionString = stepFunctionFile.toString();
 return stateMachine;
 }
}

おわりに

本記事では、AWS CDK を使用して AWS Lambda 関数と AWS Step Functions ステートマシンを作成する方法を説明しました。AWS CDK を使用することで、クラウドリソースのプロビジョニングを自動化し、繰り返し可能で信頼性の高い方法で行うことが可能です。 この記事がどなたかの参考になれば幸いです。

参考