Passer au contenu

Comment résoudre l’erreur que je reçois lorsque j’abonne une fonction Lambda à une source d’événement basée sur la technologie push dans CloudFormation ?

Lecture de 3 minute(s)
0

Je n'arrive pas à abonner ma fonction AWS Lambda à une rubrique de notification d'événement Amazon Simple Storage Service (Amazon S3) ou une rubrique Amazon Simple Notification Service (Amazon SNS) dans ma pile AWS CloudFormation.

Brève description

Si vous utilisez la ressource AWS::Lambda::EventSourceMapping pour abonner votre fonction Lambda, l'erreur suivante peut s'afficher : "Unrecognized event source, must be kinesis or dynamodb stream."

Cette ressource est conçue pour les sources d'événements basées sur des extractions, telles que les flux d'événements Amazon DynamoDB et Amazon Kinesis. Lorsque vous utilisez des sources d'événements basées sur la technologie push, telles que les notifications d'événements Amazon S3 ou les messages Amazon SNS, la source d'événements appelle la fonction Lambda. Pour qu'une source d'événement push invoque une fonction Lambda, la politique de ressources de la fonction doit autoriser un service capable d'invoquer des fonctions Lambda.

Résolution

Dans votre modèle CloudFormation, ajoutez une politique basée sur les ressources avec la ressource AWS::Lambda::Permission.

Par exemple, la politique basée sur les ressources suivante permet à une rubrique Amazon SNS d'invoquer une fonction Lambda :

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

Pour une source d'événements de rubrique Amazon SNS, vous devez définir une stratégie de rubrique dotée des autorisations requises.

Pour une source d'événements Amazon S3, vous devez disposer d'une instruction de configuration des notifications qui abonne la fonction Lambda au compartiment Amazon S3. Exemple :

{  "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": "nodejs20.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:*:*:log-group:/path/<log-group-name>:log-stream:<log-stream-name>"
                }
              ]
            }
          }
        ]
      }
    }
  }
}

Dans cet exemple, le compartiment S3 et la configuration des notifications sont créés en même temps. L'exemple évite une dépendance circulaire grâce à la fonction intrinsèque Fn::GetAtt et à l'attribut DependsOn pour créer les ressources.

Remarque : Lorsque l'attribut DependsOn n'est pas spécifié, CloudFormation crée le compartiment S3 et les ressources d'autorisation Lambda en même temps.

Les ressources sont créées dans l'ordre suivant :

  • Rôle Gestion des identités et des accès AWS (AWS IAM)
  • Fonction Lambda
  • Autorisation Lambda
  • Compartiment S3

Pour plus d'informations, consultez la section Comment corriger l’erreur dans CloudFormation ?"Unable to validate the following destination configurations"

Informations connexes

Bonnes pratiques de CloudFormation

Autorisations d'action de ressource Lambda

Mettre à jour les comportements des ressources de pile

AWS OFFICIELA mis à jour il y a 2 ans