From 07fa8ef76ab9d181a27807366dcd8ba68fb460e2 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Thu, 15 Jan 2026 21:21:00 +0000 Subject: [PATCH 1/9] RFC 859: ObservabilityAdmin OrganizationCentralizationRule L2 Construct RFC --- text/0859-organization-centralization-rule.md | 323 ++++++++++++++++++ 1 file changed, 323 insertions(+) create mode 100644 text/0859-organization-centralization-rule.md diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md new file mode 100644 index 000000000..a2a0efe6e --- /dev/null +++ b/text/0859-organization-centralization-rule.md @@ -0,0 +1,323 @@ +# AWS ObservabilityAdmin OrganizationCentralizationRule L2 Construct + +* **Original Author(s)**: @jsicheng +* **Tracking Issue**: #859 +* **API Bar Raiser**: TBD + +The Amazon ObservabilityAdmin OrganizationCentralizationRule L2 construct simplifies centralization rule creation for an AWS Organization, reducing the complexity of configuring organization-wide log centralization policies through sensible defaults, strong-typing and synthesis-time validation. + +## Working Backwards + +### CHANGELOG + +``` +feat(observabilityadmin): ObservabilityAdmin OrganizationCentralizationRule L2 construct +``` + +### README + +#### AWS ObservabilityAdmin OrganizationCentralizationRule Construct Library + +[Amazon ObservabilityAdmin OrganizationCentralizationRule](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatchLogs_Centralization.html) provides AWS Organization management accounts and optionally, delegated admin accounts, the ability to create log centralization rules for their organization. Defined rules automatically replicate select CloudWatch Logs data from multiple source accounts and regions into a centralized destination account and region. Centralization rules offers configuration flexibility to meet operational and security requirements, such as the ability to configure a backup region and KMS encryption behavior. + +This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) +project. It allows you to define ObservabilityAdmin organization centralization rules. + +##### Basic Usage + +```typescript +new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { + ruleName: 'OrganizationCentralizationRule', + sourceScope: Scope.ALL, + sourceRegions: ['us-east-1', 'us-west-2'], + sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria.ALL, + destinationAccount: '123456789012', + destinationRegion: 'us-east-1', +}); +``` + +##### Advanced Configuration +```typescript +new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { + ruleName: 'OrganizationCentralizationRule', + sourceScope: Scope.or( + Scope.organizationUnitIdEquals('ou-1234-abcdefgh'), + Scope.accountIdIn(['000000000000', '111111111111']), + ), + sourceRegions: ['us-east-1', 'us-west-2'], + sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria.or( + LogGroupSelectionCriteria.equals('ExactLogGroupName'), + LogGroupSelectionCriteria.like('LogGroupNamePrefix'), + ), + sourceEncryptedLogGroupStrategy: EncryptedLogGroupStrategy.ALLOW, + destinationAccount: '123456789012', + destinationRegion: 'us-east-1', + destinationLogEncryptionStrategy: LogEncryptionStrategy.CUSTOMER_MANAGED, + destinationLogEncryptionConflictResolutionStrategy: LogEncryptionConflictResolutionStrategy.ALLOW, + destinationLogEncryptionKmsKeyArn: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012', + destinationBackupRegion: 'us-west-2', + destinationBackupKmsKeyArn: 'arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012', +}); +``` + +Ticking the box below indicates that the public API of this RFC has been +signed-off by the API bar raiser (the `status/api-approved` label was applied to the +RFC pull request): + +``` +[ ] Signed-off by API Bar Raiser @xxxxx +``` + +## Public FAQ + +### What are we launching today? + +We are launching a new L2 construct in the `aws-observabilityadmin` module that provides a simplified, type-safe interface for creating AWS ObservabilityAdmin OrganizationCentralizationRule resources. This construct abstracts the complexity of the underlying CloudFormation resource and L1 construct while following AWS CDK design principles. + +### Why should I use this feature? + +The L2 construct enables the creation of organization centralization rules with minimal configurations while adhering to the AWS best practices. The included types and defaults smooths out rough edges in configuring the resource using L1 constructs. + +## Internal FAQ + +### Why are we doing this? + +AWS ObservabilityAdmin OrganizationCentralizationRule is a feature that helps organizations centralize their log data collection. Currently, users must work with highly nested L1 parameters, which requires deep knowledge of the service's configuration options and can lead to misconfigurations. An L2 construct will: + +1. Provide a more intuitive API with sensible defaults +2. Include built-in validation to prevent common configuration errors +3. Offer better integration with CDK patterns and other constructs + +### Why should we _not_ do this? + +Potential concerns: + +- The service is relatively new and APIs might still evolve +- The L1 construct already provides full functionality + +However, these concerns are outweighed by the benefits of providing a better developer experience and encouraging adoption of centralized log management practices. + +### What is the technical solution (design) of this feature? +- Resource interfaces: +```typescript +interface ICentralizationRuleBase extends IResource, ITaggableV2 { + /** + * The name of the centralization rule. + */ + readonly ruleName: string; + /** + * The arn of the centralization rule. + * + * @attribute + */ + readonly ruleArn: string; +} + +interface IOrganizationCentralizationRule extends ICentralizationRuleBase {} +``` +- Resource classes: +```typescript +abstract class CentralizationRuleBase extends Resource implements ICentralizationRuleBase { + public abstract readonly ruleName: string; + public abstract readonly ruleArn: string; +} + +class OrganizationCentralizationRule extends CentralizationRuleBase implements IOrganizationCentralizationRule { + public static fromOrganizationCentralizationRuleName(scope: Construct, id: string, name: string): IOrganizationCentralizationRule; + public static fromOrganizationCentralizationRuleArn(scope: Construct, id: string, arn: string): IOrganizationCentralizationRule; + constructor(scope: Construct, id: string, props: OrganizationCentralizationRuleProps); +} +``` +- Resource props: +```typescript +interface BaseCentralizationRuleProps { + /** + * The name of the centralization rule. + */ + readonly ruleName: string; + /** + * The list of source regions from which telemetry data should be centralized. + */ + readonly sourceRegions: string[]; + /** + * The selection criteria that specifies which source log groups to centralize. The selection criteria uses the same format as OAM link filters. + */ + readonly sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria; + /** + * A strategy determining whether to centralize source log groups that are encrypted with customer managed KMS keys (CMK). + * ALLOW will consider CMK encrypted source log groups for centralization while SKIP will skip CMK encrypted source log groups from centralization. + * @default - Skip centralizing CMK encrypted source log groups. + */ + readonly sourceEncryptedLogGroupStrategy?: EncryptedLogGroupStrategy; + /** + * The destination account (within the organization) to which the telemetry data should be centralized. + */ + readonly destinationAccount: string; + /** + * The primary destination region to which telemetry data should be centralized. + */ + readonly destinationRegion: string; + /** + * Configuration that determines the encryption strategy of the destination log groups. + * CUSTOMER_MANAGED uses the configured KmsKeyArn to encrypt newly created destination log groups. + * @default - Inferred from destinationLogEncryptionKmsKeyArn. If destinationLogEncryptionKmsKeyArn is not provided, defaults to AWS_OWNED. Otherwise, defaults to CUSTOMER_MANAGED. + */ + readonly destinationLogEncryptionStrategy?: LogEncryptionStrategy; + /** + * Conflict resolution strategy for centralization if the encryption strategy is set to CUSTOMER_MANAGED and the destination log group is encrypted with an AWS_OWNED KMS Key. + * ALLOW lets centralization go through while SKIP prevents centralization into the destination log group. + * @default - Skip centralization for conflicting encryption. + */ + readonly destinationLogEncryptionConflictResolutionStrategy?: LogEncryptionConflictResolutionStrategy; + /** + * KMS Key ARN belonging to the primary destination account and region, to encrypt newly created central log groups in the primary destination. + * @default - Log groups are encrypted with an AWS_OWNED KMS key. + */ + readonly destinationLogEncryptionKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account + /** + * Logs-specific backup destination region within the primary destination account to which log data should be centralized. + * @default - no centralization backup destination region is configured. + */ + readonly destinationBackupRegion?: string; + /** + * KMS Key ARN belonging to the primary destination account and backup region, to encrypt newly created central log groups in the backup destination. + * Only applied when destinationBackupRegion is set. If destinationBackupRegion is set, the backup region KMS key must be specified if destinationLogEncryptionStrategy is CUSTOMER_MANAGED. + * @default - centralization backup destination log groups are not encrypted. + */ + readonly destinationBackupKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account +} + +interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProps { + /** + * The organizational scope from which telemetry data should be centralized, specified using accounts or organizational unit ids. + */ + sourceScope: Scope; +} +``` +- Helper classes: +```typescript +export class Scope { + // All accounts in the organization + public static ALL = new Scope('*'); + // Equivalent to `AccountId = 'accountId'` + public static accountIdEquals(accountId: string): Scope; + // Equivalent to `OrganizationUnitId = 'organizationUnitId'` + public static organizationUnitIdEquals(organizationUnitId: string): Scope; + // Equivalent to `AccountId IN ('accountId1', 'accountId2')` + public static accountIdIn(accountIds: string[]): Scope; + // Equivalent to `OrganizationUnitId IN ('organizationUnitId1', 'organizationUnitId2')` + public static organizationUnitIdIn(organizationUnitIds: string[]): Scope; + // Joins all provided Scopes with an OR operator + public static or(...operands: Scope[]): Scope; + // Custom Scope from string + public static fromString(scope: string): Scope { + return new Scope(scope); + } + protected constructor(public readonly scope: string) { } +} + +/** + * The selection criteria that specifies which source log groups to centralize. + */ +export class LogGroupSelectionCriteria { + // All LogGroups + public static ALL = new LogGroupSelectionCriteria('*'); + // Equivalent to `LogGroupName = 'logGroupName'` + public static equals(logGroupName: string): LogGroupSelectionCriteria; + // Equivalent to `LogGroupName != 'logGroupName'` + public static notEquals(logGroupName: string): LogGroupSelectionCriteria; + // Equivalent to `LogGroupName IN ('logGroupName1', 'logGroupName2')` + public static in(logGroupNames: string[]): LogGroupSelectionCriteria; + // Equivalent to `LogGroupName NOT IN ('logGroupName1', 'logGroupName2')` + public static notIn(logGroupNames: string[]): LogGroupSelectionCriteria; + // Prefix search. Equivalent to `LogGroupName LIKE 'logGroupNamePrefix%'` + public static like(logGroupNamePrefix: string): LogGroupSelectionCriteria; + // Prefix search. Equivalent to `LogGroupName NOT LIKE 'logGroupNamePrefix%'` + public static notLike(logGroupNamePrefix: string): LogGroupSelectionCriteria; + // Joins all provided LogGroupSelectionCriterias with an AND operator + public static and(...operands: LogGroupSelectionCriteria[]): LogGroupSelectionCriteria; + // Joins all provided LogGroupSelectionCriterias with an OR operator + public static or(...operands: LogGroupSelectionCriteria[]): LogGroupSelectionCriteria; + // Custom LogGroupSelectionCriteria from string + public static fromString(selectionCriteria: string): LogGroupSelectionCriteria { + return new LogGroupSelectionCriteria(selectionCriteria); + } + protected constructor(public readonly selectionCriteria: string) { } +} + +/** + * Strategy for determining whether to centralize source log groups that are encrypted with customer managed KMS keys (CMK). + */ +export enum EncryptedLogGroupStrategy { + /** + * Allow CMK encrypted log groups to be centralized. + */ + ALLOW = 'ALLOW', + /** + * SKIP CMK encrypted source log groups from centralization. + */ + SKIP = 'SKIP' +} + +/** + * Configuration that determines the encryption strategy of the destination log groups. + */ +export enum LogEncryptionStrategy { + /** + * Use the configured KmsKeyArn to encrypt newly created destination log groups. + */ + CUSTOMER_MANAGED = 'CUSTOMER_MANAGED', + /** + * Use an AWS owned KMS key to encrypt newly created destination log groups. + */ + AWS_OWNED = 'AWS_OWNED' +} + +/** + * Conflict resolution strategy for centralization if the LogEncryptionStrategy is set to CUSTOMER_MANAGED and the destination log group is encrypted with an AWS_OWNED KMS Key. + */ +export enum LogEncryptionConflictResolutionStrategy { + /** + * Allow source CMK encrypted log groups to be centralized despite encryption conflicts in the destination. + */ + ALLOW = 'ALLOW', + /** + * Skip CMK encrypted source log groups from centralization. + */ + SKIP = 'SKIP' +} +``` +Validations: +- Required array inputs must not be empty. +- Account IDs in Scope should be 12 digit numbers. +- `destinationAccount` should be a 12 digit number. +- `sourceRegions` should not be empty. +- `sourceRegions` should contain valid AWS regions. +- `destinationRegion` should be a valid AWS region. +- `destinationBackupRegion` should be a valid AWS region. +- If `destinationLogEncryptionStrategy` is `CUSTOMER_MANAGED`, then + - `destinationLogEncryptionKmsKeyArn` must be provided. + - If destinationBackupRegion is set, then `destinationBackupKmsKeyArn` must also be provided. +- KMS Key ARNs should follow valid ARN format. + +### Is this a breaking change? + +No, this is a new feature that adds functionality without modifying existing APIs. + +### What alternative solutions did you consider? + +Keeping a simple string input for all fields without adding new types, but still keeping parameters unnested and flat. However, many customers are likely not familiar with available options or the [OAM LinkFilter syntax](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-oam-link-linkfilter.html). + +### What are the drawbacks of this solution? + +- **API evolution**: The underlying service is relatively new and may soon introduce new resources and fields. +### What is the high-level project plan? + +- [ ] Kick off and gather feedback for RFC +- [ ] Bar raiser to sign off on RFC +- [ ] Implement L2 Construct, iterate and respond to feedback +- [ ] Merge new construct + +### Are there any open issues that need to be addressed later? + +- **Forward compatibility**: L2 construct must support future data sources. Some fields will be intentionally left as optional to support this. From 91aca8c1ae523c5c749d42ad0ace372ebe166993 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Fri, 16 Jan 2026 18:18:32 +0000 Subject: [PATCH 2/9] Update API bar raisers --- text/0859-organization-centralization-rule.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index a2a0efe6e..68fddbf47 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -2,7 +2,7 @@ * **Original Author(s)**: @jsicheng * **Tracking Issue**: #859 -* **API Bar Raiser**: TBD +* **API Bar Raiser**: @kumsmrit, @gjurova The Amazon ObservabilityAdmin OrganizationCentralizationRule L2 construct simplifies centralization rule creation for an AWS Organization, reducing the complexity of configuring organization-wide log centralization policies through sensible defaults, strong-typing and synthesis-time validation. From 31cdf0b7b19a9a05a6da15d8ced07f1be8f0f2e9 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Fri, 16 Jan 2026 18:33:21 +0000 Subject: [PATCH 3/9] Fix linting issues --- text/0859-organization-centralization-rule.md | 54 ++++++++++++++----- 1 file changed, 41 insertions(+), 13 deletions(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index 68fddbf47..976a4e538 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -4,7 +4,8 @@ * **Tracking Issue**: #859 * **API Bar Raiser**: @kumsmrit, @gjurova -The Amazon ObservabilityAdmin OrganizationCentralizationRule L2 construct simplifies centralization rule creation for an AWS Organization, reducing the complexity of configuring organization-wide log centralization policies through sensible defaults, strong-typing and synthesis-time validation. +The Amazon ObservabilityAdmin OrganizationCentralizationRule L2 construct simplifies centralization rule creation for an AWS Organization, +reducing the complexity of configuring organization-wide log centralization policies through sensible defaults, strong-typing and synthesis-time validation. ## Working Backwards @@ -18,7 +19,11 @@ feat(observabilityadmin): ObservabilityAdmin OrganizationCentralizationRule L2 c #### AWS ObservabilityAdmin OrganizationCentralizationRule Construct Library -[Amazon ObservabilityAdmin OrganizationCentralizationRule](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatchLogs_Centralization.html) provides AWS Organization management accounts and optionally, delegated admin accounts, the ability to create log centralization rules for their organization. Defined rules automatically replicate select CloudWatch Logs data from multiple source accounts and regions into a centralized destination account and region. Centralization rules offers configuration flexibility to meet operational and security requirements, such as the ability to configure a backup region and KMS encryption behavior. +[Amazon ObservabilityAdmin OrganizationCentralizationRule](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/CloudWatchLogs_Centralization.html) +provides AWS Organization management accounts and optionally, delegated admin accounts, the ability to create log centralization rules for their +organization. Defined rules automatically replicate select CloudWatch Logs data from multiple source accounts and regions into a centralized +destination account and region. Centralization rules offers configuration flexibility to meet operational and security requirements, such as the ability +to configure a backup region and KMS encryption behavior. This module is part of the [AWS Cloud Development Kit](https://github.com/aws/aws-cdk) project. It allows you to define ObservabilityAdmin organization centralization rules. @@ -37,6 +42,7 @@ new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { ``` ##### Advanced Configuration + ```typescript new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { ruleName: 'OrganizationCentralizationRule', @@ -72,17 +78,22 @@ RFC pull request): ### What are we launching today? -We are launching a new L2 construct in the `aws-observabilityadmin` module that provides a simplified, type-safe interface for creating AWS ObservabilityAdmin OrganizationCentralizationRule resources. This construct abstracts the complexity of the underlying CloudFormation resource and L1 construct while following AWS CDK design principles. +We are launching a new L2 construct in the `aws-observabilityadmin` module that provides a simplified, type-safe interface for creating +AWS ObservabilityAdmin OrganizationCentralizationRule resources. This construct abstracts the complexity of the underlying CloudFormation +resource and L1 construct while following AWS CDK design principles. ### Why should I use this feature? -The L2 construct enables the creation of organization centralization rules with minimal configurations while adhering to the AWS best practices. The included types and defaults smooths out rough edges in configuring the resource using L1 constructs. +The L2 construct enables the creation of organization centralization rules with minimal configurations while adhering to the AWS best practices. +The included types and defaults smooths out rough edges in configuring the resource using L1 constructs. ## Internal FAQ ### Why are we doing this? -AWS ObservabilityAdmin OrganizationCentralizationRule is a feature that helps organizations centralize their log data collection. Currently, users must work with highly nested L1 parameters, which requires deep knowledge of the service's configuration options and can lead to misconfigurations. An L2 construct will: +AWS ObservabilityAdmin OrganizationCentralizationRule is a feature that helps organizations centralize their log data collection. Currently, users +must work with highly nested L1 parameters, which requires deep knowledge of the service's configuration options and can lead to misconfigurations. +An L2 construct will: 1. Provide a more intuitive API with sensible defaults 2. Include built-in validation to prevent common configuration errors @@ -95,10 +106,13 @@ Potential concerns: - The service is relatively new and APIs might still evolve - The L1 construct already provides full functionality -However, these concerns are outweighed by the benefits of providing a better developer experience and encouraging adoption of centralized log management practices. +However, these concerns are outweighed by the benefits of providing a better developer experience and encouraging adoption of +centralized log management practices. ### What is the technical solution (design) of this feature? + - Resource interfaces: + ```typescript interface ICentralizationRuleBase extends IResource, ITaggableV2 { /** @@ -115,7 +129,9 @@ interface ICentralizationRuleBase extends IResource, ITaggableV2 { interface IOrganizationCentralizationRule extends ICentralizationRuleBase {} ``` + - Resource classes: + ```typescript abstract class CentralizationRuleBase extends Resource implements ICentralizationRuleBase { public abstract readonly ruleName: string; @@ -128,7 +144,9 @@ class OrganizationCentralizationRule extends CentralizationRuleBase implements I constructor(scope: Construct, id: string, props: OrganizationCentralizationRuleProps); } ``` + - Resource props: + ```typescript interface BaseCentralizationRuleProps { /** @@ -160,11 +178,13 @@ interface BaseCentralizationRuleProps { /** * Configuration that determines the encryption strategy of the destination log groups. * CUSTOMER_MANAGED uses the configured KmsKeyArn to encrypt newly created destination log groups. - * @default - Inferred from destinationLogEncryptionKmsKeyArn. If destinationLogEncryptionKmsKeyArn is not provided, defaults to AWS_OWNED. Otherwise, defaults to CUSTOMER_MANAGED. + * @default - Inferred from destinationLogEncryptionKmsKeyArn. + * If destinationLogEncryptionKmsKeyArn is not provided, defaults to AWS_OWNED. Otherwise, defaults to CUSTOMER_MANAGED. */ readonly destinationLogEncryptionStrategy?: LogEncryptionStrategy; /** - * Conflict resolution strategy for centralization if the encryption strategy is set to CUSTOMER_MANAGED and the destination log group is encrypted with an AWS_OWNED KMS Key. + * Conflict resolution strategy for centralization if the encryption strategy is set to CUSTOMER_MANAGED and the destination log group is + * encrypted with an AWS_OWNED KMS Key. * ALLOW lets centralization go through while SKIP prevents centralization into the destination log group. * @default - Skip centralization for conflicting encryption. */ @@ -181,7 +201,8 @@ interface BaseCentralizationRuleProps { readonly destinationBackupRegion?: string; /** * KMS Key ARN belonging to the primary destination account and backup region, to encrypt newly created central log groups in the backup destination. - * Only applied when destinationBackupRegion is set. If destinationBackupRegion is set, the backup region KMS key must be specified if destinationLogEncryptionStrategy is CUSTOMER_MANAGED. + * Only applied when destinationBackupRegion is set. + * If destinationBackupRegion is set, the backup region KMS key must be specified if destinationLogEncryptionStrategy is CUSTOMER_MANAGED. * @default - centralization backup destination log groups are not encrypted. */ readonly destinationBackupKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account @@ -194,7 +215,9 @@ interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProp sourceScope: Scope; } ``` + - Helper classes: + ```typescript export class Scope { // All accounts in the organization @@ -274,7 +297,8 @@ export enum LogEncryptionStrategy { } /** - * Conflict resolution strategy for centralization if the LogEncryptionStrategy is set to CUSTOMER_MANAGED and the destination log group is encrypted with an AWS_OWNED KMS Key. + * Conflict resolution strategy for centralization if the LogEncryptionStrategy is set to CUSTOMER_MANAGED and the destination log group is + * encrypted with an AWS_OWNED KMS Key. */ export enum LogEncryptionConflictResolutionStrategy { /** @@ -287,7 +311,9 @@ export enum LogEncryptionConflictResolutionStrategy { SKIP = 'SKIP' } ``` + Validations: + - Required array inputs must not be empty. - Account IDs in Scope should be 12 digit numbers. - `destinationAccount` should be a 12 digit number. @@ -296,8 +322,8 @@ Validations: - `destinationRegion` should be a valid AWS region. - `destinationBackupRegion` should be a valid AWS region. - If `destinationLogEncryptionStrategy` is `CUSTOMER_MANAGED`, then - - `destinationLogEncryptionKmsKeyArn` must be provided. - - If destinationBackupRegion is set, then `destinationBackupKmsKeyArn` must also be provided. +- `destinationLogEncryptionKmsKeyArn` must be provided. +- If destinationBackupRegion is set, then `destinationBackupKmsKeyArn` must also be provided. - KMS Key ARNs should follow valid ARN format. ### Is this a breaking change? @@ -306,11 +332,13 @@ No, this is a new feature that adds functionality without modifying existing API ### What alternative solutions did you consider? -Keeping a simple string input for all fields without adding new types, but still keeping parameters unnested and flat. However, many customers are likely not familiar with available options or the [OAM LinkFilter syntax](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-oam-link-linkfilter.html). +Keeping a simple string input for all fields without adding new types, but still keeping parameters unnested and flat. However, many customers are +likely not familiar with available options or the [OAM LinkFilter syntax](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-oam-link-linkfilter.html). ### What are the drawbacks of this solution? - **API evolution**: The underlying service is relatively new and may soon introduce new resources and fields. + ### What is the high-level project plan? - [ ] Kick off and gather feedback for RFC From 44213eceac0e7efbf4232a4065c3d47d882e1388 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Fri, 16 Jan 2026 18:39:40 +0000 Subject: [PATCH 4/9] Trigger check From 224df1b40df271264f4b639bee3006a803273602 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Tue, 20 Jan 2026 18:58:51 +0000 Subject: [PATCH 5/9] Remove advanced Scope and LogGroupSelectionCriteria helpers --- text/0859-organization-centralization-rule.md | 41 +++---------------- 1 file changed, 5 insertions(+), 36 deletions(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index 976a4e538..b68513c79 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -46,15 +46,9 @@ new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { ```typescript new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { ruleName: 'OrganizationCentralizationRule', - sourceScope: Scope.or( - Scope.organizationUnitIdEquals('ou-1234-abcdefgh'), - Scope.accountIdIn(['000000000000', '111111111111']), - ), + sourceScope: Scope.fromString(`AccountId = '012345678901'`), sourceRegions: ['us-east-1', 'us-west-2'], - sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria.or( - LogGroupSelectionCriteria.equals('ExactLogGroupName'), - LogGroupSelectionCriteria.like('LogGroupNamePrefix'), - ), + sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria.fromString(`LogGroupName = 'ExactLogGroupName'`), sourceEncryptedLogGroupStrategy: EncryptedLogGroupStrategy.ALLOW, destinationAccount: '123456789012', destinationRegion: 'us-east-1', @@ -222,16 +216,6 @@ interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProp export class Scope { // All accounts in the organization public static ALL = new Scope('*'); - // Equivalent to `AccountId = 'accountId'` - public static accountIdEquals(accountId: string): Scope; - // Equivalent to `OrganizationUnitId = 'organizationUnitId'` - public static organizationUnitIdEquals(organizationUnitId: string): Scope; - // Equivalent to `AccountId IN ('accountId1', 'accountId2')` - public static accountIdIn(accountIds: string[]): Scope; - // Equivalent to `OrganizationUnitId IN ('organizationUnitId1', 'organizationUnitId2')` - public static organizationUnitIdIn(organizationUnitIds: string[]): Scope; - // Joins all provided Scopes with an OR operator - public static or(...operands: Scope[]): Scope; // Custom Scope from string public static fromString(scope: string): Scope { return new Scope(scope); @@ -245,22 +229,6 @@ export class Scope { export class LogGroupSelectionCriteria { // All LogGroups public static ALL = new LogGroupSelectionCriteria('*'); - // Equivalent to `LogGroupName = 'logGroupName'` - public static equals(logGroupName: string): LogGroupSelectionCriteria; - // Equivalent to `LogGroupName != 'logGroupName'` - public static notEquals(logGroupName: string): LogGroupSelectionCriteria; - // Equivalent to `LogGroupName IN ('logGroupName1', 'logGroupName2')` - public static in(logGroupNames: string[]): LogGroupSelectionCriteria; - // Equivalent to `LogGroupName NOT IN ('logGroupName1', 'logGroupName2')` - public static notIn(logGroupNames: string[]): LogGroupSelectionCriteria; - // Prefix search. Equivalent to `LogGroupName LIKE 'logGroupNamePrefix%'` - public static like(logGroupNamePrefix: string): LogGroupSelectionCriteria; - // Prefix search. Equivalent to `LogGroupName NOT LIKE 'logGroupNamePrefix%'` - public static notLike(logGroupNamePrefix: string): LogGroupSelectionCriteria; - // Joins all provided LogGroupSelectionCriterias with an AND operator - public static and(...operands: LogGroupSelectionCriteria[]): LogGroupSelectionCriteria; - // Joins all provided LogGroupSelectionCriterias with an OR operator - public static or(...operands: LogGroupSelectionCriteria[]): LogGroupSelectionCriteria; // Custom LogGroupSelectionCriteria from string public static fromString(selectionCriteria: string): LogGroupSelectionCriteria { return new LogGroupSelectionCriteria(selectionCriteria); @@ -332,8 +300,9 @@ No, this is a new feature that adds functionality without modifying existing API ### What alternative solutions did you consider? -Keeping a simple string input for all fields without adding new types, but still keeping parameters unnested and flat. However, many customers are -likely not familiar with available options or the [OAM LinkFilter syntax](https://docs.aws.amazon.com/AWSCloudFormation/latest/TemplateReference/aws-properties-oam-link-linkfilter.html). +Keeping a simple string input for all fields without adding new types, but still keeping parameters unnested and flat. +However, many customers are likely not familiar with available options. Having classes/enums can help customers see +what options are available and avoid mistakes in configuring their rules. ### What are the drawbacks of this solution? From 9304802766a4885964a1d7a52a028ae08283e0fe Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Tue, 20 Jan 2026 23:55:18 +0000 Subject: [PATCH 6/9] Update comments --- text/0859-organization-centralization-rule.md | 30 ++++++++++++++----- 1 file changed, 22 insertions(+), 8 deletions(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index b68513c79..da3352994 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -111,10 +111,12 @@ centralized log management practices. interface ICentralizationRuleBase extends IResource, ITaggableV2 { /** * The name of the centralization rule. + * + * @attribute */ readonly ruleName: string; /** - * The arn of the centralization rule. + * The ARN of the centralization rule. * * @attribute */ @@ -177,8 +179,8 @@ interface BaseCentralizationRuleProps { */ readonly destinationLogEncryptionStrategy?: LogEncryptionStrategy; /** - * Conflict resolution strategy for centralization if the encryption strategy is set to CUSTOMER_MANAGED and the destination log group is - * encrypted with an AWS_OWNED KMS Key. + * Conflict resolution strategy for centralization if the encryption strategy is set to CUSTOMER_MANAGED and + * the destination log group is encrypted with an AWS_OWNED KMS Key. * ALLOW lets centralization go through while SKIP prevents centralization into the destination log group. * @default - Skip centralization for conflicting encryption. */ @@ -197,7 +199,7 @@ interface BaseCentralizationRuleProps { * KMS Key ARN belonging to the primary destination account and backup region, to encrypt newly created central log groups in the backup destination. * Only applied when destinationBackupRegion is set. * If destinationBackupRegion is set, the backup region KMS key must be specified if destinationLogEncryptionStrategy is CUSTOMER_MANAGED. - * @default - centralization backup destination log groups are not encrypted. + * @default - backup destination log groups are encrypted with an AWS_OWNED KMS key. */ readonly destinationBackupKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account } @@ -214,9 +216,15 @@ interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProp ```typescript export class Scope { - // All accounts in the organization + /** + * All accounts in the organization. + */ public static ALL = new Scope('*'); - // Custom Scope from string + /** + * Create a scope from a string value. + * + * @param scope The scope string (e.g., account ID, OU ID, or '*'). + */ public static fromString(scope: string): Scope { return new Scope(scope); } @@ -227,9 +235,15 @@ export class Scope { * The selection criteria that specifies which source log groups to centralize. */ export class LogGroupSelectionCriteria { - // All LogGroups + /** + * All log groups. + */ public static ALL = new LogGroupSelectionCriteria('*'); - // Custom LogGroupSelectionCriteria from string + /** + * Create a LogGroupSelectionCriteria from a string value. + * + * @param selectionCriteria The selection criteria string. Uses the same format as OAM link filters. + */ public static fromString(selectionCriteria: string): LogGroupSelectionCriteria { return new LogGroupSelectionCriteria(selectionCriteria); } From 239da1eecb8f2701e8c302dcb1bbaeb18896fc3b Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Wed, 21 Jan 2026 20:10:23 +0000 Subject: [PATCH 7/9] Add fromAccountIds + fromOrganizationUnitIds helpers and additional validation --- text/0859-organization-centralization-rule.md | 38 ++++++++++++++----- 1 file changed, 28 insertions(+), 10 deletions(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index da3352994..d16006ad3 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -156,17 +156,13 @@ interface BaseCentralizationRuleProps { /** * The selection criteria that specifies which source log groups to centralize. The selection criteria uses the same format as OAM link filters. */ - readonly sourceLogGroupSelectionCriteria: LogGroupSelectionCriteria; + readonly sourceLogGroupSelectionCriteria?: LogGroupSelectionCriteria; /** * A strategy determining whether to centralize source log groups that are encrypted with customer managed KMS keys (CMK). * ALLOW will consider CMK encrypted source log groups for centralization while SKIP will skip CMK encrypted source log groups from centralization. * @default - Skip centralizing CMK encrypted source log groups. */ readonly sourceEncryptedLogGroupStrategy?: EncryptedLogGroupStrategy; - /** - * The destination account (within the organization) to which the telemetry data should be centralized. - */ - readonly destinationAccount: string; /** * The primary destination region to which telemetry data should be centralized. */ @@ -208,7 +204,11 @@ interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProp /** * The organizational scope from which telemetry data should be centralized, specified using accounts or organizational unit ids. */ - sourceScope: Scope; + readonly sourceScope: Scope; + /** + * The destination account (within the organization) to which the telemetry data should be centralized. + */ + readonly destinationAccount: string; } ``` @@ -217,18 +217,34 @@ interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProp ```typescript export class Scope { /** - * All accounts in the organization. + * All AWS account IDs and AWS Organization Unit IDs in the organization. */ - public static ALL = new Scope('*'); + public static readonly ALL = new Scope('*'); + /** + * Select AWS account IDs in the organization. + * + * @param accountIds A list of AWS account IDs to include in the scope. + */ + public static fromAccountIds(accountIds: string[]): Scope { + return new Scope(`AccountId IN (${accountIds.map(id => `'${id}'`).join(', ')})`); + } + /** + * Select AWS Organization Unit IDs in the organization. + * + * @param organizationUnitIds A list of AWS Organization Unit IDs to include in the scope. + */ + public static fromOrganizationUnitIds(organizationUnitIds: string[]): Scope { + return new Scope(`OrganizationUnitId IN (${organizationUnitIds.map(id => `'${id}'`).join(', ')})`); + } /** * Create a scope from a string value. * - * @param scope The scope string (e.g., account ID, OU ID, or '*'). + * @param scope The scope string. */ public static fromString(scope: string): Scope { return new Scope(scope); } - protected constructor(public readonly scope: string) { } + protected constructor(public readonly scope: string) {} } /** @@ -303,9 +319,11 @@ Validations: - `sourceRegions` should contain valid AWS regions. - `destinationRegion` should be a valid AWS region. - `destinationBackupRegion` should be a valid AWS region. +- `destinationBackupRegion` must not be the same as the `destinationRegion`. - If `destinationLogEncryptionStrategy` is `CUSTOMER_MANAGED`, then - `destinationLogEncryptionKmsKeyArn` must be provided. - If destinationBackupRegion is set, then `destinationBackupKmsKeyArn` must also be provided. +- `sourceLogGroupSelectionCriteria` must be defined. - KMS Key ARNs should follow valid ARN format. ### Is this a breaking change? From 3d1b2d79e7aecc3205986085be964691f8c6c681 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Tue, 27 Jan 2026 18:51:22 +0000 Subject: [PATCH 8/9] Use IKeyRef instead of ARN string --- text/0859-organization-centralization-rule.md | 37 +++++++++++-------- 1 file changed, 21 insertions(+), 16 deletions(-) diff --git a/text/0859-organization-centralization-rule.md b/text/0859-organization-centralization-rule.md index d16006ad3..5517f5e33 100644 --- a/text/0859-organization-centralization-rule.md +++ b/text/0859-organization-centralization-rule.md @@ -54,9 +54,17 @@ new OrganizationCentralizationRule(this, 'OrganizationCentralizationRule', { destinationRegion: 'us-east-1', destinationLogEncryptionStrategy: LogEncryptionStrategy.CUSTOMER_MANAGED, destinationLogEncryptionConflictResolutionStrategy: LogEncryptionConflictResolutionStrategy.ALLOW, - destinationLogEncryptionKmsKeyArn: 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012', + destinationLogEncryptionKmsKey: kms.Key.fromKeyArn( + this, + 'DestinationKey', + 'arn:aws:kms:us-east-1:123456789012:key/12345678-1234-1234-1234-123456789012', + ), destinationBackupRegion: 'us-west-2', - destinationBackupKmsKeyArn: 'arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012', + destinationBackupKmsKey: kms.Key.fromKeyArn( + this, + 'DestinationBackupKey', + 'arn:aws:kms:us-west-2:123456789012:key/12345678-1234-1234-1234-123456789012', + ), }); ``` @@ -145,10 +153,6 @@ class OrganizationCentralizationRule extends CentralizationRuleBase implements I ```typescript interface BaseCentralizationRuleProps { - /** - * The name of the centralization rule. - */ - readonly ruleName: string; /** * The list of source regions from which telemetry data should be centralized. */ @@ -182,22 +186,22 @@ interface BaseCentralizationRuleProps { */ readonly destinationLogEncryptionConflictResolutionStrategy?: LogEncryptionConflictResolutionStrategy; /** - * KMS Key ARN belonging to the primary destination account and region, to encrypt newly created central log groups in the primary destination. + * KMS IKeyRef belonging to the primary destination account and region, to encrypt newly created central log groups in the primary destination. * @default - Log groups are encrypted with an AWS_OWNED KMS key. */ - readonly destinationLogEncryptionKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account + readonly destinationLogEncryptionKmsKey?: IKeyRef; /** * Logs-specific backup destination region within the primary destination account to which log data should be centralized. * @default - no centralization backup destination region is configured. */ readonly destinationBackupRegion?: string; /** - * KMS Key ARN belonging to the primary destination account and backup region, to encrypt newly created central log groups in the backup destination. + * KMS IKeyRef belonging to the primary destination account and backup region, to encrypt newly created central log groups in the backup destination. * Only applied when destinationBackupRegion is set. * If destinationBackupRegion is set, the backup region KMS key must be specified if destinationLogEncryptionStrategy is CUSTOMER_MANAGED. * @default - backup destination log groups are encrypted with an AWS_OWNED KMS key. */ - readonly destinationBackupKmsKeyArn?: string; // explicitly string and not IKey, since the KMS key may not be from the same account + readonly destinationBackupKmsKey?: IKeyRef; } interface OrganizationCentralizationRuleProps extends BaseCentralizationRuleProps { @@ -241,10 +245,10 @@ export class Scope { * * @param scope The scope string. */ - public static fromString(scope: string): Scope { - return new Scope(scope); + public static fromString(scopeString: string): Scope { + return new Scope(scopeString); } - protected constructor(public readonly scope: string) {} + protected constructor(public readonly scopeString: string) {} } /** @@ -321,10 +325,11 @@ Validations: - `destinationBackupRegion` should be a valid AWS region. - `destinationBackupRegion` must not be the same as the `destinationRegion`. - If `destinationLogEncryptionStrategy` is `CUSTOMER_MANAGED`, then -- `destinationLogEncryptionKmsKeyArn` must be provided. -- If destinationBackupRegion is set, then `destinationBackupKmsKeyArn` must also be provided. +- `destinationLogEncryptionKmsKey` must be provided. +- If destinationBackupRegion is set, then `destinationBackupKmsKey` must also be provided. - `sourceLogGroupSelectionCriteria` must be defined. -- KMS Key ARNs should follow valid ARN format. +- KmsKeyArn and EncryptionConflictResolutionStrategy must not be present when EncryptionStrategy is AWS_OWNED +- Both KmsKeyArn and EncryptionConflictResolutionStrategy are required when EncryptionStrategy is CUSTOMER_MANAGED ### Is this a breaking change? From 088b6e16c5a33b7bbe2c667b20ef4d5f5db15ba1 Mon Sep 17 00:00:00 2001 From: Sicheng Jia Date: Tue, 27 Jan 2026 18:59:19 +0000 Subject: [PATCH 9/9] Rerun linter