Wie vermeide ich den Fehler „Unable to validate the following destination configurations“ bei Lambda-Ereignisbenachrichtigungen in CloudFormation?

Lesedauer: 4 Minute
0

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:

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:

  1. Rolle für AWS Identity and Access Management (IAM)
  2. Lambda-Funktion
  3. Lambda-Berechtigung
  4. 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

How do I avoid the "Unable to validate the following destination configurations" error in AWS CloudFormation?

Verwenden von AWS Lambda mit Amazon S3

Ref

Fn::GetAtt

AWS OFFICIAL
AWS OFFICIALAktualisiert vor 3 Jahren