From 002202fd7e32192214017772a99f9e17072bd0d8 Mon Sep 17 00:00:00 2001 From: Julian Michel Date: Wed, 22 Dec 2021 01:07:12 +0100 Subject: [PATCH] feat(docdb): allow setting log retention (#18120) Provide an option to configure the number of days log events are kept in CloudWatch Logs. Properties `cloudwatchLogsRetention` and `cloudwatchLogsRetentionRole` are added to `DatabaseClusterProps`. Closes #13191. ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license* --- packages/@aws-cdk/aws-docdb/README.md | 2 + packages/@aws-cdk/aws-docdb/lib/cluster.ts | 36 ++++++++++++++++ packages/@aws-cdk/aws-docdb/package.json | 4 ++ .../@aws-cdk/aws-docdb/test/cluster.test.ts | 41 +++++++++++++++++++ 4 files changed, 83 insertions(+) diff --git a/packages/@aws-cdk/aws-docdb/README.md b/packages/@aws-cdk/aws-docdb/README.md index 2ee2a9791c7d0..4791d99a138f7 100644 --- a/packages/@aws-cdk/aws-docdb/README.md +++ b/packages/@aws-cdk/aws-docdb/README.md @@ -130,5 +130,7 @@ const cluster = new DatabaseCluster(this, 'Database', { ..., exportProfilerLogsToCloudWatch: true, // Enable sending profiler logs exportAuditLogsToCloudWatch: true, // Enable sending audit logs + cloudWatchLogsRetention: logs.RetentionDays.THREE_MONTHS, // Optional - default is to never expire logs + cloudWatchLogsRetentionRole: myLogsPublishingRole, // Optional - a role will be created if not provided }); ``` diff --git a/packages/@aws-cdk/aws-docdb/lib/cluster.ts b/packages/@aws-cdk/aws-docdb/lib/cluster.ts index 52ce8ff5e3a64..2dd49accc8268 100644 --- a/packages/@aws-cdk/aws-docdb/lib/cluster.ts +++ b/packages/@aws-cdk/aws-docdb/lib/cluster.ts @@ -1,5 +1,7 @@ import * as ec2 from '@aws-cdk/aws-ec2'; +import { IRole } from '@aws-cdk/aws-iam'; import * as kms from '@aws-cdk/aws-kms'; +import * as logs from '@aws-cdk/aws-logs'; import * as secretsmanager from '@aws-cdk/aws-secretsmanager'; import { CfnResource, Duration, RemovalPolicy, Resource, Token } from '@aws-cdk/core'; import { Construct } from 'constructs'; @@ -164,6 +166,23 @@ export interface DatabaseClusterProps { * @default false */ readonly exportAuditLogsToCloudWatch?: boolean; + + /** + * The number of days log events are kept in CloudWatch Logs. When updating + * this property, unsetting it doesn't remove the log retention policy. To + * remove the retention policy, set the value to `Infinity`. + * + * @default - logs never expire + */ + readonly cloudWatchLogsRetention?: logs.RetentionDays; + + /** + * The IAM role for the Lambda function associated with the custom resource + * that sets the retention policy. + * + * @default - a new role is created. + */ + readonly cloudWatchLogsRetentionRole?: IRole; } /** @@ -428,6 +447,8 @@ export class DatabaseCluster extends DatabaseClusterBase { this.clusterEndpoint = new Endpoint(this.cluster.attrEndpoint, port); this.clusterReadEndpoint = new Endpoint(this.cluster.attrReadEndpoint, port); + this.setLogRetention(this, props, enableCloudwatchLogsExports); + if (secret) { this.secret = secret.attach(this); } @@ -470,6 +491,21 @@ export class DatabaseCluster extends DatabaseClusterBase { }); } + /** + * Sets up CloudWatch log retention if configured. + */ + private setLogRetention(cluster: DatabaseCluster, props: DatabaseClusterProps, cloudwatchLogsExports: string[]) { + if (props.cloudWatchLogsRetention) { + for (const log of cloudwatchLogsExports) { + new logs.LogRetention(cluster, `LogRetention${log}`, { + logGroupName: `/aws/docdb/${cluster.clusterIdentifier}/${log}`, + retention: props.cloudWatchLogsRetention, + role: props.cloudWatchLogsRetentionRole, + }); + } + } + } + /** * Adds the single user rotation of the master password to this cluster. * diff --git a/packages/@aws-cdk/aws-docdb/package.json b/packages/@aws-cdk/aws-docdb/package.json index a7ae5c843b031..5e145b8fa06f7 100644 --- a/packages/@aws-cdk/aws-docdb/package.json +++ b/packages/@aws-cdk/aws-docdb/package.json @@ -84,7 +84,9 @@ "dependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" @@ -92,7 +94,9 @@ "peerDependencies": { "@aws-cdk/aws-ec2": "0.0.0", "@aws-cdk/aws-efs": "0.0.0", + "@aws-cdk/aws-iam": "0.0.0", "@aws-cdk/aws-kms": "0.0.0", + "@aws-cdk/aws-logs": "0.0.0", "@aws-cdk/aws-secretsmanager": "0.0.0", "@aws-cdk/core": "0.0.0", "constructs": "^3.3.69" diff --git a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts index d68a91f0b80c6..b812d2b3e4742 100644 --- a/packages/@aws-cdk/aws-docdb/test/cluster.test.ts +++ b/packages/@aws-cdk/aws-docdb/test/cluster.test.ts @@ -1,6 +1,7 @@ import { expect as expectCDK, haveResource, ResourcePart, arrayWith, haveResourceLike, objectLike } from '@aws-cdk/assert-internal'; import * as ec2 from '@aws-cdk/aws-ec2'; import * as kms from '@aws-cdk/aws-kms'; +import * as logs from '@aws-cdk/aws-logs'; import * as cdk from '@aws-cdk/core'; import { ClusterParameterGroup, DatabaseCluster, DatabaseSecret } from '../lib'; @@ -652,6 +653,46 @@ describe('DatabaseCluster', () => { })); }); + test('can set CloudWatch log retention', () => { + // GIVEN + const stack = testStack(); + const vpc = new ec2.Vpc(stack, 'VPC'); + + // WHEN + new DatabaseCluster(stack, 'Database', { + masterUser: { + username: 'admin', + }, + instanceType: ec2.InstanceType.of(ec2.InstanceClass.BURSTABLE2, ec2.InstanceSize.SMALL), + vpc, + exportAuditLogsToCloudWatch: true, + exportProfilerLogsToCloudWatch: true, + cloudWatchLogsRetention: logs.RetentionDays.THREE_MONTHS, + }); + + // THEN + expectCDK(stack).to(haveResource('Custom::LogRetention', { + ServiceToken: { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + LogGroupName: { 'Fn::Join': ['', ['/aws/docdb/', { Ref: 'DatabaseB269D8BB' }, '/audit']] }, + RetentionInDays: 90, + })); + expectCDK(stack).to(haveResource('Custom::LogRetention', { + ServiceToken: { + 'Fn::GetAtt': [ + 'LogRetentionaae0aa3c5b4d4f87b02d85b201efdd8aFD4BFC8A', + 'Arn', + ], + }, + LogGroupName: { 'Fn::Join': ['', ['/aws/docdb/', { Ref: 'DatabaseB269D8BB' }, '/profiler']] }, + RetentionInDays: 90, + })); + }); + test('single user rotation', () => { // GIVEN const stack = testStack();