Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(s3): onCloudTrailWriteObject matches all update events #4723

Merged
merged 9 commits into from
Oct 30, 2019
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ export class S3SourceAction extends Action {
// this means a duplicate path for the same bucket - error out
throw new Error(`S3 source action with path '${this.props.bucketKey}' is already present in the pipeline for this source bucket`);
}
this.props.bucket.onCloudTrailPutObject(id, {
this.props.bucket.onCloudTrailWriteObject(id, {
target: new targets.CodePipeline(stage.pipeline),
paths: [this.props.bucketKey]
});
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -600,8 +600,20 @@
]
},
"eventName": [
"CompleteMultipartUpload",
"CopyObject",
"PutObject"
]
],
"requestParameters": {
"bucketName": [
{
"Ref": "PipelineBucketB967BD35"
}
],
"key": [
"key"
]
}
}
},
"State": "ENABLED",
Expand Down
90 changes: 88 additions & 2 deletions packages/@aws-cdk/aws-s3-notifications/test/notifications.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -305,7 +305,7 @@ test('a notification destination can specify a set of dependencies that must be
});

describe('CloudWatch Events', () => {
test('onPutItem contains the Bucket ARN itself when path is undefined', () => {
test('onCloudTrailPutObject contains the Bucket ARN itself when path is undefined', () => {
const stack = new cdk.Stack();
const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', {
bucketName: 'MyBucket',
Expand Down Expand Up @@ -347,7 +347,7 @@ describe('CloudWatch Events', () => {
});
});

test("onPutItem contains the path when it's provided", () => {
test("onCloudTrailPutObject contains the path when it's provided", () => {
const stack = new cdk.Stack();
const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', {
bucketName: 'MyBucket',
Expand Down Expand Up @@ -389,4 +389,90 @@ describe('CloudWatch Events', () => {
"State": "ENABLED",
});
});

test("onCloudTrailWriteObject matches on events CompleteMultipartUpload, CopyObject, and PutObject", () => {
const stack = new cdk.Stack();
const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', {
bucketName: 'MyBucket',
});
bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', {
target: {
bind: () => ({ arn: 'ARN', id: '' })
}
});

expect(stack).toHaveResourceLike('AWS::Events::Rule', {
"EventPattern": {
"source": [
"aws.s3",
],
"detail": {
"eventName": [
"CompleteMultipartUpload",
"CopyObject",
"PutObject",
],
},
},
"State": "ENABLED",
});
});

test('onCloudTrailWriteObject matches on the requestParameter bucketName when the path is not provided', () => {
const stack = new cdk.Stack();
const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', {
bucketName: 'MyBucket',
});
bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', {
target: {
bind: () => ({ arn: 'ARN', id: '' })
},
});

expect(stack).toHaveResourceLike('AWS::Events::Rule', {
"EventPattern": {
"source": [
"aws.s3",
],
"detail": {
"requestParameters": {
"bucketName": [
bucket.bucketName,
],
},
},
},
});
});

