Como posso resolver o erro que recebo ao assinar uma função do AWS Lambda em uma fonte de eventos baseada em push no AWS CloudFormation?

4 minuto de leitura
0

Não consigo inscrever minha função do AWS Lambda em uma notificação de evento do Amazon Simple Storage Service (Amazon S3) ou em um tópico do Amazon Simple Notification Service (Amazon SNS) na minha pilha do AWS CloudFormation. Se eu uso o recurso AWS::Lambda::EventSourceMapping, recebo o seguinte erro: “Fonte de eventos não reconhecida, deve ser kinesis ou dynamodb stream”.

Breve descrição

O recurso AWS::Lambda::EventSourceMapping foi projetado para fontes de eventos baseadas em pull, como streams de eventos do Amazon DynamoDB e do Amazon Kinesis. Com fontes de eventos baseadas em push, como notificações de eventos do Amazon S3 ou mensagens do Amazon SNS, a fonte do evento é responsável por invocar a função do Lambda. Para que uma fonte de evento push invoque uma função do Lambda, a política de recursos da função deve autorizar uma fonte de evento compatível.

Resolução

Em seu modelo do AWS CloudFormation, adicione uma política baseada em recursos usando o recurso AWS::Lambda::Permission.

Por exemplo, a seguinte política baseada em recursos permite que um tópico do Amazon SNS invoque uma função do Lambda:

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

Para uma fonte de evento de tópico do Amazon SNS, você deve definir uma política de tópico com as permissões necessárias.

Para uma fonte de eventos do Amazon S3, você deve ter uma declaração de configuração de notificação que inscreva a função do Lambda no bucket do Amazon S3. Por exemplo:

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

No exemplo anterior, o bucket do S3 e a configuração de notificação são criados ao mesmo tempo. O exemplo evita uma dependência circular usando a função intrínseca Fn :Join e o atributo DependsOn para criar os recursos na seguinte ordem: 1) perfil do IAM, 2) função do Lambda, 3) permissão do Lambda e, em seguida, 4) bucket do S3. Para mais informações, consulte How do I avoid the "Unable to validate the following destination configurations" error with Lambda event notifications in AWS CloudFormation? (Como evito o erro “Não é possível validar as seguintes configurações de destino” com as notificações de eventos do Lambda no AWS CloudFormation?)


Informações relacionadas

Melhores práticas do CloudFormation

Permissões do Lambda

Atualizar comportamentos dos recursos da pilha

AWS OFICIAL
AWS OFICIALAtualizada há 4 anos