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: Add Encryption to Log Retention #29471

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -11,17 +11,18 @@ interface LogRetentionEvent extends Omit<AWSLambda.CloudFormationCustomResourceE
SdkRetry?: {
maxRetries?: string;
};
RemovalPolicy?: string
RemovalPolicy?: string;
KmsKeyId?: string;
};
}

/**
* Creates a log group and doesn't throw if it exists.
*/
async function createLogGroupSafe(logGroupName: string, client: Logs.CloudWatchLogsClient, withDelay: (block: () => Promise<void>) => Promise<void>) {
async function createLogGroupSafe(logGroupName: string, client: Logs.CloudWatchLogsClient, withDelay: (block: () => Promise<void>) => Promise<void>, kmsKeyId?: string) {
await withDelay(async () => {
try {
const params = { logGroupName };
const params = { logGroupName, kmsKeyId };
const command = new Logs.CreateLogGroupCommand(params);
await client.send(command);

Expand Down Expand Up @@ -90,6 +91,9 @@ export async function handler(event: LogRetentionEvent, context: AWSLambda.Conte
// The region of the target log group
const logGroupRegion = event.ResourceProperties.LogGroupRegion;

// The kms key used to encrypt the log group
const kmsKeyId = event.ResourceProperties.KmsKeyId;

// Parse to AWS SDK retry options
const maxRetries = parseIntOptional(event.ResourceProperties.SdkRetry?.maxRetries) ?? 5;
const withDelay = makeWithDelay(maxRetries);
Expand All @@ -103,7 +107,7 @@ export async function handler(event: LogRetentionEvent, context: AWSLambda.Conte

if (event.RequestType === 'Create' || event.RequestType === 'Update') {
// Act on the target log group
await createLogGroupSafe(logGroupName, client, withDelay);
await createLogGroupSafe(logGroupName, client, withDelay, kmsKeyId);
await setRetentionPolicy(logGroupName, client, withDelay, parseIntOptional(event.ResourceProperties.RetentionInDays));

// Configure the Log Group for the Custom Resource function itself
Expand All @@ -116,7 +120,7 @@ export async function handler(event: LogRetentionEvent, context: AWSLambda.Conte
// Due to the async nature of the log group creation, the log group for this function might
// still be not created yet at this point. Therefore we attempt to create it.
// In case it is being created, createLogGroupSafe will handle the conflict.
await createLogGroupSafe(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay);
await createLogGroupSafe(`/aws/lambda/${context.functionName}`, clientForCustomResourceFunction, withDelay, kmsKeyId);
// If createLogGroupSafe fails, the log group is not created even after multiple attempts.
// In this case we have nothing to set the retention policy on but an exception will skip
// the next line.
Expand Down
8 changes: 8 additions & 0 deletions packages/aws-cdk-lib/aws-logs/lib/log-retention.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import * as iam from '../../aws-iam';
import * as s3_assets from '../../aws-s3-assets';
import * as cdk from '../../core';
import { ArnFormat } from '../../core';
import {IKey} from "../../aws-kms";

/**
* Construction properties for a LogRetention.
Expand Down Expand Up @@ -45,6 +46,12 @@ export interface LogRetentionProps {
* @default RemovalPolicy.RETAIN
*/
readonly removalPolicy?: cdk.RemovalPolicy;

/**
* The KMS key used to encrypt the log group upon creation
* @default Log group will not be encrypted
*/
readonly kmsKey?: IKey;
}

/**
Expand Down Expand Up @@ -105,6 +112,7 @@ export class LogRetention extends Construct {
} : undefined,
RetentionInDays: props.retention === RetentionDays.INFINITE ? undefined : props.retention,
RemovalPolicy: props.removalPolicy,
KmsKeyId: props.kmsKey ? props.kmsKey?.keyArn : undefined,
},
});

Expand Down
14 changes: 14 additions & 0 deletions packages/aws-cdk-lib/aws-logs/test/log-retention.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import * as iam from '../../aws-iam';
import * as cdk from '../../core';
import * as cxapi from '../../cx-api';
import { LogRetention, RetentionDays } from '../lib';
import {Key} from "../../aws-kms";

/* eslint-disable quote-props */

Expand Down Expand Up @@ -550,4 +551,17 @@ describe('log retention', () => {
Timeout: 900,
});
});

test('with KmsKeyId specified', () => {
const stack = new cdk.Stack();
new LogRetention(stack, 'MyLambda', {
logGroupName: 'group',
retention: RetentionDays.INFINITE,
kmsKey: new Key(stack, 'MyKey')
});

Template.fromStack(stack).hasResourceProperties('Custom::LogRetention', {
KmsKeyId: { 'Fn::GetAtt': [Match.stringLikeRegexp('MyKey'), 'Arn'] },
});
});
});
2 changes: 1 addition & 1 deletion yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

"@actions/github@^5.1.1":
version "5.1.1"
resolved "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz#40b9b9e1323a5efcf4ff7dadd33d8ea51651bbcb"
resolved "https://registry.npmjs.org/@actions/github/-/github-5.1.1.tgz"
integrity sha512-Nk59rMDoJaV+mHCOJPXuvB1zIbomlKS0dmSIqPGxd0enAXBnOfn4VWF+CGtRCwXZG9Epa54tZA7VIRlJDS8A6g==
dependencies:
"@actions/http-client" "^2.0.1"
Expand Down
Loading