¿Cómo puedo resolver el error que recibo al suscribir una función de AWS Lambda a un origen de eventos push en AWS CloudFormation?

3 minutos de lectura
0

No puedo suscribir mi función de AWS Lambda a una notificación de eventos de Amazon Simple Storage Service (Amazon S3) o a un tema de Amazon Simple Notification Service (Amazon SNS) de mi pila de AWS CloudFormation. Si utilizo el recurso AWS::Lambda::EventSourceMapping, recibo el siguiente error: «Origen de eventos no reconocido, debe ser kinesis o dynamodb stream».

Descripción breve

El recurso AWS::Lambda::EventSourceMapping está diseñado para orígenes de eventos pull, como las transmisiones de eventos de Amazon DynamoDB y Amazon Kinesis. En el caso de los orígenes de eventos push, como las notificaciones de eventos de Amazon S3 o los mensajes de Amazon SNS, el origen de eventos es responsable de invocar a la función de Lambda. Para que un origen de eventos push invoque a una función de Lambda, la política de recursos de la función debe autorizar un origen de eventos compatible.

Resolución

En su plantilla de AWS CloudFormation, añada una política basada en recursos mediante el recurso AWS::Lambda::Permission.

Por ejemplo, la siguiente política basada en recursos permite que un tema de Amazon SNS invoque a una función de Lambda:

"LambdaResourcePolicy": {
  "Type": "AWS::Lambda::Permission",
  "Properties": {
    "FunctionName" : { "Ref" : "MyFunction" },
    "Principal": "sns.amazonaws.com",
    "Action": "lambda:InvokeFunction",
    "SourceArn" : { "Ref" : "MySNSTopic" }
  }
}

Para un origen de eventos de tema de Amazon SNS, debe definir una política de temas con los permisos necesarios.

Para un origen de eventos de Amazon S3, debe tener una sentencia de configuración de notificaciones que suscriba la función de Lambda al bucket de Amazon S3. Por ejemplo:

{
  "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": [
              "",
              [
                "exports.handler = function(event, context) {",
                "console.log('Received event: ', JSON.stringify(event, null, 2));",
                "};"
              ]
            ]
          }
        },
        "Runtime": "nodejs8.10"
      }
    },
    "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:*:*:log-group:/path/<log-group-name>:log-stream:<log-stream-name>"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

En el ejemplo anterior, el bucket de S3 y la configuración de notificaciones se crean al mismo tiempo. El ejemplo evita una dependencia circular mediante el uso de la función intrínseca Fn::Join y el atributo DependsOn para crear los recursos en el siguiente orden: 1) Rol de IAM, 2) función de Lambda, 3) permiso de Lambda y, a continuación, 4) bucket de S3. Para obtener más información, consulte ¿Cómo puedo evitar el error «No se pueden validar las siguientes configuraciones de destino» en las notificaciones de eventos de Lambda en AWS CloudFormation?


Información relacionada

Prácticas recomendadas de CloudFormation

Permisos de Lambda

Actualice los comportamientos de los recursos de la pila

OFICIAL DE AWS
OFICIAL DE AWSActualizada hace 3 años