My application flow starts off with SES depositing an email in S3. My Lambda reads the object, parses out the relevant data, and writes to Dynamo. After the DB write, I’m attempting to copy the object to a different directory in the same bucket. Everything works up until the copy stage.
When attempting to copy I get the following error:
ERROR Invoke Error
{
“errorType”: “AccessDenied”,
“errorMessage”: “Access Denied”,
“code”: “AccessDenied”,
“message”: “Access Denied”,
“region”: null,
“time”: “2021-01-03T04:12:02.789Z”,
“requestId”: “9749B812CDC3E663”,
“extendedRequestId”: “dQPDfERl2+MN6Etf3xEhTq9dfRl90HPUHxBSXKNcV0Vi0pFY1AFcN/6lEPtepwj+IIxeVJcLLXU=”,
“statusCode”: 403,
“retryable”: false,
“retryDelay”: 40.07320833958672,
“stack”: [
“AccessDenied: Access Denied”,
" at Request.extractError (/var/task/node_modules/aws-sdk/lib/services/s3.js:700:35)",
" at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:106:20)",
" at Request.emit (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:78:10)",
" at Request.emit (/var/task/node_modules/aws-sdk/lib/request.js:688:14)",
" at Request.transition (/var/task/node_modules/aws-sdk/lib/request.js:22:10)",
" at AcceptorStateMachine.runTo (/var/task/node_modules/aws-sdk/lib/state_machine.js:14:12)",
" at /var/task/node_modules/aws-sdk/lib/state_machine.js:26:10",
" at Request. (/var/task/node_modules/aws-sdk/lib/request.js:38:9)",
" at Request. (/var/task/node_modules/aws-sdk/lib/request.js:690:12)",
" at Request.callListeners (/var/task/node_modules/aws-sdk/lib/sequential_executor.js:116:18)"
]
}
The relevant parts of my serverless.yml:
service: my-email-filter
provider:
name: aws
runtime: nodejs12.x
stage: ${opt:stage, 'dev'}
region: ${opt:region, 'us-west-2'}
s3:
emailRepositoryBucket:
bucketName: my-email-repository-${self:provider.stage}
accessControl: BucketOwnerFullControl
bucketEncryption:
ServerSideEncryptionConfiguration:
- ServerSideEncryptionByDefault:
SSEAlgorithm: AES256
corsConfiguration:
CorsRules:
-
AllowedOrigins:
- '*'
AllowedHeaders:
- '*'
AllowedMethods:
- GET
- PUT
- POST
- DELETE
- HEAD
environment:
STAGE: ${self:provider.stage}
REGION: ${self:provider.region}
EMAIL_BUCKET: busquo-email-repository-${self:provider.stage}
iamRoleStatements:
-
Effect: Allow
Action:
- s3:*
Resource: arn:aws:s3:::my-email-repository-${self:provider.stage}/*
-
Effect: Allow
Action:
- s3:*
Resource: arn:aws:s3:::my-email-repository-${self:provider.stage}
functions:
ProcessEmailEvent:
handler: handlers/handler.process
name: process-email-event-${self:provider.stage}
events:
- s3:
bucket: my-email-repository-${self:provider.stage}
event: s3:ObjectCreated:*
rules:
- prefix: inbound/
resources:
Resources:
EmailRepositoryBucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: 'my-email-repository-${self:provider.stage}'
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: AllowSESPuts
Effect: Allow
Principal:
Service: ses.amazonaws.com
Action:
- s3:PutObject
Resource: arn:aws:s3:::my-email-repository-${self:provider.stage}/*
Condition:
StringEquals:
aws:Referer: !Ref AWS::AccountId
- Sid: AllowLambdaAccess
Effect: Allow
Principal:
AWS: <MY LAMBDA EXECUTION ROLE ARN>
Action:
- s3:*
Resource:
- 'arn:aws:s3:::my-email-repository-${self:provider.stage}/*'
- 'arn:aws:s3:::my-email-repository-${self:provider.stage}'
*NOTE: I’ve tried using the lambda service instead of my role ARN with the same error.
I’m invoking my function in my handler like this:
var AWS = require(‘aws-sdk’);
AWS.config.update({ region: process.env.REGION });
var s3 = new AWS.S3({ apiVersion: ‘2006-03-01’, region: process.env.REGION });
let copyParams = {
Bucket: EmailRepositoryBucket, // These values look like they're being set correctly
CopySource: copySource,
Key: objectKey
};
await s3.copyItem(copyParams).promise().then((data) => {
// Copy succeeds. Do more work...
}).catch((error) => {
console.log(error);
throw error;
});
My lambda role looks like it has the right permissions. I’m not sure how to debug this issue. Any help is appreciated.