-
Notifications
You must be signed in to change notification settings - Fork 4.5k
Description
Describe the bug
v2.177.0 introduced the ability to set up S3 replication. This supports replicating from one source bucket to multiple destination buckets. But as soon as you configure a second source bucket, the stack fails to deploy (synth and diff work fine) with the error: CDKReplicationRole already exists ...
This appears to be caused by the replication feature using a role with a hardcoded name without any checks if a role by that name already exists.
Regression Issue
- Select this option if this issue appears to be a regression.
Last Known Working CDK Version
No response
Expected Behavior
Deployment does not generate any errors and all source buckets are set up with functioning replication.
Current Behavior
During deployment an error occurs:
CDKReplicationRole already exists in stack arn:aws:cloudformation:eu-west-1:xxxxxxxxxxxx:stack/test-BucketsInfraStack/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
Reproduction Steps
#!/usr/bin/env node
import { App } from 'aws-cdk-lib'
import { BucketsStage } from '../lib/BucketsStage'
const app = new App()
new BucketsStage(app, 'test', {})
app.synth()import { Stage, StageProps } from 'aws-cdk-lib'
import { Construct } from 'constructs'
import { BucketsDrStack } from './BucketsDRStack'
import { BucketsInfraStack } from './BucketsInfraStack'
export class BucketsStage extends Stage {
constructor(scope: Construct, id: string, props: StageProps) {
super(scope, id, props)
/**
* Disaster recovery to a different region
*/
const bucketsDrStack = new BucketsDrStack(this, 'BucketsDrStack', {
env: {
account: 'xxxxxxxxxxxx',
region: 'eu-central-1'
},
crossRegionReferences: true,
description: 'Disaster recovery to a different region'
})
/**
* Infra stack sets up the basic and statefull infra
*/
new BucketsInfraStack(this, 'BucketsInfraStack', {
env: {
account: 'xxxxxxxxxxxx',
region: 'eu-west-1'
},
bucketsDrStack,
crossRegionReferences: true,
description: 'Infra stack sets up the basic and statefull infra'
})
}
}import { RemovalPolicy, Stack, StackProps } from 'aws-cdk-lib'
import { BlockPublicAccess, Bucket, BucketEncryption, IBucket } from 'aws-cdk-lib/aws-s3'
import type { Construct } from 'constructs'
export class BucketsDrStack extends Stack {
readonly bucketAReplica: IBucket
readonly bucketBReplica: IBucket
constructor (scope: Construct, id: string, props: StackProps) {
super(scope, id, props)
this.bucketAReplica = new Bucket(this, 'bucketAReplica', {
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
encryption: BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
removalPolicy: RemovalPolicy.DESTROY
})
this.bucketBReplica = new Bucket(this, 'bucketBReplica', {
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
encryption: BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
removalPolicy: RemovalPolicy.DESTROY
})
}
}import {
RemovalPolicy,
Stack,
StackProps
} from 'aws-cdk-lib'
import { BlockPublicAccess, Bucket, BucketEncryption } from 'aws-cdk-lib/aws-s3'
import type { Construct } from 'constructs'
import { BucketsDrStack } from './BucketsDRStack'
export interface OrInfraStackProps extends StackProps {
bucketsDrStack: BucketsDrStack;
}
export class BucketsInfraStack extends Stack {
readonly privateBucket: Bucket
readonly publicBucket: Bucket
constructor(
scope: Construct,
id: string,
props: OrInfraStackProps
) {
super(scope, id, props)
const { bucketsDrStack } = props
// The S3 bucket for the private assets
this.privateBucket = new Bucket(this, 'PrivateBucket', {
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
encryption: BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
replicationRules: [{
deleteMarkerReplication: true,
destination: bucketsDrStack.bucketAReplica,
priority: 1,
}],
removalPolicy: RemovalPolicy.DESTROY
})
// The S3 bucket for the public (accessible through CloudFront) assets
this.publicBucket = new Bucket(this, 'PublicBucket', {
blockPublicAccess: BlockPublicAccess.BLOCK_ALL,
encryption: BucketEncryption.S3_MANAGED,
enforceSSL: true,
versioned: true,
/* uncommenting the next lines will cause the error
replicationRules: [{
deleteMarkerReplication: true,
destination: bucketsDrStack.bucketBReplica,
priority: 1,
}],
*/
removalPolicy: RemovalPolicy.DESTROY
})
}
}Possible Solution
The source bucket should accept an explicit replication role and add permissions to it instead of creating a role.
Additional Information/Context
No response
CDK CLI Version
2.178.1 (build ae342cb)
Framework Version
No response
Node.js Version
v22.13.0
OS
Linux
Language
TypeScript
Language Version
5.7.3
Other information
No response