I am using AWS Lambda
and serverless
framework to build a service which uses S3
to store a file.
The lambda function (“hello
“) works perfectly when deployed to the cloud (it has an http endpoint, I invoke it from the browser).
On the contrary, when invoked locally (serverless invoke local --function hello
) I get “access denied” error:
{ "errorMessage": "error getting object from S3: AccessDenied: Access Denied", "errorType": "Error", "stackTrace": [ "Error: error getting object from S3: AccessDenied: Access Denied", " at module.exports.hello (/....js:24:9)", " at processTicksAndRejections (internal/process/task_queues.js:93:5)" ] }
This is my simplified function:
'use strict'; const aws = require("aws-sdk"); const s3 = new aws.S3({ region: "eu-west-1" }); const bucket = "my-bucket-dev"; const key = "ads.json"; module.exports.hello = async (event) => { let obj = null; try { return await s3.getObject({ Bucket: bucket, Key: key }).promise(); } catch(err) { throw new Error(`error getting object from S3: ${err}`); } return { statusCode: 200, body: JSON.stringify({ message: `Hello function executed successfully!`, obj, input: event, }, null, 2 ), }; }
This is my serveless.yml (the relevant parts):
service: my-service frameworkVersion: '2' provider: name: aws runtime: nodejs12.x profile: serverless lambdaHashingVersion: 20201221 apiGateway: shouldStartNameWithService: true stage: ${opt:stage, "dev"} region: eu-west-1 iam: role: statements: - Effect: "Allow" Action: - "s3:ListBucket" Resource: { "Fn::Join": [ "", [ "arn:aws:s3:::", "my-service-dev" ] ] } - Effect: "Allow" Action: - "s3:GetObject" - "s3:PutObject" - "s3:DeleteObject" Resource: { "Fn::Join": [ "", [ "arn:aws:s3:::", "my-service-dev", "/*" ] ] } functions: hello: handler: index.hello events: - http: method: get path: hello - s3: my-bucket-dev
I did read somewhere that IAM role statements differ for local and cloud execution, but if it right, I’m a bit confused…
Can anybody clarify?
How should I correct my serverless.yml
to avoid local invocation errors?
Advertisement
Answer
To quote the documentation for invoke-local:
When you use serverless invoke local, the situation is quite different: the role isn’t available (the function is executed on your local machine), so unless you set a different user directly in the code (or via a key pair of environment variables), the AWS SDK will use the default profile specified inside your AWS credential configuration file.
So, for local invocation, either configure local AWS credentials appropriately in ~/.aws/credentials
or provide them via environment variables.