CDK Custom Resourceでカスタム AWS 設定を実現する

公開日 2025年4月25日
更新日 2025年4月25日
12 分で読める
AWS

本記事では、CDK の Custom Resource 機能を使って、CDK がネイティブにサポートしていない AWS リソースや機能に対してカスタム設定を追加する方法を紹介します。
たとえば、CDK は既存の S3 バケットに対してイベント通知(Notification)を追加する機能を標準では持っていません。以下の例では、既存の S3 バケットに対して Custom Resource 経由で Notification を動的に設定し、指定したファイル拡張子でオブジェクトがアップロードされたときに自動的に Lambda を呼び出す仕組みを実装します。


1. S3 Notification を設定する Lambda の実装

まず、S3 バケットに Notification 設定を行う専用の Lambda 関数を用意します。この関数は、受け取った拡張子リスト(suffixList)を元に PutBucketNotificationConfigurationCommand を組み立て、S3 に送信します。

// lambda/s3-notification-setting/index.ts
import { LambdaFunctionConfiguration, PutBucketNotificationConfigurationCommand, S3Client } from '@aws-sdk/client-s3';
import { CdkCustomResourceEvent, Context } from 'aws-lambda';

const createUpdateCommand = (suffixList: string[]) => {
  const configurations: LambdaFunctionConfiguration[] = suffixList.map((suffix) => ({
    LambdaFunctionArn: process.env.INVOKE_FUNC_ARN!,
    Events: ['s3:ObjectCreated:*'],
    Filter: {
      Key: {
        FilterRules: [{ Name: 'suffix', Value: suffix }],
      },
    },
  }));

  return new PutBucketNotificationConfigurationCommand({
    Bucket: process.env.TARGET_BUCKET_NAME!,
    NotificationConfiguration: {
      LambdaFunctionConfigurations: configurations,
    },
  });
};

export const handler = async (event: CdkCustomResourceEvent, context: Context) => {
  const suffixList = event.ResourceProperties.suffixList as string[];
  const bucketName = process.env.TARGET_BUCKET_NAME!;
  const s3Client = new S3Client({});

  // Delete 時用の空設定
  let command = new PutBucketNotificationConfigurationCommand({
    Bucket: bucketName,
    NotificationConfiguration: {},
  });

  // Create / Update 時は実際の設定を作成
  if (event.RequestType === 'Create' || event.RequestType === 'Update') {
    command = createUpdateCommand(suffixList);
  }

  await s3Client.send(command);

  return { PhysicalResourceId: `${bucketName}-notification` };
};

ポイント:

  • INVOKE_FUNC_ARN に、S3 イベント発行時に呼び出す Lambda の ARN を設定します。
  • TARGET_BUCKET_NAME に、設定対象の S3 バケット名を指定します。
  • Create および Update リクエストでは同じロジックを使い、Delete では空設定を送信して通知設定を削除します。

2. CDK スタックへの Custom Resource 統合

次に、CDK スタック内で次の 2 つの Lambda を定義します。

  • S3 アップロードイベントを処理する s3-notification-invoke
  • Notification 設定を行う s3-notification-setting

そして、custom-resources.Provider を使って設定用 Lambda を Custom Resource のハンドラとして登録します。

import * as cdk from 'aws-cdk-lib';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { Provider } from 'aws-cdk-lib/custom-resources';
import { Construct } from 'constructs';

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

    // 1. S3 アップロードイベントを処理する Lambda
    const s3NotificationInvokeFunc = new lambda.Function(this, 's3-notification-invoke', {
      runtime: lambda.Runtime.NODEJS_22_X,
      code: lambda.Code.fromAsset('lambda/s3-notification-invoke'),
      handler: 'index.handler',
      functionName: 's3-notification-invoke',
    });

    // 2. Notification 設定を行う Lambda
    const s3NotificationSettingFunc = new lambda.Function(this, 's3-notification-setting', {
      runtime: lambda.Runtime.NODEJS_22_X,
      code: lambda.Code.fromAsset('lambda/s3-notification-setting'),
      handler: 'index.handler',
      functionName: 's3-notification-setting',
      environment: {
        INVOKE_FUNC_ARN: s3NotificationInvokeFunc.functionArn,
        TARGET_BUCKET_NAME: 'your-existing-bucket-name', // 対象バケット名に置き換えてください
      },
    });

    // S3 から通知ハンドラ Lambda への呼び出し権限を付与
    s3NotificationInvokeFunc.addPermission('AllowS3Invoke', {
      action: 'lambda:InvokeFunction',
      principal: new iam.ServicePrincipal('s3.amazonaws.com'),
      sourceArn: `arn:aws:s3:::your-existing-bucket-name`, // 対象バケット ARN に置き換えてください
    });

    // 3. Custom Resource Provider の定義
    const provider = new Provider(this, 'S3NotificationProvider', {
      onEventHandler: s3NotificationSettingFunc,
    });

    // 4. Custom Resource の作成と suffixList の指定
    new cdk.CustomResource(this, 'S3NotificationCustomResource', {
      serviceToken: provider.serviceToken,
      properties: {
        suffixList: ['.jpg', '.pdf'], // 必要に応じて拡張子を追加・変更
      },
    });
  }
}

手順概要:

  • 通知処理用 Lambda (s3-notification-invoke) をデプロイ
  • 設定用 Lambda (s3-notification-setting) をデプロイ
  • S3 が通知処理 Lambda を呼び出せるように権限を付与
  • Custom Resource を登録し、deploy 時に設定用 Lambda を呼び出して通知の作成/更新/削除を実行

3. まとめ

このパターンにより、CDK の Custom Resource 機能を活用して、CDK 単体では対応できない既存リソースへの追加設定や、ネイティブ SDK API 呼び出しをプログラマブルに実行できます。必要に応じて他の AWS リソースや機能にも応用し、CDK の適用範囲を拡張してください。

概要

技術的洞察、経験、思考を共有する個人ブログ

クイックリンク

お問い合わせ

  • Email: hushukang_blog@proton.me
  • GitHub

© 2025 CODE赤兎. 無断転載禁止