¿Cómo puedo evitar el error «Unable to validate the following destination configurations» con las notificaciones de eventos de Lambda en CloudFormation?

5 minutos de lectura
0

Se produce un error en mi pila cuando implemento una plantilla de AWS CloudFormation. A continuación, recibo un mensaje de error similar al siguiente: «Unable to validate the following destination configurations».

Breve descripción

Aparece este error al implementar una plantilla de CloudFormation con los siguientes recursos:

Amazon S3 debe validar la configuración de notificaciones al crear el bucket. La validación se realiza comprobando si el bucket tiene permiso para enviar eventos a la función de Lambda. El recurso de permisos (que debe existir para que se realice esta comprobación) requiere el nombre del bucket. Esto significa que el recurso de permisos depende del bucket y el bucket depende del recurso de permisos.

Nota: Aparecerá el error «Circular dependency between resources» si intenta resolver este problema implementando un atributo de recurso DependsOn similar al siguiente ejemplo de código.

El siguiente ejemplo muestra una dependencia circular entre el recurso de bucket de S3 y la propiedad SourceArn del recurso de permisos de Lambda.

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

Importante: Se recomienda añadir la propiedad SourceAccount al recurso de permisos de Lambda para los orígenes de eventos de Amazon S3. Se añade la propiedad porque el nombre de recurso de Amazon (ARN) para Amazon S3 no incluye un identificador de cuenta. La propiedad SourceArn es adecuada para la mayoría de los demás orígenes de eventos, pero considere añadir la propiedad SourceAccount para los orígenes de eventos de Amazon S3. Esto impide que los usuarios vuelvan a crear un bucket que haya eliminado y concedan todos los permisos al nuevo propietario del bucket para invocar su función de Lambda.

Resolución

Puede evitar las dependencias circulares utilizando la función intrínseca Fn::Sub con parámetros de pila. También puede usar Fn::Join para combinar cadenas.

En la siguiente plantilla de ejemplo, el nombre del bucket de S3 BucketPrefix es un parámetro para los recursos AWS::S3::Bucket y AWS::Lambda::Permission.

Nota: En el siguiente ejemplo, se supone que el nombre del bucket no se usó anteriormente en sus cuentas de AWS. Si quiere reutilizar una plantilla con este fragmento de código, debe proporcionar un prefijo de bucket diferente cada vez.

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

La plantilla evita una dependencia circular porque crea los recursos en el siguiente orden:

  1. Rol de AWS Identity and Access Management (AWS IAM)
  2. Función de Lambda
  3. Permisos de Lambda
  4. Bucket de S3

Ahora, Amazon S3 puede verificar su configuración de notificaciones y crear el bucket sin problemas.

También puede probar las siguientes resoluciones:

  • Cree el bucket de S3 sin configuración de notificaciones y añada el bucket en la siguiente actualización de la pila.
  • Cree un permiso de Lambda con menos restricciones. Por ejemplo, permita las invocaciones para una cuenta de AWS específica omitiendo SourceArn.
  • Cree un recurso personalizado para ejecutarlo al final del flujo de trabajo de la pila. Este recurso añade la configuración de notificaciones al bucket de S3 después de crear todos los demás recursos.

Información relacionada

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

Uso de AWS Lambda con Amazon S3

Ref

Fn::GetAtt

OFICIAL DE AWS
OFICIAL DE AWSActualizada hace 3 años