Skip to content
This repository has been archived by the owner on Sep 26, 2021. It is now read-only.

Commit

Permalink
Add bucket-owner-full-control function.
Browse files Browse the repository at this point in the history
  • Loading branch information
blueimp committed Sep 11, 2017
1 parent eb8f9b1 commit 04e6c86
Show file tree
Hide file tree
Showing 4 changed files with 228 additions and 0 deletions.
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ A collection of functions for [AWS Lambda](https://aws.amazon.com/lambda/).
## Functions
* [Authorize the client IP for an EC2 security group](authorize-ip)
* [Return authorized keys for EC2 SSH access](ssh-authorized-keys)
* [Grant bucket owner full control over an S3 object](bucket-owner-full-control)
* [CloudWatch alarm notifications to Slack](cloudwatch-alarm-to-slack)
* [CloudWatch Events to BuildKite](cloudwatch-events-to-buildkite)
* [CloudWatch Logs to Elastic Cloud](cloudwatch-logs-to-elastic-cloud)
Expand Down
155 changes: 155 additions & 0 deletions bucket-owner-full-control/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# bucket-owner-full-control
[AWS Lambda](https://aws.amazon.com/lambda/) function to grant the bucket owner
full control over an S3 object.

## Setup

### Prerequisites
This setup assumes two AWS accounts. The main account (`Account A`) grants
another account (`Account B`) access to an S3 bucket via
[bucket policy](http://docs.aws.amazon.com/AmazonS3/latest/dev/example-bucket-policies.html),
e.g. the following:

```json
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::BUCKET_NAME",
"arn:aws:s3:::BUCKET_NAME/*"
]
}
]
}
```

Ideally this bucket policy would restrict S3 uploads to always set the
`bucket-owner-full-control`
[canned ACL](http://docs.aws.amazon.com/AmazonS3/latest/dev/acl-overview.html#canned-acl).

A sample bucket policy with this restriction would be the following:

```json
{
"Statement": [
{
"Effect": "Allow",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:root"
},
"Action": "s3:*",
"Resource": [
"arn:aws:s3:::BUCKET_NAME",
"arn:aws:s3:::BUCKET_NAME/*"
]
},
{
"Effect": "Deny",
"Principal": {
"AWS": "arn:aws:iam::ACCOUNT_ID:root"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::BUCKET_NAME/*",
"Condition": {
"StringNotEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
```

A sample [s3 put-object](http://docs.aws.amazon.com/cli/latest/reference/s3api/put-object.html)
command with the required `bucket-owner-full-control` ACL as argument:

```sh
aws s3api put-object \
--bucket BUCKET_NAME \
--key test.txt \
--body test.txt \
--acl bucket-owner-full-control
```

In cases where this is not possible, e.g. when allowing uploads with an S3
application like [Cyberduck](https://cyberduck.io/), this Lambda function comes
in handy.

### IAM roles creation
In `Account B`, create a new cross-account [IAM](https://aws.amazon.com/iam/)
role. Fill in the account ID of `Account A` as account that can use this role.
As role name, choose `bucket-owner-full-control-role`.

After creating the role, attach the following inline policy, replacing
`BUCKET_NAME` with the name of your bucket:

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "s3:PutObjectAcl",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
},
"Resource": "arn:aws:s3:::BUCKET_NAME/*"
}
]
}
```

In `Account A`, create a new Lambda service role with the managed
`AWSLambdaBasicExecutionRole` attached. As role name choose
`aws-lambda-bucket-owner-role`.

After creating the role, attach the following inline policy, replacing
`ACCOUNT_ID` with the account ID of `Account B`:

```json
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": "sts:AssumeRole",
"Resource": "arn:aws:iam::ACCOUNT_ID:role/bucket-owner-full-control-role"
}
]
}
```

### Function configuration
Add the function code to AWS Lambda with the following configuration options:

Key | Value
--------|--------------
Runtime | Node.js 6.10
Handler | index.handler
Role | aws-lambda-bucket-owner-role
Memory | 128 (MB)
Timeout | 3 sec

### Environment variables
Set the following required environment variable for the Lambda function:

Key | Value
--------|--------------
rolearn | The ARN of the `bucket-owner-full-control-role` of `Account B`.

### Trigger configuration
Add an `S3` trigger for your bucket with the `PUT` event type.
[test-event.json](test-event.json) contains a sample S3 PUT event.

## License
Released under the [MIT license](https://opensource.org/licenses/MIT).

## Author
[Sebastian Tschan](https://blueimp.net/)
34 changes: 34 additions & 0 deletions bucket-owner-full-control/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
/*
* AWS Lambda function to grant the bucket owner full control over an S3 object.
* https://github.com/blueimp/aws-lambda
*
* Required environment variables:
* - rolearn: The ARN of the cross-account role to assume.
*
* Copyright 2017, Sebastian Tschan
* https://blueimp.net
*
* Licensed under the MIT license:
* https://opensource.org/licenses/MIT
*/

'use strict'

const AWS = require('aws-sdk')

AWS.config.credentials = new AWS.TemporaryCredentials({
RoleArn: process.env.rolearn
})

exports.handler = (event, context, callback) => {
console.log('Event:', JSON.stringify(event))
const s3 = event.Records[0].s3
new AWS.S3().putObjectAcl(
{
Bucket: s3.bucket.name,
Key: s3.object.key,
ACL: 'bucket-owner-full-control'
},
callback
)
}
38 changes: 38 additions & 0 deletions bucket-owner-full-control/test-event.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
{
"Records": [
{
"eventVersion": "2.0",
"eventSource": "aws:s3",
"awsRegion": "eu-west-1",
"eventTime": "2017-09-11T14:57:20.224Z",
"eventName": "ObjectCreated:Put",
"userIdentity": {
"principalId": "AWS:xxxxxxxxxxxxxxxxxxxxx"
},
"requestParameters": {
"sourceIPAddress": "127.0.0.1"
},
"responseElements": {
"x-amz-request-id": "xxxxxxxxxxxxxxxx",
"x-amz-id-2": "Cg=="
},
"s3": {
"s3SchemaVersion": "1.0",
"configurationId": "xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"bucket": {
"name": "BUCKET_NAME",
"ownerIdentity": {
"principalId": "xxxxxxxxxxxxx"
},
"arn": "arn:aws:s3:::BUCKET_NAME"
},
"object": {
"key": "test.txt",
"size": 7,
"eTag": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
"sequencer": "xxxxxxxxxxxxxxxxxx"
}
}
}
]
}

0 comments on commit 04e6c86

Please sign in to comment.