如何避免 CloudFormation 中的 Lambda 事件通知發生「無法驗證以下目標組態」錯誤?
當我部署 AWS CloudFormation 範本時,我的堆疊會失敗。然後,我收到類似以下內容的錯誤: 「無法驗證以下目的地組態。」
簡短說明
當您使用下列資源部署 CloudFormation 範本時,您會收到這個錯誤:
- AWS Lambda 函數資源
- 具有參考 Lambda 函數之 NotificationConfiguration 屬性的Amazon Simple Storage Service (Amazon S3) 儲存貯體資源
- 具有符合 Lambda 函數和 S3 儲存貯體之 FunctionName 和 SourceArn 屬性的 Lambda 權限資源
Amazon S3 在建立儲存貯體時必須驗證通知組態。驗證是透過檢查儲存貯體是否具有將事件推送至 Lambda 函數的權限來完成。權限資源 (必須存在才能通過此檢查) 需要儲存貯體名稱。這意味著權限資源取決於儲存貯體,並且儲存貯體取決於權限資源。
**注意:**如果您嘗試透過實作類似下列程式碼範例的 DependsOn 資源屬性來解決這個問題,就會收到「資源之間的循環相依性」錯誤。
下列範例顯示 S3 儲存貯體資源與 Lambda 權限資源的 SourceArn 屬性之間的循環相依性。
"Resources": { "MyS3BucketPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", ... ... "SourceArn": { "Ref": "MyS3Bucket" } } }, "MyS3Bucket": { "DependsOn" : "MyS3BucketPermission", ... ...
**重要:**最佳做法是將 SourceAccount 屬性新增至 Amazon S3 事件來源的 Lambda 權限資源。您新增屬性是因為 Amazon S3 的 Amazon Resource Name (ARN) 不包含帳戶 ID。SourceArn 屬性適用於大多數其他事件來源,但是請考慮為 Amazon S3 事件來源新增 SourceAccount 屬性。這樣可防止使用者重新建立您刪除的儲存貯體,然後授予新儲存貯體所有者完整權限來調用 Lambda 函數。
解決方法
您可以使用 Fn::Sub 內在函數搭配堆疊參數來避免循環相依性。您也可以使用 Fn::Join 來合併字串。
在下列範例範本中,S3 儲存貯體名稱儲存貯體 BucketPrefix 是 AWS::S3::Bucket 和 AWS::Lambda::Permission 資源的參數。
**注意:**下列範例假設儲存貯體名稱先前未用於您的 AWS 帳戶。如果您想要重複使用含有此程式碼片段的範本,則每次都必須提供不同的儲存貯體前綴。
{ "AWSTemplateFormatVersion": "2010-09-09", "Parameters": { "BucketPrefix": { "Type": "String", "Default": "test-bucket-name" } }, "Resources": { "EncryptionServiceBucket": { "DependsOn": "LambdaInvokePermission", "Type": "AWS::S3::Bucket", "Properties": { "BucketName": { "Fn::Sub": "${BucketPrefix}-encryption-service" }, "NotificationConfiguration": { "LambdaConfigurations": [ { "Function": { "Fn::GetAtt": [ "AppendItemToListFunction", "Arn" ] }, "Event": "s3:ObjectCreated:*", "Filter": { "S3Key": { "Rules": [ { "Name": "suffix", "Value": "zip" } ] } } } ] } } }, "LambdaInvokePermission": { "Type": "AWS::Lambda::Permission", "Properties": { "FunctionName": { "Fn::GetAtt": [ "AppendItemToListFunction", "Arn" ] }, "Action": "lambda:InvokeFunction", "Principal": "s3.amazonaws.com", "SourceAccount": { "Ref": "AWS::AccountId" }, "SourceArn": { "Fn::Sub": "arn:aws:s3:::${BucketPrefix}-encryption-service" } } }, "AppendItemToListFunction": { "Type": "AWS::Lambda::Function", "Properties": { "Handler": "index.handler", "Role": { "Fn::GetAtt": [ "LambdaExecutionRole", "Arn" ] }, "Code": { "ZipFile": { "Fn::Join": [ "", [ "var response = require('cfn-response');", "exports.handler = function(event, context) {", " var responseData = {Value: event.ResourceProperties.List};", " responseData.Value.push(event.ResourceProperties.AppendedItem);", " response.send(event, context, response.SUCCESS, responseData);", "};" ] ] } }, "Runtime": "nodejs12.x" } }, "LambdaExecutionRole": { "Type": "AWS::IAM::Role", "Properties": { "AssumeRolePolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Principal": { "Service": [ "lambda.amazonaws.com" ] }, "Action": [ "sts:AssumeRole" ] } ] }, "Path": "/", "Policies": [ { "PolicyName": "root", "PolicyDocument": { "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "logs:*" ], "Resource": "arn:aws:logs:*:*:*" } ] } } ] } } } }
該範本可避免循環相依性,因為它會按照以下順序建立資源:
- 建立 AWS Identity and Access Management (IAM) 角色
- Lambda 函數
- Lambda 權限
- S3 儲存貯體
現在,Amazon S3 可以驗證其通知組態並建立儲存貯體,而不會出現任何問題。
您也可以嘗試以下解決方案:
- 在沒有通知設定的情況下建立 S3 儲存貯體,然後在下一次堆疊更新中新增儲存貯體。
- 建立不受限制的 Lambda 權限。例如,透過省略 SourceArn,允許針對特定 AWS 帳戶調用。
- 建立要在堆疊工作流程結束時執行的自訂資源。此資源會在建立所有其他資源後,將通知組態新增至 S3 儲存貯體。
相關資訊
如何避免 AWS CloudFormation 中出現「無法驗證以下目的地組態」錯誤?
相關內容
- 已提問 2 個月前lg...
- 已提問 2 年前lg...
- 已提問 1 年前lg...
- AWS 官方已更新 2 個月前
- AWS 官方已更新 1 個月前
- AWS 官方已更新 9 個月前