From 7664c052d62142c95f99645da68ff3ade7eacf2a Mon Sep 17 00:00:00 2001 From: Kevin Chiang Date: Wed, 3 Jan 2024 12:55:18 -0800 Subject: [PATCH] Implement PR suggestions: create CustomDataIdentifier class, add PolicyConfiguration interface --- .../test/aws-logs/test/integ.log-group.ts | 4 +- packages/aws-cdk-lib/aws-logs/README.md | 2 +- .../aws-logs/lib/data-protection-policy.ts | 59 ++++++++++++++----- .../aws-logs/test/loggroup.test.ts | 6 +- 4 files changed, 50 insertions(+), 21 deletions(-) diff --git a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.log-group.ts b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.log-group.ts index c100ff8346fd5..edc755f10a664 100644 --- a/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.log-group.ts +++ b/packages/@aws-cdk-testing/framework-integ/test/aws-logs/test/integ.log-group.ts @@ -1,7 +1,7 @@ import { Bucket } from 'aws-cdk-lib/aws-s3'; import { App, Stack, StackProps } from 'aws-cdk-lib'; import { IntegTest } from '@aws-cdk/integ-tests-alpha'; -import { LogGroup, DataProtectionPolicy, DataIdentifier } from 'aws-cdk-lib/aws-logs'; +import { LogGroup, DataProtectionPolicy, DataIdentifier, CustomDataIdentifier } from 'aws-cdk-lib/aws-logs'; class LogGroupIntegStack extends Stack { constructor(scope: App, id: string, props?: StackProps) { @@ -14,7 +14,7 @@ class LogGroupIntegStack extends Stack { const dataProtectionPolicy = new DataProtectionPolicy({ name: 'policy-name', description: 'policy description', - identifiers: [DataIdentifier.DRIVERSLICENSE_US, new DataIdentifier('EmailAddress'), new DataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], + identifiers: [DataIdentifier.DRIVERSLICENSE_US, new DataIdentifier('EmailAddress'), new CustomDataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], logGroupAuditDestination: audit, s3BucketAuditDestination: bucket, }); diff --git a/packages/aws-cdk-lib/aws-logs/README.md b/packages/aws-cdk-lib/aws-logs/README.md index 391e79af36fbd..d481209f46147 100644 --- a/packages/aws-cdk-lib/aws-logs/README.md +++ b/packages/aws-cdk-lib/aws-logs/README.md @@ -373,7 +373,7 @@ const dataProtectionPolicy = new logs.DataProtectionPolicy({ identifiers: [ logs.DataIdentifier.DRIVERSLICENSE_US, // managed data identifier new logs.DataIdentifier('EmailAddress'), // forward compatibility for new managed data identifiers - new logs.DataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], // custom data identifier + new CustomDataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], // custom data identifier logGroupAuditDestination: logGroupDestination, s3BucketAuditDestination: bucket, deliveryStreamNameAuditDestination: deliveryStream.deliveryStreamName, diff --git a/packages/aws-cdk-lib/aws-logs/lib/data-protection-policy.ts b/packages/aws-cdk-lib/aws-logs/lib/data-protection-policy.ts index fed5b2a4abb33..c27f443b14491 100644 --- a/packages/aws-cdk-lib/aws-logs/lib/data-protection-policy.ts +++ b/packages/aws-cdk-lib/aws-logs/lib/data-protection-policy.ts @@ -24,7 +24,7 @@ export class DataProtectionPolicy { const description = this.dataProtectionPolicyProps.description || 'cdk generated data protection policy'; const version = '2021-06-01'; - const findingsDestination: FindingsDestination = {}; + const findingsDestination: PolicyFindingsDestination = {}; if (this.dataProtectionPolicyProps.logGroupAuditDestination) { findingsDestination.cloudWatchLogs = { logGroup: this.dataProtectionPolicyProps.logGroupAuditDestination.logGroupName, @@ -44,9 +44,9 @@ export class DataProtectionPolicy { } const identifiers: string[] = []; - const customDataIdentifiers: CustomDataIdentifier[] = []; + const customDataIdentifiers: PolicyCustomDataIdentifier[] = []; for (let identifier of this.dataProtectionPolicyProps.identifiers) { - if (identifier.regex) { + if (identifier instanceof CustomDataIdentifier) { identifiers.push(identifier.name); customDataIdentifiers.push({ name: identifier.name, @@ -84,32 +84,35 @@ export class DataProtectionPolicy { }, ]; - const configuration = { + const configuration: PolicyConfiguration = { customDataIdentifier: customDataIdentifiers, }; return { name, description, version, configuration, statement }; } } -interface CustomDataIdentifier { +interface PolicyConfiguration { + customDataIdentifier?: PolicyCustomDataIdentifier[]; +} +interface PolicyCustomDataIdentifier { name: string; regex: string; } -interface FindingsDestination { - cloudWatchLogs?: CloudWatchLogsDestination; - firehose?: FirehoseDestination; - s3?: S3Destination; +interface PolicyFindingsDestination { + cloudWatchLogs?: PolicyCloudWatchLogsDestination; + firehose?: PolicyFirehoseDestination; + s3?: PolicyS3Destination; } -interface CloudWatchLogsDestination { +interface PolicyCloudWatchLogsDestination { logGroup: string; } -interface FirehoseDestination { +interface PolicyFirehoseDestination { deliveryStream: string; } -interface S3Destination { +interface PolicyS3Destination { bucket: string; } @@ -166,7 +169,7 @@ export interface DataProtectionPolicyProps { readonly description?: string; /** - * List of data protection identifiers, containing managed or custom data identfiers. + * List of data protection identifiers, containing managed or custom data identfiers (CustomDataIdentifier). * Managed data identiers must be in the following list: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL-managed-data-identifiers.html * Custom data identfiers must have a valid regex defined: https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL-custom-data-identifiers.html * @@ -197,7 +200,6 @@ export interface DataProtectionPolicyProps { /** * A data protection identifier. If an identifier is supported but not in this class, it can be passed in the constructor instead. - * To create a custom data identifier, pass in a custom name and regex. */ export class DataIdentifier { public static readonly ADDRESS = new DataIdentifier('Address'); @@ -299,9 +301,36 @@ export class DataIdentifier { public static readonly VEHICLEIDENTIFICATIONNUMBER = new DataIdentifier('VehicleIdentificationNumber'); public static readonly ZIPCODE_US = new DataIdentifier('ZipCode-US'); - constructor(public readonly name: string, public readonly regex?: string) { } + /** + * Create a managed data identifier not in the list of static members. This is used to maintain forward compatibility, in case a new managed identifier is supported but not updated in CDK yet. + * @param name - name of the identifier. + */ + constructor(public readonly name: string) { } public toString(): string { return this.name; } } + +/** + * A custom data identifier. Include a custom data identifier name and regular expression in the JSON policy used to define the data protection policy. + * https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CWL-custom-data-identifiers.html + */ +export class CustomDataIdentifier extends DataIdentifier { + /** + * Create a custom data identfier + * @param name - the name of the custom data identifier. This cannot share the same name as a managed data identifier. + * @param regex - the regular expresssion to detect and mask log events for. + */ + constructor(public readonly name: string, public readonly regex: string) { + super(name); + } + + /** + * String representation of a CustomDataIdentifier + * @returns the name and RegEx of the custom data identifier + */ + public toString(): string { + return `${this.name}: ${this.regex}`; + } +} diff --git a/packages/aws-cdk-lib/aws-logs/test/loggroup.test.ts b/packages/aws-cdk-lib/aws-logs/test/loggroup.test.ts index 1388167ded747..4b3382343086a 100644 --- a/packages/aws-cdk-lib/aws-logs/test/loggroup.test.ts +++ b/packages/aws-cdk-lib/aws-logs/test/loggroup.test.ts @@ -4,7 +4,7 @@ import * as iam from '../../aws-iam'; import * as kms from '../../aws-kms'; import { Bucket } from '../../aws-s3'; import { App, CfnParameter, Fn, RemovalPolicy, Stack } from '../../core'; -import { LogGroup, RetentionDays, LogGroupClass, DataProtectionPolicy, DataIdentifier, ILogGroup, ILogSubscriptionDestination, FilterPattern } from '../lib'; +import { LogGroup, RetentionDays, LogGroupClass, DataProtectionPolicy, DataIdentifier, CustomDataIdentifier, ILogGroup, ILogSubscriptionDestination, FilterPattern } from '../lib'; describe('log group', () => { test('set kms key when provided', () => { @@ -787,7 +787,7 @@ describe('log group', () => { const dataProtectionPolicy = new DataProtectionPolicy({ name: 'test-policy-name', description: 'test description', - identifiers: [new DataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], + identifiers: [new CustomDataIdentifier('EmployeeId', 'EmployeeId-\\d{9}')], }); // WHEN @@ -847,7 +847,7 @@ describe('log group', () => { const dataProtectionPolicy = new DataProtectionPolicy({ name: 'test-policy-name', description: 'test description', - identifiers: [new DataIdentifier('EmployeeId', 'EmployeeId-\\d{9}'), DataIdentifier.EMAILADDRESS], + identifiers: [new CustomDataIdentifier('EmployeeId', 'EmployeeId-\\d{9}'), DataIdentifier.EMAILADDRESS], }); // WHEN