I'm trying to set a lambda to trigger when an object is created in an S3 bucket.
My serverless.yml includes this:
handleNewRawObjectInS3:
handler: lambdas/handleNewRawObjectInS3/handleNewRawObjectInS3.handleS3Event
events:
- s3:
bucket: ${file(../evn.${opt:stage, 'dev'}.json):RAW_IMAGE_BUCKET}
event: s3:ObjectCreated:*
This results in an error:
Error:
CREATE_FAILED: S3Bucketxxxxxxxxxrawimages (AWS::S3::Bucket)
xxxxxxxxx-raw-images already exists in stack arn:aws:cloudformation:us-east-1:xxxx:stack/s3-xxxxxxxxx-raw-images/310e7010-xxx-xxx-xxxx-12f066874c93
I already have the bucket created -- created via uploading a cloudformation template directly (our corporate version of AWS doesn't allow us to use serverless framework to create a bucket). How to add S3 trigger event on AWS Lambda function using Serverless framework? indicates this was not possible with older versions of serverless, but following the rabbit hole, you can see a feature request ... and later an answer that shows you need to add 'existing: true'.
So I add that to my serverless framework setup:
service: my-service-events
provider:
name: aws
runtime: nodejs14.x
region: ${file(../evn.${opt:stage, 'dev'}.json):REGION}
stage: ${opt:stage, 'dev'}
deploymentBucket: #must name manually-created bucket for deployment because enterprise doesn't allow automated bucket creation
name: ${file(../evn.${opt:stage, 'dev'}.json):DEPLOYMENT_BUCKET}
iam: #must name a role because enterprise doesn't allow automated role creation
role: myServerlessRole # This is a reference to the resource name from the role created in the resources -> iam roles section
deploymentRole: ${file(../evn.${opt:stage, 'dev'}.json):DEPLOYMENT_ROLE}
resources:
- ${file(../iam-roles.${opt:stage, 'dev'}.yml)}
functions:
handleNewRawObjectInS3:
handler: lambdas/handleNewRawObjectInS3/handleNewRawObjectInS3.handleS3Event
events:
- s3:
bucket: ${file(../evn.${opt:stage, 'dev'}.json):RAW_IMAGE_BUCKET}
event: s3:ObjectCreated:*
existing: true
The IAM file/role referenced above looks like this:
Resources:
myServerlessRole:
Type: AWS::IAM::Role
Properties:
PermissionsBoundary: arn:aws:iam::xxx:policy/csr-Developer-Permissions-Boundary
Path: /my/default/path/
RoleName: myServerlessRole-${self:service}
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service:
- lambda.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole
Policies:
- PolicyName: myPolicyName
PolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
Resource:
- 'Fn::Join':
- ':'
-
- 'arn:aws:logs'
- Ref: 'AWS::Region'
- Ref: 'AWS::AccountId'
- 'log-group:/aws/lambda/*:*:*'
- Effect: "Allow"
Action:
- "s3:*"
Resource: "arn:aws:s3:::*" #
- Effect: "Allow"
Action:
- "lambda:*"
Resource: "*"
- Effect: "Allow"
Action:
- cloudfront:CreateDistribution
- cloudfront:GetDistribution
- cloudfront:UpdateDistribution
- cloudfront:DeleteDistribution
- cloudfront:TagResource
Resource: "arn:aws:cloudfront:::*"
Trying to deploy this gets me the error:
Error:
CREATE_FAILED: CustomDashresourceDashexistingDashs3LambdaFunction (AWS::Lambda::Function)
Resource handler returned message: "The role defined for the function cannot be assumed by Lambda. (Service: Lambda, Status Code: 400, Request ID: 812c5384-1c26-42c9-bdef-1ce4a59f2be4)" (RequestToken: 9cdbb5af-3bc7-d6bf-384b-5126d1048ccd, HandlerErrorCode: InvalidRequest)
How can I deploy this lambda triggered by an s3 event?
The issue comes from the fact that CustomDashresourceDashexistingDashs3LambdaFunction lambda runs as the deployementRole
and not under the defined role
(which is the default role that lambdas run under). Given the deployment role doesn't normally need to assumeRole
my deployment role did not have the assumeRole permission.
The fix for this is to ensure that the sts:assumeRole
trust relationship has been applied to the deploymentRole
like so:
{
"Effect": "Allow",
"Principal": {
"Service": "lambda.amazonaws.com"
},
"Action": "sts:AssumeRole"
}