使用 Serverless 时如何解决“Error validating stack policy”"Unsupported action"?

How to solve “Error validating stack policy" "Unsupported action" when using Serverless?

我正在尝试编写无服务器脚本来创建具有 S3 权限的 AWS lambda 函数。

但是,我得到 Error validating stack policy to be applied after stack update: Unsupported action 'lambda:InvokeFunction' in statement {}

这是我的 serverless.yml 目前的片段:

    service: {{lambda_function_name}}
    # You can pin your service to only deploy with a specific Serverless version
    # frameworkVersion: "=X.X.X"

    provider:
      name: aws
      runtime: nodejs8.10
      role: {{&roleArn}}
      stage: {{stage}}
      region: {{region}}
      vpc:
        securityGroupIds:
          - {{securityGroupId1}}
        subnetIds:
          - {{subnetId1}}
          - {{subnetId2}}
      stackPolicy:
        - Effect: Allow
          Principal:
            Service: "s3.amazonaws.com"
          Action: "lambda:InvokeFunction"
          Condition:
            ArnLike:
              AWS:SourceArn:
                - "arn:aws:s3:::{{bucket}}"

    package:
      include:
        - app.js
        - node_modules/**
        - src/**
        - bin/**
        - tests/** 

请注意,花括号内的值是环境变量。

一切正常,直到我尝试添加权限。这里出了什么问题?

我的解决方案是创建一个资源。

https://serverless.com/framework/docs/providers/aws/events/s3/

针对我的反对票,我想我会给出进一步的解释。

对于无服务器,您可以使用纯 Cloudformation。我创建了一个自定义资源来向我的 S3 存储桶添加所需的权限。

# resource to add S3 lambdainvoke permissions
resources:
  Resources:
    # Cloudformation key, can be called anything.
    LambdaPermission:
      Type: "AWS::Lambda::Permission"
      Properties:
        FunctionName:
          "Fn::GetAtt": # grabs function arn
            - AppLambdaFunction
            - Arn
        Principal: "s3.amazonaws.com"
        Action: "lambda:InvokeFunction"
        SourceAccount:
          Ref: AWS::AccountId
        SourceArn: "arn:aws:s3:::bucket-name"

我希望这对遇到与我相同问题的任何人有所帮助。

至于添加触发器,只能通过 Cloudformation 在尚不存在的存储桶上完成。

我的解决方法是在我的部署中简单地使用 AWS CLI 在现有 S3 存储桶上添加触发器。

有一个名为 serverless-plugin-existing-s3 的无服务器插件,旨在允许向现有 S3 存储桶添加触发器,但我发现了此插件的错误。这就是为什么我会坚持使用 CLI 来添加触发器。

https://github.com/matt-filion/serverless-external-s3-event

我终于设法做到了以下几点:

  1. 创建 Lambda 函数
  2. 创建 S3 存储桶
  3. 允许 Lambda 函数写入 S3 存储桶

这是 serverless.yml 的摘录:

provider:
  iamRoleStatements:
   - Effect: "Allow"
     Action:
      - "s3:PutObject"
      - "s3:GetObject"
     Resource:
      Fn::Join:
        - ""
        - - Fn::GetAtt:
            - S3BucketMyBucket
            - Arn
          - "/*"

resources:
  Resources:
    S3BucketMyBucket:
      Type: AWS::S3::Bucket
      Properties:
        BucketName: ${self:custom.cfg.s3BucketName}

functions:
  process:
    handler: handler.process
    events:
      - s3:
        bucket: ${self:custom.dre.s3BucketName}
        event: s3:ObjectCreated:*

custom:
  cfg:
    s3BucketName: "mybucket-${opt:stage}"

关键是,通过将 /functions/process/events/s3 拆分为多个字段(bucketevent),它不会尝试创建 S3 存储桶。当它全部列在一行(没有事件)时,它会尝试创建存储桶,但您最终会遇到命名冲突,因为它会尝试创建两个具有相同名称的存储桶(一个来自 /functions,一个来自 /resources).