Como evito o erro “Não é possível validar as seguintes configurações de destino” com as notificações de eventos do Lambda no CloudFormation?

5 minuto de leitura
0

Minha pilha falha quando eu implanto um modelo do AWS CloudFormation. Em seguida, recebo um erro semelhante ao seguinte: “Não é possível validar as seguintes configurações de destino.”

Breve descrição

Você recebe esse erro ao implantar um modelo do CloudFormation com os seguintes recursos:

O Amazon S3 deve validar a configuração de notificação ao criar o bucket. A validação é feita verificando se o bucket tem permissão para enviar eventos para a função Lambda. O recurso de permissão (que deve existir para que essa verificação seja aprovada) requer o nome do bucket. Isso significa que o recurso de permissão depende do bucket, e o bucket depende do recurso de permissão.

Observação: você receberá o erro “Dependência circular entre recursos” se tentar resolver esse problema implementando um atributo de recurso DependsOn semelhante ao exemplo de código a seguir.

O exemplo a seguir mostra uma dependência circular entre o recurso bucket do S3 e a propriedade SourceArn do recurso de permissão do Lambda.

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

Importante: é uma prática recomendada adicionar a propriedade SourceAccount ao recurso de permissão do Lambda para fontes de eventos do Amazon S3. Você adiciona a propriedade porque um nome do recurso da Amazon (ARN) para o Amazon S3 não inclui um ID de conta. A propriedade SourceArn é adequada para a maioria das outras fontes de eventos, mas considere adicionar a propriedade SourceAccount às fontes de eventos do Amazon S3. Isso impede que os usuários recriem um bucket que você excluiu e, em seguida, concedam a um novo proprietário do bucket permissões completas para invocar sua função do Lambda.

Resolução

Você pode evitar dependências circulares usando a função intrínseca Fn::Sub com parâmetros de pilha. Você também pode usar Fn::Join para combinar strings.

No modelo de exemplo a seguir, o nome do bucket S3 BucketPrefix é um parâmetro para os recursos AWS::S3::Bucket e AWS::Lambda::Permission.

Observação: o exemplo a seguir pressupõe que o nome do bucket não foi usado anteriormente com suas contas da AWS. Se quiser reutilizar um modelo com esse trecho de código, forneça sempre um prefixo de bucket diferente.

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

O modelo evita uma dependência circular porque cria os recursos na seguinte ordem:

  1. Perfil do AWS Identity and Access Management (IAM)
  2. Função do Lambda
  3. Permissões do Lambda
  4. Bucket do S3

Agora, o Amazon S3 pode verificar sua configuração de notificação e criar o bucket sem problemas.

Você também pode tentar as seguintes resoluções:

  • Crie o bucket do S3 sem uma configuração de notificação e adicione o bucket na próxima atualização da pilha.
  • Crie uma permissão do Lambda menos restrita. Por exemplo, permita invocações para uma conta específica da AWS omitindo o SourceArn.
  • Crie um recurso personalizado para ser executado no final do fluxo de trabalho da pilha. Esse recurso adiciona a configuração de notificação ao bucket do S3 após a criação de todos os outros recursos.

Informações relacionadas

Como evito o erro “Não é possível validar as seguintes configurações de destino” no AWS CloudFormation?

Usar o AWS Lambda com eventos do Amazon S3

Ref

Fn::GetAtt

AWS OFICIAL
AWS OFICIALAtualizada há 3 anos