AWS CDK で Lambda@Edge がクロスリージョン対応しそう

AWS, TypeScript

はじめに

AWS の Lambda@Edge は us-east1 リージョンで作成する必要がある。
ところが、クロスリージョンの怒られにより、CDK で Lambda の Stack やコードを、 ap-northeast-1 リージョンを設定した CloudFront に噛ませてデプロイしようとしてもコケてしまうのだった。

今までは、SSM に Lambda の ARN を渡して、さらにその値を読むカスタムリソースを噛ませないといけなかった。

lambda-stack.ts

import { Stack, Construct, CfnOutput, Fn, StackProps } from '@aws-cdk/core'
import {
  AssetCode,
  Runtime,
  Function as LambdaFunction,
} from '@aws-cdk/aws-lambda'
import {
  Role,
  CompositePrincipal,
  ServicePrincipal,
  ManagedPolicy,
} from '@aws-cdk/aws-iam'
import { LAMBDA_OUTPUT_NAME } from '../config'
import { StringParameter } from '@aws-cdk/aws-ssm'

type Props = {
  code: AssetCode
  lambdaFunctionArnParameterName: string
} & StackProps

export class LambdaStack extends Stack {
  public readonly cfnOutput: CfnOutput

  constructor(scope: Construct, id: string, props: Props) {
    super(scope, id, props)
    const { code, lambdaFunctionArnParameterName, env } = props

    if (env?.region !== 'us-east-1') {
      throw new Error('region must be us-east-1')
    }

    /**
     * Lambda
     */
    const myLambda = new LambdaFunction(this, 'myLambda', {
      handler: 'index.handler',
      code,
      role: new Role(this, 'AllowLambdaServiceToAssumeRole', {
        assumedBy: new CompositePrincipal(
          new ServicePrincipal('lambda.amazonaws.com'),
          new ServicePrincipal('edgelambda.amazonaws.com'),
        ),
        managedPolicies: [
          ManagedPolicy.fromAwsManagedPolicyName(
            'service-role/AWSLambdaBasicExecutionRole',
          ),
        ],
      }),
      runtime: Runtime.NODEJS_12_X,
    })

    new StringParameter(this, 'LambdaFunctionArnParameter', {
      parameterName: lambdaFunctionArnParameterName,
      stringValue: myLambda.currentVersion.functionArn,
    })

    this.cfnOutput = new CfnOutput(this, LAMBDA_OUTPUT_NAME, {
      value: Fn.join(':', [
        myLambda.functionArn,
        myLambda.currentVersion.version,
      ]),
    })
  }
}

そんな中、Lambda のクロスリージョンな construct を作成する PR がマージされて、先週リリースされてたので、試してみた。
[cloudfront][lambda]Cross-region Lambda construct for Lambda@Edge

環境

  • AWS CDK 1.78.0

リリースノートによれば、 1.77.0 から対応している。 Release v1.77.0 · aws/aws-cdk

使い方

下記のように @aws-cdk/aws-lambdaFunction を使うコードがあるとして…。

cloudfront-stack.ts

import * as CloudFront from '@aws-cdk/aws-cloudfront'
import * as Lambda from '@aws-cdk/aws-lambda'

const lambdaFunction = new Lambda.Function(this, 'myLambda', {
  handler: 'index.lambdaFunctions',
  code: new Lambda.AssetCode(`${resolve(__dirname)}/../lambda/dist`),
  runtime: Lambda.Runtime.NODEJS_12_X,
}).currentVersion

new Lambda.Function@aws-cdk/aws-cloudfront/lib/experimentalexperimental.EdgeFunction に置き換えるだけ。
(CloudFront から export されてなかった)

cloudfront-stack.ts

import * as CloudFront from '@aws-cdk/aws-cloudfront'
// @aws-cdk/aws-cloudfront/lib/experimental を import
import * as CloudFrontExperimental from '@aws-cdk/aws-cloudfront/lib/experimental'
import * as Lambda from '@aws-cdk/aws-lambda'

const lambdaFunction = new CloudFrontExperimental.EdgeFunction(
  this,
  'myLambda',
  {
    handler: 'index.lambdaFunctions',
    code: new Lambda.AssetCode(`${resolve(__dirname)}/../lambda/dist`),
    runtime: Lambda.Runtime.NODEJS_12_X,
  },
).currentVersion

これで、Lambda@Edge を us-east-1 に置きつつ、他の Stack を ap-northeast-1 に置いたままデプロイできた。

内部的には冒頭のそれとほぼ同じようなことをやっているけど、CDK 側で対応してくれるのは嬉しい。
ただ、こちらのコメントにもあるように、ロググループが見当たらない…。