Come faccio a evitare l'errore "Unable to validate the following destination configurations" con le notifiche degli eventi Lambda in CloudFormation?

4 minuti di lettura
0

Il mio stack fallisce quando impiego un modello AWS CloudFormation. Quindi, visualizzo un errore simile al seguente: "Unable to validate the following destination configurations."

Breve descrizione

Visualizzi questo errore quando impieghi un modello CloudFormation con le seguenti risorse:

Amazon S3 deve convalidare la configurazione delle notifiche quando crea il bucket. La convalida viene eseguita controllando se il bucket è autorizzato a inviare eventi alla funzione Lambda. La risorsa di autorizzazione (che deve esistere per il superamento di questo controllo) richiede il nome del bucket. Ciò significa che la risorsa di autorizzazione dipende dal bucket e il bucket dipende dalla risorsa di autorizzazione.

Nota: viene visualizzato l'errore "Circular dependency between resources" se si tenta di risolvere questo problema implementando un attributo di risorsa DependsOn simile al seguente esempio di codice.

L'esempio seguente mostra una dipendenza circolare tra la risorsa bucket S3 e la proprietà SourceArn della risorsa di autorizzazione Lambda.

"Resources": {
  "MyS3BucketPermission": {
    "Type": "AWS::Lambda::Permission",
    "Properties": {
      "Action": "lambda:InvokeFunction",
      ...
      ...
      "SourceArn": {
        "Ref": "MyS3Bucket"
      }
    }
  },
  "MyS3Bucket": {
    "DependsOn" : "MyS3BucketPermission",
    ...
    ...

Importante: è consigliabile aggiungere la proprietà SourceAccount alla risorsa di autorizzazione Lambda per le sorgenti di eventi Amazon S3. Aggiungi la proprietà perché un nome delle risorsa Amazon (ARN) per Amazon S3 non include un ID account. La proprietà SourceArn è adeguata per la maggior parte delle altre fonti di eventi, ma considera l'aggiunta della proprietà SourceAccount per le fonti di eventi di Amazon S3. Ciò impedisce agli utenti di ricreare un bucket che hai eliminato e quindi di concedere a un nuovo proprietario del bucket le autorizzazioni complete per richiamare la tua funzione Lambda.

Risoluzione

È possibile evitare dipendenze circolari utilizzando la funzione intrinseca Fn::Sub con parametri dello stack. Puoi anche usare Fn::Join per combinare le stringhe.

Nel seguente modello di esempio, il nome del bucket S3 BucketPrefix è un parametro per le risorse AWS::S3::Bucket e AWS::Lambda::Permission.

Nota: l'esempio seguente presuppone che il nome del bucket non sia stato utilizzato in precedenza con i tuoi account AWS. Se desideri riutilizzare un modello con questo frammento di codice, devi fornire ogni volta un prefisso bucket diverso.

{
  "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:*:*:*"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

Il modello evita una dipendenza circolare perché crea le risorse nel seguente ordine:

  1. Ruolo AWS Identity and Access Management (IAM)
  2. Funzione lambda
  3. Autorizzazione Lambda
  4. Bucket S3

Ora Amazon S3 può verificare la configurazione delle notifiche e creare il bucket senza problemi.

Puoi anche provare le seguenti risoluzioni:

  • Crea il bucket S3 senza una configurazione di notifica, quindi aggiungi il bucket nel prossimo aggiornamento dello stack.
  • Crea un'autorizzazione Lambda meno vincolata. Ad esempio, consenti le chiamate per un account AWS specifico omettendo SourceArn.
  • Crea una risorsa personalizzata da eseguire alla fine del flusso di lavoro dello stack. Questa risorsa aggiunge la configurazione delle notifiche al bucket S3 dopo la creazione di tutte le altre risorse.

Informazioni correlate

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

Utilizzo di AWS Lambda con Amazon S3 Events

Ref

Fn::GetAtt

AWS UFFICIALE
AWS UFFICIALEAggiornata 3 anni fa