使用 CDK Custom Resource 实现自定义 AWS 设置
发布于
2025年4月25日
更新于
2025年4月25日
15
分钟阅读
AWS
在本篇文章中,我们将介绍如何通过 CDK 的 Custom Resource 功能,为 CDK 原生不支持的 AWS 资源或功能添加自定义配置。
举例来说,CDK 默认并不支持为已有的 S3 Bucket 添加事件通知(Notification)。下面的示例演示,如何在一个已存在的 S3 Bucket 上,通过 Custom Resource 动态添加 Notification 设置,使其在指定后缀的文件上传时,自动触发 Lambda 函数。
一、编写用于配置 S3 Notification 的 Lambda
首先,我们需要一个专门负责为 S3 Bucket 设置 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({});
let command = new PutBucketNotificationConfigurationCommand({
Bucket: bucketName,
NotificationConfiguration: {}, // 用于 Delete 操作
});
if (event.RequestType === 'Create' || event.RequestType === 'Update') {
command = createUpdateCommand(suffixList);
}
await s3Client.send(command);
return { PhysicalResourceId: `${bucketName}-notification` };
};
要点说明:
INVOKE_FUNC_ARN环境变量指定要被触发的 Lambda ARN。TARGET_BUCKET_NAME环境变量指定目标 S3 Bucket 名称(或 ARN)。- 通过
Create和Update请求类型,调用同一逻辑;删除(Delete)时则发送一个空配置,以清除 Notification。
二、在 CDK Stack 中集成 Custom Resource
接下来,在 CDK Stack 中创建两个 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. 配置 S3 Notification 的 Custom Resource 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', // 替换为目标 Bucket 名称
},
});
// 赋予 S3 调用目标 Lambda 的权限
s3NotificationInvokeFunc.addPermission('AllowS3Invoke', {
action: 'lambda:InvokeFunction',
principal: new iam.ServicePrincipal('s3.amazonaws.com'),
sourceArn: `arn:aws:s3:::your-existing-bucket-name`, // 替换为目标 Bucket ARN
});
// 3. 定义 Custom Resource Provider
const provider = new Provider(this, 'S3NotificationProvider', {
onEventHandler: s3NotificationSettingFunc,
});
// 4. 创建 Custom Resource,传入后缀列表参数
new cdk.CustomResource(this, 'S3NotificationCustomResource', {
serviceToken: provider.serviceToken,
properties: {
suffixList: ['.jpg', '.pdf'], // 根据需要添加后缀
},
});
}
}
关键步骤:
- 部署通知处理 Lambda:
s3-notification-invoke用于处理来自 S3 的事件。 - 部署配置 Lambda:
s3-notification-setting负责对已有 Bucket 调用PutBucketNotificationConfiguration。 - 添加权限:允许 S3 对
s3-notification-invokeLambda 发起调用。 - 注册 Custom Resource:CDK 在
deploy时,自动调用配置 Lambda,完成 Notification 的创建、更新或删除。
三、总结
通过以上示例,我们利用 CDK 的 Custom Resource 机制,灵活地为 CDK 本身不支持的场景(如对已有资源进行额外配置)提供了可编程的解决方案。你可以将此模式推广到各种需要“落地”原生 SDK API、或自定义 AWS 资源行为的场景中,从而让 CDK 的能力更为强大与全面。