I tried @mfrankwork’s solution but am getting a cryptic error:
An error occurred: DiyBucket - Unable to validate the following destination configurations (Service: Amazon S3; Status Code: 400; Error Code: InvalidArgument; Request ID: 6516C03FC6506837; S3 Extended Request ID: RD1gHlYOOA+DRL7J8vg1MIf6xnPkDQ28p+lAkZOzgJijzalp/z6i1u1CaXUslLIzrmZ6Y4glYFE=).
My complete serverless.yml:
service: vg-diy-bucket
plugins:
- serverless-dotenv-plugin
provider:
name: aws
stage: ${{opt:stage, 'dev'}}
region: ${{opt:region, 'us-east-1'}}
# use ${{}} to access serverless variables
# this is necessary because cloudformation uses ${} syntax
variableSyntax: "\\${{([ ~:a-zA-Z0-9._\\'\",\\-\\/\\(\\)]+?)}}"
runtime: nodejs8.10
memorySize: 512
custom:
userFolderName: alpha
functions:
transformOnBucketUpload:
handler: dist/transform.onBucketUpload
reservedConcurrency: 100
# events:
# - s3:
# bucket: vg-diy-bucket-dev-diybucket-14aa5jo8lpn0j # fixme
# event: s3:ObjectCreated:*
# # rules:
# # - prefix: input/
# # - suffix: .sketch
# environment:
# sloppy: true
# outputBucketArn:
# Fn::GetAtt: [DiyBucket, Arn]
# iamRoleStatements:
# - Effect: Allow
# Action:
# - s3:*
# Resource:
# - Fn::GetAtt: [DiyBucket, Arn]
# - Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/*']]
resources:
Resources:
# lambda permission for the function to be invoked by the s3 bucket
ResizeLambdaPermissionPhotosS3:
Type: AWS::Lambda::Permission
Properties:
FunctionName:
Fn::GetAtt: [TransformOnBucketUploadLambdaFunction, Arn]
Principal: s3.amazonaws.com
Action: lambda:*
# SourceAccount:
# Ref: AWS::AccountId
SourceArn:
Fn::GetAtt: [DiyBucket, Arn]
# the s3 bucket to store sketch files and receive applications
DiyBucket:
Type: AWS::S3::Bucket
Properties:
NotificationConfiguration:
LambdaConfigurations:
- Event: "s3:ObjectCreated:*"
Function:
Fn::GetAtt: [TransformOnBucketUploadLambdaFunction, Arn]
# the admin user that can create bucket users
DiyBucketAdminUser:
Type: AWS::IAM::User
Properties:
LoginProfile:
Password: ${{env:DIY_BUCKET_ADMIN_PASSWORD}}
PasswordResetRequired: false
Groups:
- Ref: DiyBucketAdminUserGroup
# the policy group that bucket admin users should be assigned to
DiyBucketAdminUserGroup:
Type: AWS::IAM::Group
Properties:
Policies:
- PolicyName: DiyBucketAdminUserGroupPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
# required for user to use AWS S3 Console web ui
- Sid: AllowGroupToSeeBucketListInTheConsole
Action:
- s3:ListAllMyBuckets
- s3:GetBucketLocation
Effect: Allow
Resource:
- arn:aws:s3:::*
- Sid: AllowFullDiyBucketS3Access
Action:
- s3:*
Effect: Allow
Resource:
- Fn::GetAtt: [DiyBucket, Arn]
- Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/*']]
- Sid: AllowFullIAMAccess
Action:
- iam:*
Effect: Allow
Resource: '*'
# the policy group that bucket users should be assigned to
# see https://aws.amazon.com/blogs/security/writing-iam-policies-grant-access-to-user-specific-folders-in-an-amazon-s3-bucket/
DiyBucketUserGroup:
Type: AWS::IAM::Group
Properties:
Policies:
- PolicyName: DiyBucketUserGroupPolicy
PolicyDocument:
Version: '2012-10-17'
Statement:
# required for user to use AWS S3 Console web ui
- Sid: AllowGroupToSeeBucketListInTheConsole
Action:
- s3:ListAllMyBuckets
- s3:GetBucketLocation
Effect: Allow
Resource:
- arn:aws:s3:::*
- Sid: AllowRootAndHomeListingOfCompanyBucket
Action:
- s3:ListBucket
Effect: Allow
Resource:
- Fn::GetAtt: [DiyBucket, Arn]
Condition:
StringEquals:
s3:prefix:
- ''
- '${{self:custom.userFolderName}}/'
s3:delimiter:
- '/'
- Sid: AllowListingOfUserFolder
Action:
- s3:ListBucket
Effect: Allow
Resource:
- Fn::GetAtt: [DiyBucket, Arn]
Condition:
StringLike:
s3:prefix:
- '${{self:custom.userFolderName}}/${aws:username}/*'
- '${{self:custom.userFolderName}}/${aws:username}'
- Sid: AllowInputSketch
Action:
- s3:GetObject
- s3:PutObject
- s3:DeleteObject
Effect: Allow
Resource:
- Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/input/*.sketch']]
- Sid: AllowDownloadOutput
Action:
- s3:GetObject
- s3:DeleteObject
Effect: Allow
Resource:
- Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/output/*']]
- Sid: DenyInputOutputFolderDeletion
Effect: Deny
Action:
- s3:DeleteObject
Resource:
- Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/input/']]
- Fn::Join: ['', [Fn::GetAtt: [DiyBucket, Arn], '/${{self:custom.userFolderName}}/${aws:username}/output/']]