Skip to content

Commit 0b09e52

Browse files
authored
fix(s3): bucket notifications in owning stack deletes bucket notifications from other stacks (#31091)
### Issue # (if applicable) Closes #30607. ### Reason for this change There's a bug reported in the Github issue that bucket notifications in owing stack will remove all notifications added in imported stack. This is because we treated the bucket as `managed` hence we use bucket notifications in that stack as source of truth. In the `unmanaged` path, we already filtered out external notifications it should handle both scenarios when the bucket is managed or unmanaged. ### Description of changes Always set `Managed` property to false when the feature flag is enabled. Here we introduce a feature flag to prevent it breaking current customers. ### Description of how you validated changes Added unit tests. Integrations test can't validate this change because we need to deploy twice to actually see the change. Also tested manually. ### Checklist - [x] My code adheres to the [CONTRIBUTING GUIDE](https://github.com/aws/aws-cdk/blob/main/CONTRIBUTING.md) and [DESIGN GUIDELINES](https://github.com/aws/aws-cdk/blob/main/docs/DESIGN_GUIDELINES.md) ---- *By submitting this pull request, I confirm that my contribution is made under the terms of the Apache-2.0 license*
1 parent 23fba1c commit 0b09e52

File tree

5 files changed

+82
-3
lines changed

5 files changed

+82
-3
lines changed

packages/aws-cdk-lib/aws-s3/lib/notifications-resource/notifications-resource.ts

+9-1
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { Construct, IConstruct } from 'constructs';
22
import { NotificationsResourceHandler } from './notifications-resource-handler';
33
import * as iam from '../../../aws-iam';
44
import * as cdk from '../../../core';
5+
import * as cxapi from '../../../cx-api';
56
import { Bucket, IBucket, EventType, NotificationKeyFilter } from '../bucket';
67
import { BucketNotificationDestinationType, IBucketNotificationDestination } from '../destination';
78

@@ -124,7 +125,14 @@ export class BucketNotifications extends Construct {
124125
role: this.handlerRole,
125126
});
126127

127-
const managed = this.bucket instanceof Bucket;
128+
let managed = this.bucket instanceof Bucket;
129+
130+
// We should treat buckets as unmanaged because it will not remove notifications added somewhere else
131+
// Ading a feature flag to prevent it brings unexpected changes to customers
132+
// Put it here because we still need to create the permission if it's unmanaged bucket.
133+
if (cdk.FeatureFlags.of(this).isEnabled(cxapi.S3_KEEP_NOTIFICATION_IN_IMPORTED_BUCKET)) {
134+
managed = false;
135+
}
128136