test("onCloudTrailWriteObject matches on the requestParameters bucketName and key when the path is provided", () => {
const stack = new cdk.Stack();
const bucket = s3.Bucket.fromBucketAttributes(stack, 'Bucket', {
bucketName: 'MyBucket',
});
bucket.onCloudTrailWriteObject('OnCloudTrailWriteObjectRule', {
target: {
bind: () => ({ arn: 'ARN', id: '' })
},
paths: ['my/path.zip']
});

expect(stack).toHaveResourceLike('AWS::Events::Rule', {
"EventPattern": {
"source": [
"aws.s3",
],
"detail": {
"requestParameters": {
"bucketName": [
bucket.bucketName,
],
"key": [
"my/path.zip",
],
},
},
},
});
});
});
68 changes: 63 additions & 5 deletions packages/@aws-cdk/aws-s3/lib/bucket.ts
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ export interface IBucket extends IResource {
grantPublicAccess(keyPrefix?: string, ...allowedActions: string[]): iam.Grant;

/**
* Define a CloudWatch event that triggers when something happens to this repository
* Defines a CloudWatch event that triggers when something happens to this bucket
*
* Requires that there exists at least one CloudTrail Trail in your account
* that captures the event. This method will not create the Trail.
Expand All @@ -183,8 +183,12 @@ export interface IBucket extends IResource {
onCloudTrailEvent(id: string, options?: OnCloudTrailBucketEventOptions): events.Rule;

/**
* Defines an AWS CloudWatch event rule that can trigger a target when an image is pushed to this
* repository.
* Defines an AWS CloudWatch event that triggers when an object is uploaded
* to the specified paths (keys) in this bucket using the PutObject API call.
*
* Note that some tools like `aws s3 cp` will automatically use either
* PutObject or the multipart upload API depending on the file size,
* so using `onCloudTrailWriteObject` may be preferable.
*
* Requires that there exists at least one CloudTrail Trail in your account
* that captures the event. This method will not create the Trail.
Expand All @@ -193,6 +197,23 @@ export interface IBucket extends IResource {
* @param options Options for adding the rule
*/
onCloudTrailPutObject(id: string, options?: OnCloudTrailBucketEventOptions): events.Rule;

/**
* Defines an AWS CloudWatch event that triggers when an object at the
* specified paths (keys) in this bucket are written to. This includes
* the events PutObject, CopyObject, and CompleteMultipartUpload.
*
* Note that some tools like `aws s3 cp` will automatically use either
* PutObject or the multipart upload API depending on the file size,
* so using this method may be preferable to `onCloudTrailPutObject`.
*
* Requires that there exists at least one CloudTrail Trail in your account
* that captures the event. This method will not create the Trail.
*
* @param id The id of the rule
* @param options Options for adding the rule
*/
onCloudTrailWriteObject(id: string, options?: OnCloudTrailBucketEventOptions): events.Rule;
}

/**
Expand Down Expand Up @@ -325,8 +346,12 @@ abstract class BucketBase extends Resource implements IBucket {
}

/**
* Defines an AWS CloudWatch event rule that can trigger a target when an image is pushed to this
* repository.
* Defines an AWS CloudWatch event that triggers when an object is uploaded
* to the specified paths (keys) in this bucket using the PutObject API call.
*
* Note that some tools like `aws s3 cp` will automatically use either
* PutObject or the multipart upload API depending on the file size,
* so using `onCloudTrailWriteObject` may be preferable.
*
* Requires that there exists at least one CloudTrail Trail in your account
* that captures the event. This method will not create the Trail.
Expand All @@ -344,6 +369,39 @@ abstract class BucketBase extends Resource implements IBucket {
return rule;
}

/**
* Defines an AWS CloudWatch event that triggers when an object at the
* specified paths (keys) in this bucket are written to. This includes
* the events PutObject, CopyObject, and CompleteMultipartUpload.
*
* Note that some tools like `aws s3 cp` will automatically use either
* PutObject or the multipart upload API depending on the file size,
* so using this method may be preferable to `onCloudTrailPutObject`.
*
* Requires that there exists at least one CloudTrail Trail in your account
* that captures the event. This method will not create the Trail.
*
* @param id The id of the rule
* @param options Options for adding the rule
*/
public onCloudTrailWriteObject(id: string, options: OnCloudTrailBucketEventOptions = {}): events.Rule {
const rule = this.onCloudTrailEvent(id, options);
rule.addEventPattern({
detail: {
eventName: [
'CompleteMultipartUpload',
'CopyObject',
'PutObject'
],
requestParameters: {
bucketName: [ this.bucketName ],
key: options.paths,
},
},
});
return rule;
}

/**
* Adds a statement to the resource policy for a principal (i.e.
* account/role/service) to perform actions on this bucket and/or it's
Expand Down