AWS CDK 自定义资源
AWS CDK v1在2023-06-01上达到了支持结束. 此软件包不再更新,用户应该迁移到 AWS CDK v2.
关于如何移徙的更多信息,请参见: 移动到 AWS CDK v2 指南。 。 。 .
供应商框架
AWS 云阵 自定义资源 用于提供 发动机。 当 CloudFormation 需要创建、更新或删除自定义资源时, 它向一个 自定义资源提供者提供方 处理事件(例如创建资源),并向 CloudFormation 发送回复.
这个 @aws-cdk/custom-resources.Provider 构造是用于
aWS CloudFormation 自定义资源的执行提供者。 该框架提供了高级别的API,使执行强健的API更加容易
和强大的定制资源,包括以下能力:
- 处理对AWS CloudFormation 的响应并防范被封锁 部署
- 验证处理器返回值, 帮助正确处理器执行
- 支持同步处理器,以启用需要长时间等待资源,超过AWS Lambda超时的操作
- 执行物理资源ID的默认行为.
以下代码显示 Provider 结合使用构造
带有 CustomResource 和用户提供的AWS Lambda 函数,用于执行
实际操作者.
declare const onEvent: lambda.Function;
declare const isComplete: lambda.Function;
declare const myRole: iam.Role;
const myProvider = new cr.Provider(this, 'MyProvider', {
onEventHandler: onEvent,
isCompleteHandler: isComplete, // optional async "waiter"
logRetention: logs.RetentionDays.ONE_DAY, // default is INFINITE
role: myRole, // must be assumable by the `lambda.amazonaws.com` service principal
});
new CustomResource(this, 'Resource1', { serviceToken: myProvider.serviceToken });
new CustomResource(this, 'Resource2', { serviceToken: myProvider.serviceToken });
供应商是通过AWS Lambda功能执行的,这些功能由AWS Lambda 应对生命周期事件的提供者框架.
用户至少必须界定 onEvent 操作器,由
所有资源生命周期活动的框架Create, (中文(简体) ), Update 财务报告和审定财务报表 Delete(中文(简体) )
并返回结果,然后提交到 Cloud Formation .
以下实例是 Python 执行 onEvent数字 :
def on_event(event, context):
print(event)
request_type = event['RequestType']
if request_type == 'Create': return on_create(event)
if request_type == 'Update': return on_update(event)
if request_type == 'Delete': return on_delete(event)
raise Exception("Invalid request type: %s" % request_type)
def on_create(event):
props = event["ResourceProperties"]
print("create new resource with props %s" % props)
# add your create code here...
physical_id = ...
return { 'PhysicalResourceId': physical_id }
def on_update(event):
physical_id = event["PhysicalResourceId"]
props = event["ResourceProperties"]
print("update resource %s with props %s" % (physical_id, props))
# ...
def on_delete(event):
physical_id = event["PhysicalResourceId"]
print("delete resource %s" % physical_id)
# ...
用户还可以提供一个额外的处理器,称为 isComplete,用于案件
寿命周期操作无法立即完成。 这个
isComplete 处理器会在之后同步重试 onEvent 直到它结束
返回时 IsComplete: true,或直到供应商总超时.
以下实例是 Python 执行 isComplete数字 :
def is_complete(event, context):
physical_id = event["PhysicalResourceId"]
request_type = event["RequestType"]
# check if resource is stable based on request_type
is_ready = ...
return { 'IsComplete': is_ready }
安全说明: 自定义资源提供者框架将写入
ResponseURL, (中文(简体) ), 用于报告自定义资源执行的成败的 S3 URL 返回 CloudFormation, 以可读形式显示 AWS 步骤函数执行历史.在您的账户中能够列出并读取 AWS 步骤功能处决的任何人都可以写 对此 URL 的假响应, 并让您的 CloudFormation 部署失败 .
如果您的威胁模式要求您不能信任有能力的演员, 请不要使用此库 在您的账户中列出 StepFunction 处决.
处理生命周期事件:关于活动的
用户定义 onEvent 每当资源时都会引用 AWS Lambda 函数
发生生命周期事件。 该函数预计将处理事件并返回
对框架的反应,其中至少包括实物资源ID.
若为 onEvent 返回成功,框架将提交“SUCCESS”响应
改为用于此资源操作的 AWS CloudFormation 。 如果提供者是
一个同步 (单位:千美元)isCompleteHandler 实值
定义),框架将仅根据以下结果提交答复:
isComplete。 。 。 .
若为 onEvent 扔出错误,框架将提交“FAILED”响应
AWS云阵.
输入活动包括以下领域: 自定义资源 提供者请求数字 :
| 外地 | 类型 | 说明 |
|---|---|---|
RequestType | 字符串 | 生命周期事件的类型: Create, (中文(简体) ), Update 或者说 Delete。 。 。 . |
LogicalResourceId | 字符串 | AWS CloudFormation模板中自定义资源的模板开发者选择名称(逻辑ID). |
PhysicalResourceId | 字符串 | 此字段仅用于 Update 财务报告和审定财务报表 Delete 包含返回的值 PhysicalResourceId 前次行动. |
ResourceProperties | 贾森 | 此字段包含自定义资源模板中定义的属性 . |
OldResourceProperties | 贾森 | 此字段仅用于 Update 并包含更新请求前已声明的资源属性. |
ResourceType | 字符串 | 在模板中为此自定义资源定义的资源类型 。 提供者可以处理任何数量的自定义资源类型. |
RequestId | 字符串 | 请求的唯一身份 . |
StackId | 字符串 | 识别包含自定义资源的堆栈的 ARN . |
返回值从 onEvent 必须是具有以下字段的 JSON 对象:
| 外地 | 类型 | 需求 | 说明 |
|---|---|---|---|
PhysicalResourceId | 字符串 | 没有 | 所分配/分配的资源实物标识。 如果省略 Create 活动,活动 RequestId 将被使用。 对于 Update,将使用当前物理ID。 如果返回了不同的值, 将随同Cloud Formation Delete 用于上一个ID(资源替换)。 对于 Delete,它总是返回当前物理资源ID,如果用户返回一个不同的,则会出现出错. |
Data | 贾森 | 没有 | 资源属性,稍后可通过 Fn::GetAtt 在自定义资源对象上. |
NoEcho | 布尔 | 没有 | 是否通过使用自定义资源来隐藏自定义资源的输出 Fn::GetAtt 函数. |
| 任意 | 任意 | 没有 | 答复中包括的任何其他领域将转交 isComplete。这有时有助于在处理器之间传递状态. |
同步提供者: 完成
提供资源是同步进行的,这并非罕见 行动,这意味着行动不会立即结束,我们 需要"等待"直到资源稳定.
供应商框架允许用户使用
在 isCompleteHandler。 。 。 .
框架将反复引用处理器 queryInterval时
isComplete 返回时使用 IsComplete: true,框架将提交
"SUCCESS"回应AWS云阵. 若为 totalTimeout 期满和
操作尚未完成,框架将提交“FAILED”响应
带有“ 行动超时” 的信息.
如果出错, 框架将向 AWS 提交“ FAILED” 响应 云门会.
输入事件到 isComplete 包含所有请求字段,结合所有
从 onEvent如果 PhysicalResourceId 没有明确
从 onEvent,它的价值会根据热度计算
说明.
返回值必须是具有以下字段的 JSON 对象:
| 外地 | 类型 | 需求 | 说明 |
|---|---|---|---|
IsComplete | 布尔 | 对 | 说明操作是否已经完成. |
Data | 贾森 | 没有 | 只有在 IsComplete 实值 true 并包括额外的资源属性。 这些属性将是: 合并 与那些从 onEvent |
物理资源标识
CloudFormation中的每一个资源都有物理资源ID. 当资源是
创建, 创建 PhysicalResourceId 从 Create 操作被存储
由 AWS CloudFormation 指定,并指定为此资源定义的逻辑 ID
在模板中。 如果有的话 Create 没有操作返回 PhysicalResourceId, (中文(简体) ),
框架将使用 RequestId 作为默认。 这足以
各种案例,例如只查询数据的"pseudo-resources".
对于 Update 财务报告和审定财务报表 Delete ,资源活动将始终包括
当前 PhysicalResourceId 资源.
当 Update 操作时,默认行为是返回当前
物理资源标识。如果 onEvent 返回 a PhysicalResourceId 这是
与当前不同,AWS CloudFormation将将其作为一种
资源替换,它会发布一个后续 Delete 运行于
旧资源.
作为拇指的常规,如果自定义资源支持配置物理名称
(例如,您可以指定 BucketName 当定义一个 AWS::S3::Bucket),你这个
必须返回此名称 PhysicalResourceId 并确保处理
替换得当。 这个 S3File 示例证明这一点
通过 objectKey 属性.
当有错误时
如上所述,如果任何用户处理器失败(即丢出例外) 或超时(由于他们的AWS Lambda时间超时),框架将锁定这些 错误并提交 AWS 云格式的“ FAILED” 响应, 以及错误 留言.
由于错误可能发生在提供者的多处(框架, onEvent, (中文(简体) ),
isComplete因此,必须知道,在下述情况下:
资源操作失败,即使操作技术成功(即:.
isConflete 丢出一个错误.
当AWS CloudFormation收到"FAILED"响应时,它将尝试滚动 回到最后的状态 这对不同的意义不同 生命周期事件:
- 如果有的话
Create事件失败, 资源提供者框架将自动 忽略随后的Delete由AWS CloudFormation发布的操作. 这个 框架目前不支持自定义此行为(见 https://github.com/aws/aws-cdk/issues/5524 (英语)) (中文(简体) ). - 如果一个
Update事件失败, CloudFormation 会发布额外的Update与以前的属性. - 如果有的话
Delete事件失败, CloudFormation 将放弃此资源.
需要处理的重要案件
在将自定义资源写入到 在所有情况下确保您的自定义资源表现正确 :
- 期间
Create数字 :- 如果创建失败 提供者框架 会确保你
以后就别了
Delete活动。 如果你的创作涉及多个不同的 行动,这是你的责任 抓住和重新扔和清理 已执行的任何部分更新。 保证你 API呼叫超时和Lambda超时允许这样做.
- 如果创建失败 提供者框架 会确保你
以后就别了
- 期间
Update数字 :- 如果更新失败, 您将会得到一个后续
Update事件 以滚回上一州(与ResourceProperties财务报告和审定财务报表OldResourceProperties页:1. - 如果你还了别的东西
PhysicalResourceId,您将随后 已收到Delete用于清理资源上一个状态的事件.
- 如果更新失败, 您将会得到一个后续
- 期间
Delete数字 :- 如果自定义资源的行为与另一个 AWS 资源绑定 (例如,它的存在是为了清理状态资源的内容),保留 考虑到您的自定义资源可能会被独立删除 您必须确认执行此动作是适当的.
- (只有您是 没有 (使用供应商框架)a
Delete事件 可能是由于失败Create。您必须能够处理案件 您想要删除的资源尚未创建 .
- 如果您更新自定义资源的代码并更改格式
资源属性,请注意可能已经部署
您的自定义资源实例, 您仍可收到
页:1 旧 属性格式
ResourceProperties(期间)Delete财务报告和审定财务报表 倒滚Updates或 在内OldResourceProperties(滚动期间)Update) (中文(简体) ). 您必须继续处理所有可能的属性组合 您的自定义资源过去曾被创建过 .
供应商框架执行政策
类似于任何 AWS Lambda 函数, 如果用户定义的处理器需要
访问 AWS 资源, 您必须定义这些权限
使用“赠款”方法,例如 myBucket.grantRead(myHandler)),使用 myHandler.addToRolePolicy
或指定一个 initialPolicy 当定义函数时.
铭记在多数情况下,一个供应商将被用于多个供应商 资源实例。 这意味着提供者的执行政策必须 拥有适当的特权.
以下例子表明: onEvent 处理器 s3:GetObject* 权限
所有桶 :
new lambda.Function(this, 'OnEventHandler', {
runtime: lambda.Runtime.NODEJS_14_X,
handler: 'index.handler',
code: lambda.Code.fromInline('my code'),
initialPolicy: [
new iam.PolicyStatement({ actions: [ 's3:GetObject*' ], resources: [ '*' ] }),
],
});
超时
用户负责定义 AWS Lambda 函数的超时 用户定义的处理器。 建议不超过 14分钟 暂停, 由于所有框架功能都配置为15分钟后超时 最大AWS蓝巴达超时.
如果你的行动接管了 14分钟,建议的方法是
执行 同步提供者,以及
然后配置同步重试通过
queryInterval 编辑 totalTimeout 选项.
提供者框架实例
本单元包括一些自定义资源实施的实例:
S3 文件
S3桶中装有文字内容的物件。 见源代码 联 合 国 构造 财务报告和审定财务报表 处理器。 。 。 .
以下示例将创建文件 folder/file1.txt 内部 myBucket
内容 hello!。 。 。 .
// This example exists only for TypeScript
declare const myBucket: s3.Bucket;
new cr.S3File(this, 'MyFile', {
bucket: myBucket,
objectKey: 'folder/file1.txt', // optional
content: 'hello!',
public: true, // optional
});
该样本显示了以下概念:
- 同步执行
isComplete未定义) - 如果
objectKey未定义 - 处理物理名称更改
- 返回资源属性
- 处理删除
- 在类型脚本中执行
S3Assert 软件
检查一个 S3 对象的文字内容是否匹配某个值。 只要未找到对象或数值不同,检查将重复5分钟。 参见源代码 构造 财务报告和审定财务报表 处理器。 。 。 .
以下实例定义了 S3Assert 资源等待到
myfile.txt 内 myBucket 已存在并包含内容 foo bar数字 :
// This example exists only for TypeScript
declare const myBucket: s3.Bucket;
new cr.S3Assert(this, 'AssertMyFile', {
bucket: myBucket,
objectKey: 'myfile.txt',
expectedContent: 'foo bar',
});
该样本显示了以下概念:
- 同步执行
- 非内脏物理身份证明
- 在Python执行
自定义提供者函数名
在多账户环境中,或当自定义资源可在多个账户重新使用时 堆栈 手动设置“ 提供者函数 Lambda” 的名称可能有用, 因此 拥有预定义的服务符号ARN.
declare const onEvent: lambda.Function;
declare const isComplete: lambda.Function;
declare const myRole: iam.Role;
const myProvider = new cr.Provider(this, 'MyProvider', {
onEventHandler: onEvent,
isCompleteHandler: isComplete,
logRetention: logs.RetentionDays.ONE_DAY,
role: myRole,
providerFunctionName: 'the-lambda-name', // Optional
});
AWS API 自定义资源
有时单次API呼叫可以填补CloudFormation覆盖中的空白. 单位
这个案子你可以用 AwsCustomResource 构造。 此构造创建
一个可定制的自定义资源,用于发出特定的 API 呼叫
CREATE, (中文(简体) ), UPDATE 财务报告和审定财务报表 DELETE 事件。 此外,API返回的数据
调用可以提取并用于其他构造/资源(创建真实的
使用云格式依赖 Fn::GetAtt 盖下.
自定义资源的物理 ID 可以指定或从数据中得出 由API呼叫返回.
这个 AwsCustomResource 对JavaScript使用AWS SDK. 服务、行动和
参数可见于 API 文档。 。 。 .
数据路径必须使用点标记来指定,例如获取字符串值
会 议 日 程 和 议 程 Title 属性 dynamodb.query 应该
为: Items.0.Title.S。 。 。 .
为了确保最新的API呼叫可用,安装了最新的AWS SDK v2
在 Lambda 函数中执行自定义资源。 安装大约60个
秒数。 如果您喜欢优化速度, 您可以通过设置来禁用安装
页:1 installLatestAwsSdk 向 false。 。 。 .
自定义资源执行政策
你必须提供 policy 属性定义将应用于 API 呼叫的 IAM 策略.
图书馆提供两种工厂方法来快速配置:
AwsCustomResourcePolicy.fromSdkCalls- 用这个自动生成IAM 基于配置的 SDK 调用的政策声明 。 记住两件事 使用此策略时:- 这个政策变体假设IAM政策名称与API相同
电话 在99%的案件中都是这样,但也有例外(例如,
3号
PutBucketLifecycleConfiguration需求s3:PutLifecycleConfiguration权限,兰布达的Invoke需求lambda:InvokeFunction权限)。 使用fromStatements如果你想的话 做一个需要不同IAM动作名的呼叫. - 您必须提供特定的 ARN 或明确使用
AwsCustomResourcePolicy.ANY_RESOURCE允许访问任何资源.
- 这个政策变体假设IAM政策名称与API相同
电话 在99%的案件中都是这样,但也有例外(例如,
3号
AwsCustomResourcePolicy.fromStatements- 用这个来指定自己的 自定义语句.
自定义资源也执行 iam.IGrantable,从而有可能使用 grantXxx() 方法。 。 .
由于此自定义资源使用单通的Lambda函数,需要注意 函数的作用最终会累积来自所有 资源.
链式API呼叫可以通过创建依赖性来实现:
const awsCustom1 = new cr.AwsCustomResource(this, 'API1', {
onCreate: {
service: '...',
action: '...',
physicalResourceId: cr.PhysicalResourceId.of('...'),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
const awsCustom2 = new cr.AwsCustomResource(this, 'API2', {
onCreate: {
service: '...',
action: '...',
parameters: {
text: awsCustom1.getResponseField('Items.0.text'),
},
physicalResourceId: cr.PhysicalResourceId.of('...'),
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
物理资源 Id 参数
一些AWS API可能要求将物理资源id作为进行更新和删除的参数来传递. 你可以通过使用它 PhysicalResourceIdReference。 。 。 .
const awsCustom = new cr.AwsCustomResource(this, 'aws-custom', {
onCreate: {
service: '...',
action: '...',
parameters: {
text: '...',
},
physicalResourceId: cr.PhysicalResourceId.of('...'),
},
onUpdate: {
service: '...',
action: '...',
parameters: {
text: '...',
resourceId: new cr.PhysicalResourceIdReference(),
},
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
})
处理自定义资源出错
API调用产生的每一个出错都按原样处理,并将导致"FAILED"响应被提交到Cloud Formation.
通过指定 ignoreErrorCodesMatching 属性,它接受正则表达式,即
测试 code 答复的属性。 如果匹配,则提交“SUCCESS”响应.
请注意,在这种情况下,呼叫响应数据和 Data 密钥提交 CloudFormation 将既是空的 JSON 对象.
由于成功提供资源可能或不会产生产出,这给我们带来了一些限制:
PhysicalResourceId.fromResponse- 由于呼叫响应数据可能是空的,我们不能用它来提取物理ID.getResponseField财务报告和审定财务报表getResponseFieldReference- 自从..Data键为空,资源将没有任何属性,因此,引用这些函数将导致出错.
在这两种情况下,如果试图与 ignoreErrorCodesMatching。 。 。 .
自定义执行自定义资源的 Lambda 函数
使用 role, (中文(简体) ), timeout, (中文(简体) ), logRetention 财务报告和审定财务报表 functionName 要自定义的属性
lambda 函数执行自定义资源:
declare const myRole: iam.Role;
new cr.AwsCustomResource(this, 'Customized', {
role: myRole, // must be assumable by the `lambda.amazonaws.com` service principal
timeout: Duration.minutes(10), // defaults to 2 minutes
logRetention: logs.RetentionDays.ONE_WEEK, // defaults to never delete logs
functionName: 'my-custom-name', // defaults to a CloudFormation generated name
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
限制自定义资源的输出
CloudFormation 对自定义资源响应规定了4096字节的硬限制 对象。 如果您的 API 调用返回超过此限制的对象, 您可以限制 aPI 响应中自定义资源返回到特定路径的数据 :
new cr.AwsCustomResource(this, 'ListObjects', {
onCreate: {
service: 's3',
action: 'listObjectsV2',
parameters: {
Bucket: 'my-bucket',
},
physicalResourceId: cr.PhysicalResourceId.of('id'),
outputPaths: ['Contents.0.Key', 'Contents.1.Key'], // Output only the two first keys
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
请注意,即使限制自定义资源的输出,仍然可以使用任意
路径在 PhysicalResourceId.fromResponse()。 。 。 .
自定义资源示例
用 SES 验证一个域
import * as route53 from '@aws-cdk/aws-route53';
const verifyDomainIdentity = new cr.AwsCustomResource(this, 'VerifyDomainIdentity', {
onCreate: {
service: 'SES',
action: 'verifyDomainIdentity',
parameters: {
Domain: 'example.com',
},
physicalResourceId: cr.PhysicalResourceId.fromResponse('VerificationToken'), // Use the token returned by the call as physical id
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
declare const zone: route53.HostedZone;
new route53.TxtRecord(this, 'SESVerificationRecord', {
zone,
recordName: `_amazonses.example.com`,
values: [verifyDomainIdentity.getResponseField('VerificationToken')],
});
获取安全 SSM 参数的最新版本
const getParameter = new cr.AwsCustomResource(this, 'GetParameter', {
onUpdate: { // will also be called for a CREATE event
service: 'SSM',
action: 'getParameter',
parameters: {
Name: 'my-parameter',
WithDecryption: true,
},
physicalResourceId: cr.PhysicalResourceId.of(Date.now().toString()), // Update physical id to always fetch the latest version
},
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
// Use the value in another construct with
getParameter.getResponseField('Parameter.Value');
A 私营HostedZone公司与VPC公司从另一个账户分享
const getParameter = new cr.AwsCustomResource(this, 'AssociateVPCWithHostedZone', {
onCreate: {
assumedRoleArn: 'arn:aws:iam::OTHERACCOUNT:role/CrossAccount/ManageHostedZoneConnections',
service: 'Route53',
action: 'associateVPCWithHostedZone',
parameters: {
HostedZoneId: 'hz-123',
VPC: {
VPCId: 'vpc-123',
VPCRegion: 'region-for-vpc',
},
},
physicalResourceId: cr.PhysicalResourceId.of('${vpcStack.SharedVpc.VpcId}-${vpcStack.Region}-${PrivateHostedZone.HostedZoneId}'),
},
//Will ignore any resource and use the assumedRoleArn as resource and 'sts:AssumeRole' for service:action
policy: cr.AwsCustomResourcePolicy.fromSdkCalls({
resources: cr.AwsCustomResourcePolicy.ANY_RESOURCE,
}),
});
这个模块是 AWS 云开发套件 项目.