aws/aws-cdk

TableV2MultiAccountReplica: does not set top-level SSESpecification when using TableEncryptionV2.customerManagedKey(), causing deployment failure

Open

#37.783 aberto em 6 de mai. de 2026

Ver no GitHub
 (5 comments) (0 reactions) (0 assignees)TypeScript (3.530 forks)batch import
@aws-cdk/aws-cloudformationbugeffort/smallgood first issuep2

Métricas do repositório

Stars
 (10.710 stars)
Métricas de merge de PR
 (Mesclagem média 13d 14h) (134 fundiu PRs em 30d)

Description

Describe the bug

When using TableV2MultiAccountReplica with TableEncryptionV2.customerManagedKey(), the generated CloudFormation template is missing the top-level SSESpecification property on the AWS::DynamoDB::GlobalTable resource. This causes CloudFormation to fail with:

Resource handler returned message: "Invalid request provided: ReplicaSSESpecification and SSEType must be null when SSE is set to default."

Regression Issue

  • Select this option if this issue appears to be a regression.

Last Known Working CDK Library Version

No response

Expected Behavior

The TableV2MultiAccountReplica construct should render a top-level SSESpecification with SSEEnabled: true and SSEType: "KMS" when using customer-managed key encryption, matching the behavior of TableV2:

 {
   "Type": "AWS::DynamoDB::GlobalTable",
   "Properties": {
     "TableName": "MyGlobalTable",
     "GlobalTableSourceArn": "arn:aws:dynamodb:us-west-2:111111111111:table/MyGlobalTable",
     "SSESpecification": { /* <=== this */
       "SSEEnabled": true,
       "SSEType": "KMS"
     },
     "Replicas": [{
       "Region": "us-east-2",
       "SSESpecification": {
         "KMSMasterKeyId": "arn:aws:kms:us-east-2:222222222222:key/..."
       }
     }]
   }
 }

Current Behavior

TableV2MultiAccountReplica only sets SSESpecification.KMSMasterKeyId at the replica level, but omits the top-level SSESpecification entirely:

{
 "Type": "AWS::DynamoDB::GlobalTable",
 "Properties": {
   "TableName": "MyGlobalTable",
   "GlobalTableSourceArn": "arn:aws:dynamodb:us-west-2:111111111111:table/MyGlobalTable",
   "Replicas": [{
     "Region": "us-east-2",
     "SSESpecification": {
       "KMSMasterKeyId": "arn:aws:kms:us-east-2:222222222222:key/..."
     }
   }]
 }
}

DDB's CFN validator has a rule that says "all settings must be null if SSE is disabled". This lack of SSESpecification at the top-level is being interpreted as SSEEnabled: false. Because the replicas themselves have encryption info, the validator fails.

This seems to be backed up in the docs for SSESpecification:

Specifies the settings to enable server-side encryption. These settings will be applied to all replicas. If you plan to use customer-managed KMS keys, you must provide a key for each replica using the ReplicaSpecification.ReplicaSSESpecification property.

Reproduction Steps

import * as cdk from 'aws-cdk-lib';
import { Stack } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import {
  AttributeType,
  Billing,
  TableEncryptionV2,
  TableV2,
  TableV2MultiAccountReplica,
} from 'aws-cdk-lib/aws-dynamodb';
import { Key } from 'aws-cdk-lib/aws-kms';

const PRIMARY_ACCOUNT = '111111111111';
const PRIMARY_REGION = 'us-west-2';
const REPLICA_ACCOUNT = '222222222222';
const REPLICA_REGION = 'us-east-2';

class PrimaryTableStack extends Stack {
  public readonly table: TableV2;

  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const kmsKey = new Key(this, 'TableKey', { enableKeyRotation: true });

    this.table = new TableV2(this, 'GlobalTable', {
      tableName: 'MyGlobalTable',
      partitionKey: { name: 'pk', type: AttributeType.STRING },
      billing: Billing.onDemand(),
      encryption: TableEncryptionV2.customerManagedKey(kmsKey),
    });
  }
}

class ReplicaTableStack extends Stack {
  constructor(scope: Construct, id: string, primaryTable: TableV2, props?: cdk.StackProps) {
    super(scope, id, props);

    const kmsKey = new Key(this, 'TableKey', { enableKeyRotation: true });

    // BUG: This generates CloudFormation without top-level SSESpecification
    new TableV2MultiAccountReplica(this, 'GlobalTableReplica', {
      replicaSourceTable: primaryTable,
      encryption: TableEncryptionV2.customerManagedKey(kmsKey),
    });
  }
}

const app = new cdk.App();

const primaryStack = new PrimaryTableStack(app, 'PrimaryTableStack', {
  env: { account: PRIMARY_ACCOUNT, region: PRIMARY_REGION },
});

new ReplicaTableStack(app, 'ReplicaTableStack', primaryStack.table, {
  env: { account: REPLICA_ACCOUNT, region: REPLICA_REGION },
});

app.synth();

Possible Solution

The TableV2MultiAccountReplica doesn't have anything setting sseSpecification. TableV2 in the same file sets it here.

Additional Information/Context

I've been able to mitigate this with an escape hatch:

 const cfnTable = replicaTable.node.defaultChild as CfnGlobalTable;
 cfnTable.addPropertyOverride('SSESpecification', {
   SSEEnabled: true,
   SSEType: 'KMS',
 })

AWS CDK Library version (aws-cdk-lib)

2.241.0

AWS CDK CLI version

2.241.0

Node.js Version

20.x

OS

macOs

Language

TypeScript

Language Version

No response

Other information

No response

Guia do colaborador