如何使用 AwsSdkCall 接口从 CDK 项目进行 AWS SDK 调用?
我想使用 AwsSdkCall 接口从 AWS Cloud Development Kit (AWS CDK) 项目进行 AWS SDK 调用。
简述
您可以将 AWS 软件开发工具包 (AWS SDK) 调用用于以下堆栈部署场景:
- 在创建和更新堆栈时动态检索配置。
- 检索 AWS CloudFormation 在返回值中不支持的资源的属性。
- 进行 AWS CloudFormation 不支持的小修补或配置更改。
可以在发生不同的 CloudFormation 堆栈操作事件(例如创建、删除或更新)时触发 AWS SDK 调用。无需为部署管线设置访问权限和工具即可进行 AWS SDK 调用。AWS SDK 运行时由 AWS CDK 设置。您可以自定义和限制自定义资源背后的 AWS Lambda 函数访问权限。
解决方法
注意: 以下示例使用 TypeScript。确保使用特定于您正在使用的编程语言的语法。
要使用 AwsSdkCall 进行 AWS SDK 调用,请使用以下参数:
- 对于 Service(服务),使用您打算调用的 AWS 服务。值区分大小写。
- 对于 Action(操作),使用您要进行的 API 调用或操作调用。这通常遵循驼峰式大小写模式,并且值区分大小写。
- 对于 Parameters(参数),使用您在发出 API 调用或操作调用时传递的可选参数。可以将参数声明为变量,然后将其传递给接口,类似于 API 有效载荷的 JSON 对象。有关详细信息,请参阅 AWS SDK for JavaScript(适用于 JavaScript 的 AWS SDK)。
示例 1: 动态检索配置
以下示例在堆栈创建期间从 AWS Systems Manager Parameter Store 中检索亚马逊机器映像 ID。其中展示如何通过 getResponseField 方法以及点号表示法引用 API 调用的响应,从而逐层访问 SDK 的响应结构:
import * as cdk from "aws-cdk-lib/core"; import { Construct } from "constructs"; import * as cr from "aws-cdk-lib/custom-resources"; export class Example1Stack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const getAmiId = new cr.AwsCustomResource(this, "GetAMIId", { onCreate: { service: "SSM", action: "getParameter", parameters: { Name: "/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-x86_64", }, physicalResourceId: cr.PhysicalResourceId.of("get-ami-id"), }, policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE, }), }); new cdk.CfnOutput(this, "ImageId", { value: getAmiId.getResponseField("Parameter.Value"), }); } }
示例 2: 检索 CloudFormation 中不可用的资源属性
CloudFormation 不会通过 Fn::GetAtt 公开所有资源属性。如果 CloudFormation 未返回您需要的值,则使用 SDK 调用直接从服务 API 中检索该值。您还可以使用此方法检索位于 CloudFormation 之外的资源及其未存储在堆栈导出、SSM 参数或 Secrets Manager 中的属性。
例如,AWS::Organizations::Organization 将 Id 和 ManagementAccountId 作为返回值公开,但是 CloudFormation 并不创建大多数组织。对 describeOrganization 的 SDK 调用可让您从成员账户检索这些值,且无需将组织包含在堆栈中。
import * as cdk from "aws-cdk-lib/core"; import { Construct } from "constructs"; import * as cr from "aws-cdk-lib/custom-resources"; export class Example2Stack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const orgInfo = new cr.AwsCustomResource(this, "DescribeOrg", { onCreate: { service: "Organizations", action: "describeOrganization", physicalResourceId: cr.PhysicalResourceId.of("describe-org"), outputPaths: ["Organization.Id", "Organization.MasterAccountId"], }, policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE, }), }); new cdk.CfnOutput(this, "OrgId", { value: orgInfo.getResponseField("Organization.Id"), }); new cdk.CfnOutput(this, "ManagementAccountId", { value: orgInfo.getResponseField("Organization.MasterAccountId"), }); } }
注意: 该示例使用 outputPaths 将响应限制为仅包含所需的字段。这样可以避免达到 4096 字节的 CloudFormation 响应限制。
示例 3:作出 CloudFormation 不支持的配置更改
有些操作没有相应的 CloudFormation 资源或属性。例如,CloudFormation 可以创建 DynamoDB 表,但不能向其中插入项目。要解决此问题,请在部署时使用 AwsSdkCall 播种初始数据。
以下示例使用 onCreate,因此它仅在您首次创建堆栈时插入项目。要同时在堆栈更新时更新项目,请向 onUpdate 添加相同的调用。
import * as cdk from "aws-cdk-lib/core"; import { Construct } from "constructs"; import * as cr from "aws-cdk-lib/custom-resources"; import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; export class Example3Stack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const table = new dynamodb.Table(this, "ConfigTable", { partitionKey: { name: "PK", type: dynamodb.AttributeType.STRING }, }); new cr.AwsCustomResource(this, "SeedData", { onCreate: { service: "DynamoDB", action: "putItem", parameters: { TableName: table.tableName, Item: { PK: { S: "CONFIG" }, version: { S: "1.0" }, enabled: { BOOL: true }, }, }, physicalResourceId: cr.PhysicalResourceId.of("seed-data"), }, policy: cr.AwsCustomResourcePolicy.fromSdkCalls({ resources: [table.tableArn], }), }); } }
处理复杂的权限情境
policy 属性向自定义资源背后的 Lambda 函数授予权限。使用 fromSdkCalls() 会自动将每个 API 调用转换为相应的 IAM 权限。请尽可能将权限范围限定为特定资源 ARN,而不是使用 ANY_RESOURCE(示例 3)。
在某些情况下,fromSdkCalls() 可能无法生成所需的所有权限。例如,如果示例 3 中的 DynamoDB 表使用客户自主管理型 KMS 密钥,则 fromSdkCalls() 仅生成 dynamodb:PutItem,根本不添加 KMS 权限。部署将失败,因为 DynamoDB 需要 kms:Encrypt、kms:Decrypt 和 kms:GenerateDataKey 将项目写入加密表。您可以使用 fromStatements() 来指定确切的权限。
例如:
import * as cdk from "aws-cdk-lib/core"; import { Construct } from "constructs"; import * as cr from "aws-cdk-lib/custom-resources"; import * as dynamodb from "aws-cdk-lib/aws-dynamodb"; import * as kms from "aws-cdk-lib/aws-kms"; import * as iam from "aws-cdk-lib/aws-iam"; export class Example4Stack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); const encryptionKey = new kms.Key(this, "TableKey"); const table = new dynamodb.Table(this, "ConfigTable", { partitionKey: { name: "PK", type: dynamodb.AttributeType.STRING }, encryption: dynamodb.TableEncryption.CUSTOMER_MANAGED, encryptionKey, }); new cr.AwsCustomResource(this, "SeedData", { onCreate: { service: "DynamoDB", action: "putItem", parameters: { TableName: table.tableName, Item: { PK: { S: "CONFIG" }, version: { S: "1.0" }, enabled: { BOOL: true }, }, }, physicalResourceId: cr.PhysicalResourceId.of("seed-data"), }, policy: cr.AwsCustomResourcePolicy.fromStatements([ new iam.PolicyStatement({ actions: ["dynamodb:PutItem"], resources: [table.tableArn], }), new iam.PolicyStatement({ actions: ["kms:Encrypt", "kms:Decrypt", "kms:GenerateDataKey"], resources: [encryptionKey.keyArn], }), ]), }); } }
- 语言
- 中文 (简体)

This article was reviewed and updated on 2026-06-01.