S3 Policy to Allow Lambda
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.
Introduction
For an AWS Lambda function to read from or write to an S3 bucket, two things must be configured: the Lambda function's execution role must have an IAM policy granting S3 permissions, and (optionally) the S3 bucket policy can explicitly allow the Lambda role. The execution role policy is the primary and required mechanism. A bucket policy is needed only if the bucket is in a different AWS account or has restrictive access controls.
Lambda Execution Role Policy
The Lambda execution role is an IAM role attached to the function. Add S3 permissions to this role:
s3:GetObject/PutObject/DeleteObjectapply to objects (my-bucket/*)s3:ListBucketapplies to the bucket itself (my-bucket, no/*)
Creating the Role with AWS CLI
S3 Bucket Policy (Cross-Account or Restrictive Buckets)
If the S3 bucket is in a different account or has a restrictive bucket policy, add an explicit allow:
Replace 123456789012 with the AWS account ID that owns the Lambda function.
CloudFormation / SAM Template
SAM provides shorthand policy templates (S3ReadPolicy, S3CrudPolicy) that generate the correct IAM statements automatically.
Terraform Example
S3 Event Trigger (Lambda Invocation from S3)
To trigger Lambda when an object is uploaded to S3, you also need a resource-based policy on the Lambda function:
Then configure the S3 event notification:
Lambda Function Example
Common Pitfalls
- Using
s3:*as the action: This grants full S3 access including deleting buckets and modifying policies. Always use the minimum actions needed (GetObject,PutObject,ListBucket). Follow the principle of least privilege. - Wrong Resource ARN format:
s3:ListBucketrequires the bucket ARN (arn:aws:s3:::my-bucket), whiles3:GetObjectrequires the object ARN (arn:aws:s3:::my-bucket/*). Mixing these up causesAccessDeniederrors that are hard to diagnose. - Forgetting the Lambda invocation permission for S3 triggers: The execution role controls what Lambda can access. A separate resource-based policy (
lambda:InvokeFunction) controls what can trigger Lambda. S3 needs both. - Cross-account buckets without a bucket policy: The execution role alone is not sufficient for cross-account access. The target bucket must have a bucket policy that explicitly allows the Lambda role from the other account.
- Not including CloudWatch Logs permissions: Without
AWSLambdaBasicExecutionRole(or equivalent), Lambda cannot write logs. Debugging permission issues becomes impossible without logs.
Summary
- Attach S3 permissions to the Lambda execution role — this is the primary access mechanism
- Use specific actions (
s3:GetObject,s3:PutObject) instead ofs3:* s3:ListBuckettargets the bucket ARN; object actions targetbucket/*- Add a bucket policy only for cross-account access or restrictive bucket configurations
- For S3-triggered Lambda, add both the execution role policy and a resource-based invocation permission
- Use SAM/CloudFormation policy templates (
S3ReadPolicy,S3CrudPolicy) for managed, least-privilege policies
Related reading

System Design Fundamentals
Build a strong foundation in designing scalable, reliable distributed systems.
View the courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
System Design practice on Codemia
Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.