¿Cómo puedo evitar el error «Unable to validate the following destination configurations» con las notificaciones de eventos de Lambda en CloudFormation?
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:
- Un recurso de función de AWS Lambda
- Un recurso de bucket de Amazon Simple Storage Service (Amazon S3) con una propiedad NotificationConfiguration que haga referencia a la función de Lambda
- Un recurso de permisos de Lambda con las propiedades FunctionName y SourceArn que coincidan con la función de Lambda y el bucket de S3
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:
- Rol de AWS Identity and Access Management (AWS IAM)
- Función de Lambda
- Permisos de Lambda
- 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
Contenido relevante
- OFICIAL DE AWSActualizada hace 4 años
- OFICIAL DE AWSActualizada hace 5 meses
- OFICIAL DE AWSActualizada hace 5 meses
- OFICIAL DE AWSActualizada hace 8 meses