如何修复 AWS CloudFormation 中出现的“Unable to validate the following destination configurations(无法验证以下目标配置)”错误?
上次更新日期:2022 年 5 月 31 日
我订阅 Amazon Simple Storage Service(Amazon S3)事件通知的 Amazon Simple Notification Service(Amazon SNS)主题或 AWS Lambda 函数。我收到以下错误:“Unable to validate the following destination configurations(无法验证以下目标配置)”。 尝试从模板中的 S3 存储桶设置与 SNS 主题策略的依赖项时,我收到循环依赖项验证错误。
简短描述
因为 AWS CloudFormation 处理依赖关系排序的方式,Amazon S3 事件通知定义为 S3 存储桶的属性。在创建 S3 存储桶资源时会建立这些通知。
要避免错误,您必须按以下顺序创建资源:
- 创建 SNS 主题,因为 S3 存储桶引用 SNS 主题。
- 创建 S3 存储桶,因为 SNS 主题策略引用 S3 存储桶和 SNS 主题。
在订阅 S3 事件通知的 SNS 主题之前,您必须使用适当的权限指定主题策略(AWS::SNS::TopicPolicy)。创建订阅之前,该主题策略必须已存在。
请尝试以下其中一个策略,以避免出现“Unable to validate the following destination configurations”错误:
- 在 AWS CloudFormation 模板中指定 BucketName 的值
- 创建堆栈,然后执行堆栈更新
解决方法
在 AWS CloudFormation 模板中指定 BucketName 的值
通过为 AWS CloudFormation 模板的 S3Bucket 资源中的 BucketName 属性指定值,来使用 S3 存储桶的静态名称。这样就不需要在 SNS 主题策略中包含 {"Ref": "paramBucketName"}。同样可避免 SNS 主题策略与 Amazon S3 之间的内在依赖项。
以下示例 AWS CloudFormation 模板指定了 BucketName 属性的硬编码值(-Bucket-Name-)。在您的模板中,将 -Bucket-Name- 的所有实例替换为您的存储桶名称。
{
"Resources": {
"SNSTopic": {
"Type": "AWS::SNS::Topic"
},
"SNSTopicPolicy": {
"Type": "AWS::SNS::TopicPolicy",
"Properties": {
"PolicyDocument": {
"Id": "MyTopicPolicy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement-id",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "sns:Publish",
"Resource": {
"Ref": "SNSTopic"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
"-Bucket-Name-"
]
]
}
}
}
}
]
},
"Topics": [
{
"Ref": "SNSTopic"
}
]
}
},
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"DependsOn": [
"SNSTopicPolicy"
],
"Properties": {
"AccessControl": "BucketOwnerFullControl",
"BucketName": "-Bucket-Name-",
"NotificationConfiguration": {
"TopicConfigurations": [
{
"Topic": {
"Ref": "SNSTopic"
},
"Event": "s3:ObjectCreated:Put"
}
]
}
}
}
}
}
注意:S3Bucket 资源具有已设置为 SNSTopicPolicy 的显式 DependsOn 值。此属性会指定模板将在 S3Bucket 资源之前创建 SNSTopicPolicy 资源。
要将相同的 AWS CloudFormation 模板用于名称不同的 S3 存储桶,请为存储桶名称定义参数。通过参数可以将相同模板用于不同的存储桶名称,方法是在堆栈创建期间以参数形式传递存储桶名称。
要使用以下示例模板,您必须在堆栈创建期间以 paramBucketName 参数形式传递存储桶名称。
{
"Parameters": {
"paramBucketName": {
"Type": "String",
"Description": "Bucket Name"
}
},
"Resources": {
"SNSTopic": {
"Type": "AWS::SNS::Topic"
},
"SNSTopicPolicy": {
"Type": "AWS::SNS::TopicPolicy",
"Properties": {
"PolicyDocument": {
"Id": "MyTopicPolicy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement-id",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "sns:Publish",
"Resource": {
"Ref": "SNSTopic"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "paramBucketName"
}
]
]
}
}
}
}
]
},
"Topics": [
{
"Ref": "SNSTopic"
}
]
}
},
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"DependsOn": [
"SNSTopicPolicy"
],
"Properties": {
"AccessControl": "BucketOwnerFullControl",
"BucketName": {
"Ref": "paramBucketName"
},
"NotificationConfiguration": {
"TopicConfigurations": [
{
"Topic": {
"Ref": "SNSTopic"
},
"Event": "s3:ObjectCreated:Put"
}
]
}
}
}
}
}
创建堆栈,然后执行堆栈更新
将堆栈创建分成两个阶段。首先,创建堆栈,但不在 S3Bucket 资源中指定 NotificationConfiguration 属性。然后,执行堆栈更新以添加 S3 事件通知。这样可避免在创建 SNS 主题策略之前设置 S3 事件通知。
1. 创建所有资源,包括 SNS 主题策略。例如:
{
"Resources": {
"SNSTopic": {
"Type": "AWS::SNS::Topic"
},
"SNSTopicPolicy": {
"Type": "AWS::SNS::TopicPolicy",
"Properties": {
"PolicyDocument": {
"Id": "MyTopicPolicy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement-id",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "sns:Publish",
"Resource": {
"Ref": "SNSTopic"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3Bucket"
}
]
]
}
}
}
}
]
},
"Topics": [
{
"Ref": "SNSTopic"
}
]
}
},
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"AccessControl": "BucketOwnerFullControl"
}
}
}
}
2. 更新堆栈以添加 S3 事件通知。例如:
{
"Resources": {
"SNSTopic": {
"Type": "AWS::SNS::Topic"
},
"SNSTopicPolicy": {
"Type": "AWS::SNS::TopicPolicy",
"Properties": {
"PolicyDocument": {
"Id": "MyTopicPolicy",
"Version": "2012-10-17",
"Statement": [
{
"Sid": "Statement-id",
"Effect": "Allow",
"Principal": {
"Service": "s3.amazonaws.com"
},
"Action": "sns:Publish",
"Resource": {
"Ref": "SNSTopic"
},
"Condition": {
"ArnLike": {
"aws:SourceArn": {
"Fn::Join": [
"",
[
"arn:aws:s3:::",
{
"Ref": "S3Bucket"
}
]
]
}
}
}
}
]
},
"Topics": [
{
"Ref": "SNSTopic"
}
]
}
},
"S3Bucket": {
"Type": "AWS::S3::Bucket",
"Properties": {
"AccessControl": "BucketOwnerFullControl",
"NotificationConfiguration": {
"TopicConfigurations": [
{
"Topic": {
"Ref": "SNSTopic"
},
"Event": "s3:ObjectCreated:Put"
}
]
}
}
}
}
}
注意:您可以使用 AWS CloudFormation Template Flip,在 JSON 和 YAML 格式之间转换 AWS CloudFormation 模板。