Wie vermeide ich den Fehler „Unable to validate the following destination configurations“ bei Lambda-Ereignisbenachrichtigungen in CloudFormation?
Mein Stack schlägt fehl, wenn ich eine AWS-CloudFormation-Vorlage bereitstelle. Dann erhalte ich eine Fehlermeldung wie die folgende: „Unable to validate the following destination configurations.“
Kurzbeschreibung
Dieser Fehler wird angezeigt, wenn Sie eine CloudFormation-Vorlage mit den folgenden Ressourcen bereitstellen:
- Eine AWS-Lambda-Funktions-Ressource
- Eine Amazon Simple Storage Service (Amazon S3)-Bucket-Ressource mit einer Eigenschaft NotificationConfiguration, die auf die Lambda-Funktion verweist
- Eine Lambda-Berechtigungs-Ressource mit den Eigenschaften FunctionName und SourceArn, die der Lambda-Funktion und dem S3-Bucket entsprechen
Amazon S3 muss die Benachrichtigungskonfiguration validieren, wenn es den Bucket erstellt. Die Validierung erfolgt, indem überprüft wird, ob der Bucket berechtigt ist, Ereignisse per Push an die Lambda-Funktion zu übertragen. Die Berechtigungsressource (die vorhanden sein muss, damit diese Prüfung erfolgreich ist) benötigt den Bucket-Namen. Das bedeutet, dass die Berechtigungsressource vom Bucket und der Bucket von der Berechtigungsressource abhängt.
Hinweis: Sie erhalten den Fehler „Circular dependency between resources“, wenn Sie versuchen, dieses Problem zu lösen, indem Sie ähnlich wie im folgenden Codebeispiel ein DependsOn-Ressourcenattribut implementieren.
Das folgende Beispiel zeigt eine zirkuläre Abhängigkeit zwischen der S3-Bucket-Ressource und der SourceArn-Eigenschaft der Lambda-Berechtigungsressource.
"Resources": { "MyS3BucketPermission": { "Type": "AWS::Lambda::Permission", "Properties": { "Action": "lambda:InvokeFunction", ... ... "SourceArn": { "Ref": "MyS3Bucket" } } }, "MyS3Bucket": { "DependsOn" : "MyS3BucketPermission", ... ...
Wichtig: Es hat sich bewährt, die Eigenschaft SourceAccount zur Lambda-Berechtigungsressource für Amazon-S3-Ereignisquellen hinzuzufügen. Grund dafür ist, dass ein Amazon-Ressourcenname (ARN) für Amazon S3 keine Konto-ID enthält. Die SourceArn-Eigenschaft ist für die meisten anderen Ereignisquellen ausreichend. Erwägen Sie jedoch, für Amazon S3-Ereignisquellen die Eigenschaft SourceAccount hinzuzufügen. Dadurch wird verhindert, dass Benutzer einen von Ihnen gelöschten Bucket erneut erstellen und dann einem neuen Bucket-Besitzer volle Berechtigungen zum Aufrufen Ihrer Lambda-Funktion gewähren.
Lösung
Sie können zirkuläre Abhängigkeiten vermeiden, indem Sie die intrinsische Funktion Fn::Sub mit Stack-Parametern verwenden. Außerdem können Sie Fn::Join verwenden, um Zeichenketten zu kombinieren.
In der folgenden Beispielvorlage ist der S3-Bucket-Name BucketPrefix ein Parameter für die Ressourcen AWS::S3::Bucket und AWS::Lambda::Permission.
Hinweis: Folgendes Beispiel geht davon aus, dass der Bucket-Name zuvor nicht mit Ihren AWS-Konten verwendet wurde. Wenn Sie eine Vorlage mit diesem Codeausschnitt wiederverwenden möchten, müssen Sie jedes Mal ein anderes Bucket-Präfix angeben.
{ "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:*:*:*" } ] } } ] } } } }
Die Vorlage vermeidet eine zirkuläre Abhängigkeit, indem sie die Ressourcen in der folgenden Reihenfolge erstellt:
- Rolle für AWS Identity and Access Management (IAM)
- Lambda-Funktion
- Lambda-Berechtigung
- S3-Bucket
Nun kann Amazon S3 seine Benachrichtigungskonfiguration überprüfen und den Bucket problemlos erstellen.
Sie können auch die folgenden Lösungen ausprobieren:
- Erstellen Sie den S3-Bucket ohne Benachrichtigungskonfiguration und fügen Sie ihn dann im nächsten Stack-Update hinzu.
- Erstellen Sie eine weniger eingeschränkte Lambda-Berechtigung. Erlauben Sie beispielsweise Aufrufe für ein bestimmtes AWS-Konto, indem Sie SourceArn weglassen.
- Erstellen Sie eine benutzerdefinierte Ressource, die am Ende des Stack-Workflows ausgeführt wird. Diese Ressource fügt die Benachrichtigungskonfiguration zum S3-Bucket hinzu, nachdem alle anderen Ressourcen erstellt wurden.
Ähnliche Informationen
Relevanter Inhalt
- AWS OFFICIALAktualisiert vor 3 Monaten
- AWS OFFICIALAktualisiert vor einem Jahr