我正试图编写一个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.comframeworkdocsprovidersawseventss3。
针对我的反对票,我想我会做进一步的解释。
使用serverless,你可以使用纯粹的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 bucket 上添加触发器。
有一个叫serverless-plugin-existing-s3的serverless插件,它的设计是为了允许在现有的S3 bucket上添加触发器,但我发现这个插件有一些错误。这就是为什么我将坚持使用CLI来添加触发器。
我终于成功地让这个函数实现了以下功能。
这里是 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
变成多个字段(bucket
和 event
),那么它就不会尝试创建S3 bucket。 当所有的内容都列在一行(没有事件)时,它就会尝试创建 bucket,而你最终会遇到命名冲突,因为它试图创建两个名称相同的 bucket(一个来自于 /functions
和一个来自 /resources
).