Skip to content

Commit

Permalink
feat(cloudtrail): user specified log group (#8079)
Browse files Browse the repository at this point in the history
Allow for users to set their own log group that CloudTrail must send
events to.

Expose a log group instance property that returns the user specified or
auto-created log group.

closes #6162


----

*By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
  • Loading branch information
Niranjan Jayakar authored May 21, 2020
1 parent dadc9d1 commit 0a3785b
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 12 deletions.
4 changes: 3 additions & 1 deletion packages/@aws-cdk/aws-cloudtrail/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,9 @@ const trail = new cloudtrail.Trail(this, 'CloudTrail', {
```

This creates the same setup as above - but also logs events to a created CloudWatch Log stream.
By default, the created log group has a retention period of 365 Days, but this is also configurable.
By default, the created log group has a retention period of 365 Days, but this is also configurable
via the `cloudWatchLogsRetention` property. If you would like to specify the log group explicitly,
use the `cloudwatchLogGroup` property.

For using CloudTrail event selector to log specific S3 events,
you can use the `CloudTrailProps` configuration object.
Expand Down
34 changes: 25 additions & 9 deletions packages/@aws-cdk/aws-cloudtrail/lib/cloudtrail.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,12 +63,19 @@ export interface TrailProps {
readonly sendToCloudWatchLogs?: boolean;

/**
* How long to retain logs in CloudWatchLogs. Ignored if sendToCloudWatchLogs is false
* How long to retain logs in CloudWatchLogs.
* Ignored if sendToCloudWatchLogs is false or if cloudWatchLogGroup is set.
*
* @default logs.RetentionDays.OneYear
* @default logs.RetentionDays.ONE_YEAR
*/
readonly cloudWatchLogsRetention?: logs.RetentionDays;

/**
* Log Group to which CloudTrail to push logs to. Ignored if sendToCloudWatchLogs is set to false.
* @default - a new log group is created and used.
*/
readonly cloudWatchLogGroup?: logs.ILogGroup;

/** The AWS Key Management Service (AWS KMS) key ID that you want to use to encrypt CloudTrail logs.
*
* @default - No encryption.
Expand Down Expand Up @@ -171,6 +178,12 @@ export class Trail extends Resource {
*/
public readonly trailSnsTopicArn: string;

/**
* The CloudWatch log group to which CloudTrail events are sent.
* `undefined` if `sendToCloudWatchLogs` property is false.
*/
public readonly logGroup?: logs.ILogGroup;

private s3bucket: s3.IBucket;
private eventSelectors: EventSelector[] = [];

Expand Down Expand Up @@ -200,19 +213,22 @@ export class Trail extends Resource {
},
}));

let logGroup: logs.CfnLogGroup | undefined;
let logsRole: iam.IRole | undefined;

if (props.sendToCloudWatchLogs) {
logGroup = new logs.CfnLogGroup(this, 'LogGroup', {
retentionInDays: props.cloudWatchLogsRetention || logs.RetentionDays.ONE_YEAR,
});
if (props.cloudWatchLogGroup) {
this.logGroup = props.cloudWatchLogGroup;
} else {
this.logGroup = new logs.LogGroup(this, 'LogGroup', {
retention: props.cloudWatchLogsRetention ?? logs.RetentionDays.ONE_YEAR,
});
}

logsRole = new iam.Role(this, 'LogsRole', { assumedBy: cloudTrailPrincipal });

logsRole.addToPolicy(new iam.PolicyStatement({
actions: ['logs:PutLogEvents', 'logs:CreateLogStream'],
resources: [logGroup.attrArn],
resources: [this.logGroup.logGroupArn],
}));
}

Expand All @@ -234,8 +250,8 @@ export class Trail extends Resource {
kmsKeyId: props.kmsKey && props.kmsKey.keyArn,
s3BucketName: this.s3bucket.bucketName,
s3KeyPrefix: props.s3KeyPrefix,
cloudWatchLogsLogGroupArn: logGroup && logGroup.attrArn,
cloudWatchLogsRoleArn: logsRole && logsRole.roleArn,
cloudWatchLogsLogGroupArn: this.logGroup?.logGroupArn,
cloudWatchLogsRoleArn: logsRole?.roleArn,
snsTopicName: props.snsTopic,
eventSelectors: this.eventSelectors,
});
Expand Down
42 changes: 40 additions & 2 deletions packages/@aws-cdk/aws-cloudtrail/test/cloudtrail.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import { SynthUtils } from '@aws-cdk/assert';
import '@aws-cdk/assert/jest';
import * as iam from '@aws-cdk/aws-iam';
import * as lambda from '@aws-cdk/aws-lambda';
import { RetentionDays } from '@aws-cdk/aws-logs';
import { LogGroup, RetentionDays } from '@aws-cdk/aws-logs';
import * as s3 from '@aws-cdk/aws-s3';
import { Stack } from '@aws-cdk/core';
import { ReadWriteType, Trail } from '../lib';
Expand Down Expand Up @@ -176,7 +176,7 @@ describe('cloudtrail', () => {
Effect: 'Allow',
Action: ['logs:PutLogEvents', 'logs:CreateLogStream'],
Resource: {
'Fn::GetAtt': ['MyAmazingCloudTrailLogGroupAAD65144', 'Arn'],
'Fn::GetAtt': ['MyAmazingCloudTrailLogGroup2BE67F87', 'Arn'],
},
}],
},
Expand Down Expand Up @@ -205,6 +205,44 @@ describe('cloudtrail', () => {
const trail: any = SynthUtils.synthesize(stack).template.Resources.MyAmazingCloudTrail54516E8D;
expect(trail.DependsOn).toEqual([logsRolePolicyName, logsRoleName, 'MyAmazingCloudTrailS3Policy39C120B0']);
});

test('enabled and with custom log group', () => {
const stack = getTestStack();
const cloudWatchLogGroup = new LogGroup(stack, 'MyLogGroup', {
retention: RetentionDays.FIVE_DAYS,
});
new Trail(stack, 'MyAmazingCloudTrail', {
sendToCloudWatchLogs: true,
cloudWatchLogsRetention: RetentionDays.ONE_WEEK,
cloudWatchLogGroup,
});

expect(stack).toHaveResource('AWS::Logs::LogGroup', {
RetentionInDays: 5,
});

expect(stack).toHaveResource('AWS::CloudTrail::Trail', {
CloudWatchLogsLogGroupArn: stack.resolve(cloudWatchLogGroup.logGroupArn),
});

expect(stack).toHaveResourceLike('AWS::IAM::Policy', {
PolicyDocument: {
Statement: [{
Resource: stack.resolve(cloudWatchLogGroup.logGroupArn),
}],
},
});
});

test('disabled', () => {
const stack = getTestStack();
const t = new Trail(stack, 'MyAmazingCloudTrail', {
sendToCloudWatchLogs: false,
cloudWatchLogsRetention: RetentionDays.ONE_WEEK,
});
expect(t.logGroup).toBeUndefined();
expect(stack).not.toHaveResource('AWS::Logs::LogGroup');
});
});

describe('with event selectors', () => {
Expand Down

0 comments on commit 0a3785b

Please sign in to comment.