Creating a custom S3 bucket policy with Serverless Framework

Aurelia Fenderson-Peters
2 min readMar 4, 2021

A while back I developed an app for my job that took files uploaded to S3 and uploaded them to an SFTP host. Recently I was asked if we could re-use that app for a service hosted in a different account. After looking at the code, I determined that this was possible, provided we granted access to those accounts. Here’s how I added the custom BucketPolicy. Note that I’ve removed a lot of stuff unrelated to the bucket and BucketPolicy.

service:
name: myService
custom:
s3:
bucket: myBucket
plugins:provider:
name: aws
frameworkVersion: '1.70.0'
runtime: nodejs12.x
region: ${opt:region, 'us-east-1'}
iamRoleStatements:
- Effect: Allow
Action:
- s3:GetObject
- s3:DeleteObject
Resource:
# Specify bucket ARN this way to avoid a "Circular dependency between resources" error
- Fn::Join:
- '/'
- 'arn:aws:s3::'
- Fn::Join:
- '/'
- - ${self:custom.s3.bucket}
- '*'
- Effect: Allow
Action:
- s3:ListObjects
Resource:
# Specify bucket ARN this way to avoid a "Circular dependency between resources" error
- Fn::Join:
- ':'
- - 'arn:aws:s3::'
- ${self:custom.s3.bucket}
# see https://www.serverless.com/framework/docs/providers/aws/events/s3#custom-bucket-configuration
s3:
theBucket:
name: ${self:custom.s3.bucket}
functions:
s3ToSftp:
timeout: 300
memorySize: 1024
handler: src/handler.main
events:
- s3:
bucket: theBucket
resources:
Resources:
BucketPolicy:
Type: AWS::S3::BucketPolicy
Properties:
Bucket: !Ref S3BucketTheBucket
PolicyDocument:
Statement:
- Action:
- s3:ListBucket
- s3:GetObjectVersion
- s3:GetObject
- s3:GetBucketVersioning
- s3:GetBucketLocation
- s3:PutObject
- s3:GetObject
- s3:GetObjectVersion
- s3:GetObjectACL
- s3:PutObjectACL
Resource:
- arn:aws:s3:::${self:custom.s3.bucket}/*
- arn:aws:s3:::${self:custom.s3.bucket}
Effect: Allow
Principal:
AWS:
- arn:aws:iam::123456789012:root
- arn:aws:iam::123456789013:root
- Fn::Join
- ':'
- - 'arn:aws:iam:'
- !Ref 'AWS::AccountId'
- 'root'

One thing to note: the version of the Serverless Framework (see provider.frameworkVersion) is way out of date. This is because the app was developed a year ago. serverless.yml might need some updates to be current.

You may also notice that while we have called our S3 bucket theBucket under provider.s3, we refer to it as S3BucketTheBucket inBucketPolicy. This is because Serverless is going to PascalCase all of the resources it creates (as opposed to those explicitly specified in the Resources section, e.g. BucketPolicy).

So what have we done here? We have granted read and create access to our S3 bucket to AWS accounts 123456789012 and 123456789013, as well as the AWS account that this stack (because ultimately, Serverless produces a CloudFormation stack) is deployed in.

I hope you find this helpful. If so, maybe put a tip in the jar?: https://ko-fi.com/popefelix. If you have any questions, please leave them in the comments below.

--

--

Aurelia Fenderson-Peters

20+ years writing code of various sorts. Full of trans magic.