129137
if (!managed) {
130138
handler.addToRolePolicy(new iam.PolicyStatement({

packages/aws-cdk-lib/aws-s3/test/notification.test.ts

+40
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Match, Template } from '../../assertions';
22
import * as iam from '../../aws-iam';
33
import * as cdk from '../../core';
4+
import * as cxapi from '../../cx-api';
45
import * as s3 from '../lib';
56

67
describe('notification', () => {
@@ -226,6 +227,45 @@ describe('notification', () => {
226227
},
227228
});
228229
});
230+
231+
test('Notification custom resource uses always treat bucket as unmanaged', () => {
232+
// GIVEN
233+
const stack = new cdk.Stack();
234+
235+
stack.node.setContext(cxapi.S3_KEEP_NOTIFICATION_IN_IMPORTED_BUCKET, true);
236+
237+
// WHEN
238+
new s3.Bucket(stack, 'MyBucket', {
239+
eventBridgeEnabled: true,
240+
});
241+
242+
// THEN
243+
Template.fromStack(stack).resourceCountIs('AWS::S3::Bucket', 1);
244+
Template.fromStack(stack).hasResourceProperties('Custom::S3BucketNotifications', {
245+
NotificationConfiguration: {
246+
EventBridgeConfiguration: {},
247+
},
248+
Managed: false,
249+
});
250+
Template.fromStack(stack).hasResourceProperties('AWS::IAM::Policy', {
251+
PolicyDocument: {
252+
Statement: [
253+
{
254+
Action: 's3:PutBucketNotification',
255+
Effect: 'Allow',
256+
Resource: '*',
257+
},
258+
{
259+
Action: 's3:GetBucketNotification',
260+
Effect: 'Allow',
261+
Resource: '*',
262+
},
263+
],
264+
Version: '2012-10-17',
265+
},
266+
});
267+
});
268+
229269
test('check notifications handler runtime version', () => {
230270
const stack = new cdk.Stack();
231271

packages/aws-cdk-lib/cx-api/FEATURE_FLAGS.md

+17
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ Flags come in three types:
7171
| [@aws-cdk/pipelines:reduceAssetRoleTrustScope](#aws-cdkpipelinesreduceassetroletrustscope) | Remove the root account principal from PipelineAssetsFileRole trust policy | 2.141.0 | (default) |
7272
| [@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm](#aws-cdkaws-ecsremovedefaultdeploymentalarm) | When enabled, remove default deployment alarm settings | 2.143.0 | (default) |
7373
| [@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault](#aws-cdkcustom-resourceslogapiresponsedatapropertytruedefault) | When enabled, the custom resource used for `AwsCustomResource` will configure the `logApiResponseData` property as true by default | 2.145.0 | (fix) |
74+
| [@aws-cdk/aws-s3:keepNotificationInImportedBucket](#aws-cdkaws-s3keepnotificationinimportedbucket) | When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack. | V2NEXT | (fix) |
7475

7576
<!-- END table -->
7677

@@ -1338,4 +1339,20 @@ property from the event object.
13381339
| 2.145.0 | `false` | `false` |
13391340

13401341

1342+
### @aws-cdk/aws-s3:keepNotificationInImportedBucket
1343+
1344+
*When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack.* (fix)
1345+
1346+
Currently, adding notifications to a bucket where it was created by ourselves will override notification added where it is imported.
1347+
1348+
When this feature flag is enabled, adding notifications to a bucket in the current stack will only update notification defined in this stack.
1349+
Other notifications that are not managed by this stack will be kept.
1350+
1351+
1352+
| Since | Default | Recommended |
1353+
| ----- | ----- | ----- |
1354+
| (not in v1) | | |
1355+
| V2NEXT | `false` | `false` |
1356+
1357+
13411358
<!-- END details -->

packages/aws-cdk-lib/cx-api/lib/features.ts

+15
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@ export const EKS_NODEGROUP_NAME = '@aws-cdk/aws-eks:nodegroupNameAttribute';
105105
export const EBS_DEFAULT_GP3 = '@aws-cdk/aws-ec2:ebsDefaultGp3Volume';
106106
export const ECS_REMOVE_DEFAULT_DEPLOYMENT_ALARM = '@aws-cdk/aws-ecs:removeDefaultDeploymentAlarm';
107107
export const LOG_API_RESPONSE_DATA_PROPERTY_TRUE_DEFAULT = '@aws-cdk/custom-resources:logApiResponseDataPropertyTrueDefault';
108+
export const S3_KEEP_NOTIFICATION_IN_IMPORTED_BUCKET = '@aws-cdk/aws-s3:keepNotificationInImportedBucket';
108109

109110
export const FLAGS: Record<string, FlagInfo> = {
110111
//////////////////////////////////////////////////////////////////////
@@ -1092,6 +1093,20 @@ export const FLAGS: Record<string, FlagInfo> = {
10921093
introducedIn: { v2: '2.145.0' },
10931094
recommendedValue: false,
10941095
},
1096+
1097+
//////////////////////////////////////////////////////////////////////
1098+
[S3_KEEP_NOTIFICATION_IN_IMPORTED_BUCKET]: {
1099+
type: FlagType.BugFix,
1100+
summary: 'When enabled, Adding notifications to a bucket in the current stack will not remove notification from imported stack.',
1101+
detailsMd: `
1102+
Currently, adding notifications to a bucket where it was created by ourselves will override notification added where it is imported.
1103+
1104+
When this feature flag is enabled, adding notifications to a bucket in the current stack will only update notification defined in this stack.
1105+
Other notifications that are not managed by this stack will be kept.
1106+
`,
1107+
introducedIn: { v2: 'V2NEXT' },
1108+
recommendedValue: false,
1109+
},
10951110
};
10961111

10971112
const CURRENT_MV = 'v2';

packages/aws-cdk-lib/cx-api/test/features.test.ts

+1-2
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,8 @@ test('feature flag defaults may not be changed anymore', () => {
3737
[feats.EFS_DEFAULT_ENCRYPTION_AT_REST]: true,
3838
[feats.LAMBDA_RECOGNIZE_VERSION_PROPS]: true,
3939
[feats.CLOUDFRONT_DEFAULT_SECURITY_POLICY_TLS_V1_2_2021]: true,
40-
// Add new disabling feature flags below this line
4140
[feats.PIPELINE_REDUCE_ASSET_ROLE_TRUST_SCOPE]: true,
42-
41+
// Add new disabling feature flags below this line
4342
});
4443
});
4544

0 commit comments

Comments
 (0)