如何修復 AWS CloudFormation 中的「無法驗證以下目的地組態」錯誤?

3 分的閱讀內容
0

我訂閱 Amazon Simple Notification Service (Amazon SNS) 主題或 Amazon Simple Storage Service (Amazon S3) 事件通知的 AWS Lamdba 函數。我收到下列錯誤: 「無法驗證以下目的地組態。」 當我嘗試從範本中的 S3 儲存貯體設定 SNS 主題政策的相依性時,收到循環相依性驗證錯誤。

簡短說明

由於 AWS CloudFormation 處理相依性排序的方式,因此 Amazon S3 事件通知會定義為 S3 儲存貯體的屬性。這些通知會在建立 S3 儲存貯體資源時建立。

若要避免發生錯誤,您必須依下列順序建立資源:

  1. 建立 SNS 主題,因為 S3 儲存貯體會參考 SNS 主題。
  2. 建立 S3 儲存貯體,因為 SNS 主題政策同時參考 S3 儲存貯體和 SNS 主題。

在訂閱 SNS 主題以接收 S3 事件通知之前,您必須指定具有適當權限的主題政策 (AWS::SNS::TopicPolicy)。在建立訂閱之前,該主題政策必須存在。

請嘗試下列其中一種策略,以避免出現「無法驗證以下目的地組態」錯誤:

  • 在 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 資源。

若要針對具有不同名稱的 S3 儲存貯體使用相同的 AWS CloudFormation 範本,請為儲存貯體名稱定義參數。該參數允許您在堆疊建立期間將儲存貯體名稱作為參數傳遞以便不同的儲存貯體名稱使用相同的範本。

若要使用下列範例範本,您必須在堆疊建立期間傳遞儲存貯體名稱作為 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 範本翻轉,在 JSON 和 YAML 格式之間轉換 AWS CloudFormation 範本。


相關資訊

如何避免 AWS CloudFormation 中的 Lambda 事件通知發生「無法驗證以下目的地組態」錯誤?

AWS CloudFormation 堆疊更新

設定 Amazon SNS 通知

AWS 官方
AWS 官方已更新 2 年前