Salta al contenuto

Come posso risolvere l'errore che ricevo quando sottoscrivo un'origine di eventi di tipo push per una funzione Lambda in CloudFormation?

3 minuti di lettura
0

Non riesco a sottoscrivere una notifica degli eventi Amazon Simple Storage Service (Amazon S3) o un topic Amazon Simple Notification Service (Amazon SNS) per la mia funzione AWS Lambda nel mio stack di AWS CloudFormation.

Breve descrizione

Se effettui la sottoscrizione per la funzione Lambda utilizzando la risorsa AWS::Lambda::EventSourceMapping, potresti ricevere il seguente errore: "Unrecognized event source, must be kinesis or dynamodb stream."

Questa risorsa è progettata per origini di eventi di tipo pull, come i flussi di eventi Amazon DynamoDB e Amazon Kinesis. Quando utilizzi origini di eventi di tipo push, come le notifiche degli eventi Amazon S3 o i messaggi di Amazon SNS, l'origine dell'evento invoca la funzione Lambda. Affinché un'origine di eventi di tipo push invochi una funzione Lambda, la policy delle risorse della funzione deve autorizzare un servizio in grado di invocare funzioni Lambda.

Risoluzione

Nel modello in CloudFormation, aggiungi una policy basata sulle risorse con la risorsa AWS::Lambda::Permission.

Ad esempio, la seguente policy basata sulle risorse consente a un topic Amazon SNS di invocare una funzione Lambda:

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

Per l'origine di eventi di un topic Amazon SNS, devi definire una policy del topic con le autorizzazioni richieste.

Per un'origine di eventi Amazon S3, devi disporre di un'istruzione di configurazione delle notifiche che effettui la sottoscrizione al bucket Amazon S3 per la funzione Lambda. Ad esempio:

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

In questo esempio, il bucket S3 e la configurazione delle notifiche vengono creati contemporaneamente. L'esempio evita una dipendenza circolare tramite la funzione intrinseca Fn::GetAtt e l'attributo DependsOn per creare le risorse.

Nota: Quando l'attributo DependsOn non è specificato, CloudFormation crea contemporaneamente il bucket S3 e le risorse di autorizzazione di Lambda.

Le risorse vengono create nel seguente ordine:

  • Ruolo AWS Identity and Access Management (AWS IAM)
  • Funzione lambda
  • Autorizzazione Lambda
  • Bucket S3

Per ulteriori informazioni, consulta Come faccio a correggere l'errore in CloudFormation?"Unable to validate the following destination configurations"

Informazioni correlate

Best practice per CloudFormation

Gestione delle autorizzazioni in AWS Lambda

Comprendi i comportamenti di aggiornamento delle risorse dello stack

AWS UFFICIALEAggiornata un anno fa