@mavogel/awscdk-rootmail 0.0.336 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.codegraph/.gitignore +5 -0
- package/.jsii +460 -8
- package/CLAUDE.md +1 -1
- package/README.md +6 -1
- package/docs/plans/2026-08-09-bump-mvc-projen-cdk-nag-v3.md +199 -0
- package/integ-tests/integ.rootmail-custom-santa.ts +2 -2
- package/integ-tests/integ.rootmail-filter-subject.ts +2 -2
- package/integ-tests/integ.rootmail.ts +2 -2
- package/lib/hosted-zone-dkim-propagation.js +46 -15
- package/lib/hosted-zone-dkim-verification-records.js +47 -12
- package/lib/rootmail-autowire-dns.js +47 -15
- package/lib/rootmail.js +13 -16
- package/lib/ses-receipt-ruleset-activation.js +53 -15
- package/lib/ses-receive.js +12 -12
- package/node_modules/cdk-nag/.jsii +6331 -2945
- package/node_modules/cdk-nag/.jsii.tabl.json +1 -1
- package/node_modules/cdk-nag/API.md +490 -1778
- package/node_modules/cdk-nag/MIGRATION.md +239 -0
- package/node_modules/cdk-nag/README.md +88 -513
- package/node_modules/cdk-nag/lib/index.d.ts +0 -3
- package/node_modules/cdk-nag/lib/index.js +1 -4
- package/node_modules/cdk-nag/lib/nag-logger.d.ts +5 -145
- package/node_modules/cdk-nag/lib/nag-logger.js +4 -199
- package/node_modules/cdk-nag/lib/nag-pack.d.ts +57 -44
- package/node_modules/cdk-nag/lib/nag-pack.js +140 -114
- package/node_modules/cdk-nag/lib/nag-rules.d.ts +0 -2
- package/node_modules/cdk-nag/lib/nag-rules.js +3 -5
- package/node_modules/cdk-nag/lib/packs/aws-solutions.d.ts +4 -15
- package/node_modules/cdk-nag/lib/packs/aws-solutions.js +21 -40
- package/node_modules/cdk-nag/lib/packs/hipaa-security.d.ts +4 -2
- package/node_modules/cdk-nag/lib/packs/hipaa-security.js +31 -37
- package/node_modules/cdk-nag/lib/packs/nist-800-53-r4.d.ts +4 -2
- package/node_modules/cdk-nag/lib/packs/nist-800-53-r4.js +29 -35
- package/node_modules/cdk-nag/lib/packs/nist-800-53-r5.d.ts +4 -2
- package/node_modules/cdk-nag/lib/packs/nist-800-53-r5.js +30 -36
- package/node_modules/cdk-nag/lib/packs/pci-dss-321.d.ts +4 -2
- package/node_modules/cdk-nag/lib/packs/pci-dss-321.js +29 -35
- package/node_modules/cdk-nag/lib/packs/serverless.d.ts +4 -2
- package/node_modules/cdk-nag/lib/packs/serverless.js +14 -20
- package/node_modules/cdk-nag/lib/rules/ec2/EC2IMDSv2Enabled.js +5 -1
- package/node_modules/cdk-nag/package.json +5 -5
- package/package.json +16 -17
- package/node_modules/cdk-nag/lib/ignore-suppression-conditions.d.ts +0 -59
- package/node_modules/cdk-nag/lib/ignore-suppression-conditions.js +0 -97
- package/node_modules/cdk-nag/lib/models/nag-suppression.d.ts +0 -30
- package/node_modules/cdk-nag/lib/models/nag-suppression.js +0 -7
- package/node_modules/cdk-nag/lib/nag-suppressions.d.ts +0 -30
- package/node_modules/cdk-nag/lib/nag-suppressions.js +0 -96
- package/node_modules/cdk-nag/lib/utils/nag-suppression-helper.d.ts +0 -20
- package/node_modules/cdk-nag/lib/utils/nag-suppression-helper.js +0 -119
|
@@ -41,33 +41,35 @@ For a full list of options See `NagPackProps` in the [API.md](./API.md#struct-na
|
|
|
41
41
|
<details>
|
|
42
42
|
<summary>Including in an application</summary>
|
|
43
43
|
|
|
44
|
-
```
|
|
45
|
-
import { App,
|
|
46
|
-
import {
|
|
47
|
-
|
|
44
|
+
```ts nofixture
|
|
45
|
+
import { App, Validations } from 'aws-cdk-lib';
|
|
46
|
+
import { AwsSolutionsChecks, NIST80053R5Checks } from 'cdk-nag';
|
|
47
|
+
|
|
48
|
+
declare const CdkTestStack: any;
|
|
48
49
|
|
|
49
50
|
const app = new App();
|
|
50
51
|
new CdkTestStack(app, 'CdkNagDemo');
|
|
51
52
|
// Simple rule informational messages using the AWS Solutions Rule pack
|
|
52
|
-
|
|
53
|
+
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
|
|
53
54
|
// Multiple rule packs can be run against the same app
|
|
54
|
-
|
|
55
|
+
Validations.of(app).addPlugins(new NIST80053R5Checks(app));
|
|
55
56
|
// Additional explanations on the purpose of triggered rules
|
|
56
|
-
//
|
|
57
|
+
// Validations.of(app).addPlugins(new AwsSolutionsChecks(app, { verbose: true }));
|
|
57
58
|
```
|
|
58
59
|
|
|
59
60
|
</details>
|
|
60
61
|
|
|
61
|
-
##
|
|
62
|
+
## Acknowledging a Rule
|
|
63
|
+
|
|
64
|
+
Use CDK's native `Validations.of()` API to acknowledge (suppress) rule violations on specific constructs.
|
|
62
65
|
|
|
63
66
|
<details>
|
|
64
|
-
<summary>Example 1)
|
|
67
|
+
<summary>Example 1) Acknowledging a rule on a construct</summary>
|
|
65
68
|
|
|
66
|
-
```
|
|
69
|
+
```ts nofixture
|
|
67
70
|
import { SecurityGroup, Vpc, Peer, Port } from 'aws-cdk-lib/aws-ec2';
|
|
68
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
71
|
+
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
|
|
69
72
|
import { Construct } from 'constructs';
|
|
70
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
71
73
|
|
|
72
74
|
export class CdkTestStack extends Stack {
|
|
73
75
|
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
@@ -76,36 +78,10 @@ export class CdkTestStack extends Stack {
|
|
|
76
78
|
vpc: new Vpc(this, 'vpc'),
|
|
77
79
|
});
|
|
78
80
|
test.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
}
|
|
84
|
-
```
|
|
85
|
-
|
|
86
|
-
</details>
|
|
87
|
-
|
|
88
|
-
<details>
|
|
89
|
-
<summary>Example 2) On Multiple Constructs</summary>
|
|
90
|
-
|
|
91
|
-
```typescript
|
|
92
|
-
import { SecurityGroup, Vpc, Peer, Port } from 'aws-cdk-lib/aws-ec2';
|
|
93
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
94
|
-
import { Construct } from 'constructs';
|
|
95
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
96
|
-
|
|
97
|
-
export class CdkTestStack extends Stack {
|
|
98
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
99
|
-
super(scope, id, props);
|
|
100
|
-
const vpc = new Vpc(this, 'vpc');
|
|
101
|
-
const test1 = new SecurityGroup(this, 'test', { vpc });
|
|
102
|
-
test1.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
|
|
103
|
-
const test2 = new SecurityGroup(this, 'test', { vpc });
|
|
104
|
-
test2.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
|
|
105
|
-
NagSuppressions.addResourceSuppressions(
|
|
106
|
-
[test1, test2],
|
|
107
|
-
[{ id: 'AwsSolutions-EC23', reason: 'lorem ipsum' }]
|
|
108
|
-
);
|
|
81
|
+
Validations.of(test).acknowledge({
|
|
82
|
+
id: 'AwsSolutions-EC23',
|
|
83
|
+
reason: 'This security group is used for internal testing only.',
|
|
84
|
+
});
|
|
109
85
|
}
|
|
110
86
|
}
|
|
111
87
|
```
|
|
@@ -113,322 +89,59 @@ export class CdkTestStack extends Stack {
|
|
|
113
89
|
</details>
|
|
114
90
|
|
|
115
91
|
<details>
|
|
116
|
-
<summary>Example
|
|
92
|
+
<summary>Example 2) Acknowledging a rule on a stack</summary>
|
|
117
93
|
|
|
118
|
-
```
|
|
119
|
-
import {
|
|
120
|
-
import {
|
|
121
|
-
import { Construct } from 'constructs';
|
|
122
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
123
|
-
|
|
124
|
-
export class CdkTestStack extends Stack {
|
|
125
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
126
|
-
super(scope, id, props);
|
|
127
|
-
const user = new User(this, 'rUser');
|
|
128
|
-
user.addToPolicy(
|
|
129
|
-
new PolicyStatement({
|
|
130
|
-
actions: ['s3:PutObject'],
|
|
131
|
-
resources: ['arn:aws:s3:::bucket_name/*'],
|
|
132
|
-
})
|
|
133
|
-
);
|
|
134
|
-
// Enable adding suppressions to child constructs
|
|
135
|
-
NagSuppressions.addResourceSuppressions(
|
|
136
|
-
user,
|
|
137
|
-
[
|
|
138
|
-
{
|
|
139
|
-
id: 'AwsSolutions-IAM5',
|
|
140
|
-
reason: 'lorem ipsum',
|
|
141
|
-
appliesTo: ['Resource::arn:aws:s3:::bucket_name/*'], // optional
|
|
142
|
-
},
|
|
143
|
-
],
|
|
144
|
-
true
|
|
145
|
-
);
|
|
146
|
-
}
|
|
147
|
-
}
|
|
148
|
-
```
|
|
149
|
-
|
|
150
|
-
</details>
|
|
151
|
-
|
|
152
|
-
<details>
|
|
153
|
-
<summary>Example 4) Stack Level </summary>
|
|
94
|
+
```ts nofixture
|
|
95
|
+
import { App, Validations } from 'aws-cdk-lib';
|
|
96
|
+
import { AwsSolutionsChecks } from 'cdk-nag';
|
|
154
97
|
|
|
155
|
-
|
|
156
|
-
import { App, Aspects } from 'aws-cdk-lib';
|
|
157
|
-
import { CdkTestStack } from '../lib/cdk-test-stack';
|
|
158
|
-
import { AwsSolutionsChecks, NagSuppressions } from 'cdk-nag';
|
|
98
|
+
declare const CdkTestStack: any;
|
|
159
99
|
|
|
160
100
|
const app = new App();
|
|
161
101
|
const stack = new CdkTestStack(app, 'CdkNagDemo');
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
102
|
+
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
|
|
103
|
+
Validations.of(stack).acknowledge({
|
|
104
|
+
id: 'AwsSolutions-EC23',
|
|
105
|
+
reason: 'All security groups in this stack are internal only.',
|
|
106
|
+
});
|
|
166
107
|
```
|
|
167
108
|
|
|
168
109
|
</details>
|
|
169
110
|
|
|
170
111
|
<details>
|
|
171
|
-
<summary>Example
|
|
172
|
-
|
|
173
|
-
If you received the following error on synth/deploy
|
|
174
|
-
|
|
175
|
-
```bash
|
|
176
|
-
[Error at /StackName/Custom::CDKBucketDeployment8675309/ServiceRole/Resource] AwsSolutions-IAM4: The IAM user, role, or group uses AWS managed policies
|
|
177
|
-
```
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
180
|
-
import { Bucket } from 'aws-cdk-lib/aws-s3';
|
|
181
|
-
import { BucketDeployment } from 'aws-cdk-lib/aws-s3-deployment';
|
|
182
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
183
|
-
import { Construct } from 'constructs';
|
|
184
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
185
|
-
|
|
186
|
-
export class CdkTestStack extends Stack {
|
|
187
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
188
|
-
super(scope, id, props);
|
|
189
|
-
new BucketDeployment(this, 'rDeployment', {
|
|
190
|
-
sources: [],
|
|
191
|
-
destinationBucket: Bucket.fromBucketName(this, 'rBucket', 'foo'),
|
|
192
|
-
});
|
|
193
|
-
NagSuppressions.addResourceSuppressionsByPath(
|
|
194
|
-
this,
|
|
195
|
-
'/StackName/Custom::CDKBucketDeployment8675309/ServiceRole/Resource',
|
|
196
|
-
[{ id: 'AwsSolutions-IAM4', reason: 'at least 10 characters' }]
|
|
197
|
-
);
|
|
198
|
-
}
|
|
199
|
-
}
|
|
200
|
-
```
|
|
112
|
+
<summary>Example 3) Acknowledging a specific finding</summary>
|
|
201
113
|
|
|
202
|
-
|
|
114
|
+
Certain rules report multiple findings per resource (e.g., IAM wildcard permissions). Each finding has its own ID in the format `RuleId[FindingId]`.
|
|
203
115
|
|
|
204
|
-
|
|
205
|
-
<summary>Example 6) Granular Suppressions of findings</summary>
|
|
206
|
-
|
|
207
|
-
Certain rules support granular suppressions of `findings`. If you received the following errors on synth/deploy
|
|
116
|
+
If you received the following errors on synth/deploy:
|
|
208
117
|
|
|
209
118
|
```bash
|
|
210
|
-
[Error at /StackName/
|
|
211
|
-
[Error at /StackName/
|
|
212
|
-
[Error at /StackName/rSecondUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Action::s3:*]: The IAM entity contains wildcard permissions and does not have a cdk-nag rule suppression with evidence for those permission.
|
|
213
|
-
[Error at /StackName/rSecondUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Resource::*]: The IAM entity contains wildcard permissions and does not have a cdk-nag rule suppression with evidence for those permission.
|
|
119
|
+
[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Action::s3:*]: The IAM entity contains wildcard permissions.
|
|
120
|
+
[Error at /StackName/rUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Resource::*]: The IAM entity contains wildcard permissions.
|
|
214
121
|
```
|
|
215
122
|
|
|
216
|
-
|
|
123
|
+
You can acknowledge a specific finding:
|
|
217
124
|
|
|
218
|
-
```
|
|
219
|
-
import { User } from 'aws-cdk-lib/aws-iam';
|
|
220
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
125
|
+
```ts nofixture
|
|
126
|
+
import { User, PolicyStatement } from 'aws-cdk-lib/aws-iam';
|
|
127
|
+
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
|
|
221
128
|
import { Construct } from 'constructs';
|
|
222
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
223
129
|
|
|
224
130
|
export class CdkTestStack extends Stack {
|
|
225
131
|
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
226
132
|
super(scope, id, props);
|
|
227
|
-
const
|
|
228
|
-
|
|
229
|
-
new PolicyStatement({
|
|
230
|
-
actions: ['s3:*'],
|
|
231
|
-
resources: ['*'],
|
|
232
|
-
})
|
|
233
|
-
);
|
|
234
|
-
const secondUser = new User(this, 'rSecondUser');
|
|
235
|
-
secondUser.addToPolicy(
|
|
133
|
+
const user = new User(this, 'rUser');
|
|
134
|
+
user.addToPolicy(
|
|
236
135
|
new PolicyStatement({
|
|
237
136
|
actions: ['s3:*'],
|
|
238
137
|
resources: ['*'],
|
|
239
138
|
})
|
|
240
139
|
);
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
resources: [`arn:aws:sqs:${this.region}:${this.account}:*`],
|
|
246
|
-
})
|
|
247
|
-
);
|
|
248
|
-
NagSuppressions.addResourceSuppressions(
|
|
249
|
-
firstUser,
|
|
250
|
-
[
|
|
251
|
-
{
|
|
252
|
-
id: 'AwsSolutions-IAM5',
|
|
253
|
-
reason:
|
|
254
|
-
"Only suppress AwsSolutions-IAM5 's3:*' finding on First User.",
|
|
255
|
-
appliesTo: ['Action::s3:*'],
|
|
256
|
-
},
|
|
257
|
-
],
|
|
258
|
-
true
|
|
259
|
-
);
|
|
260
|
-
NagSuppressions.addResourceSuppressions(
|
|
261
|
-
secondUser,
|
|
262
|
-
[
|
|
263
|
-
{
|
|
264
|
-
id: 'AwsSolutions-IAM5',
|
|
265
|
-
reason: 'Suppress all AwsSolutions-IAM5 findings on Second User.',
|
|
266
|
-
},
|
|
267
|
-
],
|
|
268
|
-
true
|
|
269
|
-
);
|
|
270
|
-
NagSuppressions.addResourceSuppressions(
|
|
271
|
-
thirdUser,
|
|
272
|
-
[
|
|
273
|
-
{
|
|
274
|
-
id: 'AwsSolutions-IAM5',
|
|
275
|
-
reason: 'Suppress AwsSolutions-IAM5 on the SQS resource.',
|
|
276
|
-
appliesTo: [
|
|
277
|
-
{
|
|
278
|
-
regex: '/^Resource::arn:aws:sqs:(.*):\\*$/g',
|
|
279
|
-
},
|
|
280
|
-
],
|
|
281
|
-
},
|
|
282
|
-
],
|
|
283
|
-
true
|
|
284
|
-
);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
You would see the following error on synth/deploy
|
|
290
|
-
|
|
291
|
-
```bash
|
|
292
|
-
[Error at /StackName/rFirstUser/DefaultPolicy/Resource] AwsSolutions-IAM5[Resource::*]: The IAM entity contains wildcard permissions and does not have a cdk-nag rule suppression with evidence for those permission.
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
</details>
|
|
296
|
-
|
|
297
|
-
## Suppressing Rule Validation Failures
|
|
298
|
-
|
|
299
|
-
When a rule validation fails it is handled similarly to a rule violation, and can be suppressed in the same manner. The `ID` for a rule failure is `CdkNagValidationFailure`.
|
|
300
|
-
|
|
301
|
-
If a rule is suppressed in a non-granular manner (i.e. `appliesTo` is not set, see example 1 above) then validation failures on that rule are also suppressed.
|
|
302
|
-
|
|
303
|
-
Validation failure suppression respects any applied [Suppression Ignore Conditions](#conditionally-ignoring-suppressions)
|
|
304
|
-
|
|
305
|
-
<details>
|
|
306
|
-
<summary>Example 1) Suppress all Validation Failures on a Resource</summary>
|
|
307
|
-
|
|
308
|
-
```typescript
|
|
309
|
-
import { SecurityGroup, Vpc, Peer, Port } from 'aws-cdk-lib/aws-ec2';
|
|
310
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
311
|
-
import { Construct } from 'constructs';
|
|
312
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
313
|
-
|
|
314
|
-
export class CdkTestStack extends Stack {
|
|
315
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
316
|
-
super(scope, id, props);
|
|
317
|
-
const test = new SecurityGroup(this, 'test', {
|
|
318
|
-
vpc: new Vpc(this, 'vpc'),
|
|
140
|
+
// Only acknowledge the s3:* action — Resource::* still triggers
|
|
141
|
+
Validations.of(user).acknowledge({
|
|
142
|
+
id: 'AwsSolutions-IAM5[Action::s3:*]',
|
|
143
|
+
reason: 'Need s3:* for cross-account replication.',
|
|
319
144
|
});
|
|
320
|
-
test.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
|
|
321
|
-
NagSuppressions.addResourceSuppressions(test, [
|
|
322
|
-
{ id: 'CdkNagValidationFailure', reason: 'lorem ipsum' },
|
|
323
|
-
]);
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
```
|
|
327
|
-
|
|
328
|
-
</details>
|
|
329
|
-
|
|
330
|
-
<details>
|
|
331
|
-
<summary>Example 2) Granular Suppression of Validation Failures</summary>
|
|
332
|
-
Validation failures can be suppressed for individual rules by using `appliesTo` to list the desired rules
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
import { SecurityGroup, Vpc, Peer, Port } from 'aws-cdk-lib/aws-ec2';
|
|
336
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
337
|
-
import { Construct } from 'constructs';
|
|
338
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
339
|
-
|
|
340
|
-
export class CdkTestStack extends Stack {
|
|
341
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
342
|
-
super(scope, id, props);
|
|
343
|
-
const test = new SecurityGroup(this, 'test', {
|
|
344
|
-
vpc: new Vpc(this, 'vpc'),
|
|
345
|
-
});
|
|
346
|
-
test.addIngressRule(Peer.anyIpv4(), Port.allTraffic());
|
|
347
|
-
NagSuppressions.addResourceSuppressions(test, [
|
|
348
|
-
{
|
|
349
|
-
id: 'CdkNagValidationFailure',
|
|
350
|
-
reason: 'lorem ipsum',
|
|
351
|
-
appliesTo: ['AwsSolutions-L1'],
|
|
352
|
-
},
|
|
353
|
-
]);
|
|
354
|
-
}
|
|
355
|
-
}
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
</details>
|
|
359
|
-
|
|
360
|
-
## Suppressing `aws-cdk-lib/pipelines` Violations
|
|
361
|
-
|
|
362
|
-
The [aws-cdk-lib/pipelines.CodePipeline](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.pipelines.CodePipeline.html) construct and its child constructs are not guaranteed to be "Visited" by `Aspects`, as they are not added during the "Construction" phase of the [cdk lifecycle](https://docs.aws.amazon.com/cdk/v2/guide/apps.html#lifecycle). Because of this behavior, you may experience problems such as rule violations not appearing or the inability to suppress violations on these constructs.
|
|
363
|
-
|
|
364
|
-
You can remediate these rule violation and suppression problems by forcing the pipeline construct creation forward by calling `.buildPipeline()` on your `CodePipeline` object. Otherwise you may see errors such as:
|
|
365
|
-
|
|
366
|
-
```
|
|
367
|
-
Error: Suppression path "/this/construct/path" did not match any resource. This can occur when a resource does not exist or if a suppression is applied before a resource is created.
|
|
368
|
-
```
|
|
369
|
-
|
|
370
|
-
See [this issue](https://github.com/aws/aws-cdk/issues/18440) for more information.
|
|
371
|
-
|
|
372
|
-
<details>
|
|
373
|
-
<summary>Example) Suppressing Violations in Pipelines</summary>
|
|
374
|
-
|
|
375
|
-
`example-app.ts`
|
|
376
|
-
|
|
377
|
-
```ts
|
|
378
|
-
import { App, Aspects } from 'aws-cdk-lib';
|
|
379
|
-
import { AwsSolutionsChecks } from 'cdk-nag';
|
|
380
|
-
import { ExamplePipeline } from '../lib/example-pipeline';
|
|
381
|
-
|
|
382
|
-
const app = new App();
|
|
383
|
-
new ExamplePipeline(app, 'example-cdk-pipeline');
|
|
384
|
-
Aspects.of(app).add(new AwsSolutionsChecks({ verbose: true }));
|
|
385
|
-
app.synth();
|
|
386
|
-
```
|
|
387
|
-
|
|
388
|
-
`example-pipeline.ts`
|
|
389
|
-
|
|
390
|
-
```ts
|
|
391
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
392
|
-
import { Repository } from 'aws-cdk-lib/aws-codecommit';
|
|
393
|
-
import {
|
|
394
|
-
CodePipeline,
|
|
395
|
-
CodePipelineSource,
|
|
396
|
-
ShellStep,
|
|
397
|
-
} from 'aws-cdk-lib/pipelines';
|
|
398
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
399
|
-
import { Construct } from 'constructs';
|
|
400
|
-
|
|
401
|
-
export class ExamplePipeline extends Stack {
|
|
402
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
403
|
-
super(scope, id, props);
|
|
404
|
-
|
|
405
|
-
const exampleSynth = new ShellStep('ExampleSynth', {
|
|
406
|
-
commands: ['yarn build --frozen-lockfile'],
|
|
407
|
-
input: CodePipelineSource.codeCommit(
|
|
408
|
-
new Repository(this, 'ExampleRepo', { repositoryName: 'ExampleRepo' }),
|
|
409
|
-
'main'
|
|
410
|
-
),
|
|
411
|
-
});
|
|
412
|
-
|
|
413
|
-
const ExamplePipeline = new CodePipeline(this, 'ExamplePipeline', {
|
|
414
|
-
synth: exampleSynth,
|
|
415
|
-
});
|
|
416
|
-
|
|
417
|
-
// Force the pipeline construct creation forward before applying suppressions.
|
|
418
|
-
// @See https://github.com/aws/aws-cdk/issues/18440
|
|
419
|
-
ExamplePipeline.buildPipeline();
|
|
420
|
-
|
|
421
|
-
// The path suppression will error if you comment out "ExamplePipeline.buildPipeline();""
|
|
422
|
-
NagSuppressions.addResourceSuppressionsByPath(
|
|
423
|
-
this,
|
|
424
|
-
'/example-cdk-pipeline/ExamplePipeline/Pipeline/ArtifactsBucket/Resource',
|
|
425
|
-
[
|
|
426
|
-
{
|
|
427
|
-
id: 'AwsSolutions-S1',
|
|
428
|
-
reason: 'Because I said so',
|
|
429
|
-
},
|
|
430
|
-
]
|
|
431
|
-
);
|
|
432
145
|
}
|
|
433
146
|
}
|
|
434
147
|
```
|
|
@@ -437,12 +150,12 @@ export class ExamplePipeline extends Stack {
|
|
|
437
150
|
|
|
438
151
|
## Rules and Property Overrides
|
|
439
152
|
|
|
440
|
-
In some cases L2 Constructs do not have a native option to remediate an issue and must be fixed via [Raw Overrides](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_raw). Since raw overrides take place after template synthesis these fixes are not caught by cdk-nag. In this case you should remediate the issue and
|
|
153
|
+
In some cases L2 Constructs do not have a native option to remediate an issue and must be fixed via [Raw Overrides](https://docs.aws.amazon.com/cdk/latest/guide/cfn_layer.html#cfn_layer_raw). Since raw overrides take place after template synthesis these fixes are not caught by cdk-nag. In this case you should remediate the issue and acknowledge the rule.
|
|
441
154
|
|
|
442
155
|
<details>
|
|
443
156
|
<summary>Example) Property Overrides</summary>
|
|
444
157
|
|
|
445
|
-
```ts
|
|
158
|
+
```ts nofixture
|
|
446
159
|
import {
|
|
447
160
|
Instance,
|
|
448
161
|
InstanceType,
|
|
@@ -451,9 +164,8 @@ import {
|
|
|
451
164
|
Vpc,
|
|
452
165
|
CfnInstance,
|
|
453
166
|
} from 'aws-cdk-lib/aws-ec2';
|
|
454
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
167
|
+
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
|
|
455
168
|
import { Construct } from 'constructs';
|
|
456
|
-
import { NagSuppressions } from 'cdk-nag';
|
|
457
169
|
|
|
458
170
|
export class CdkTestStack extends Stack {
|
|
459
171
|
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
@@ -465,233 +177,96 @@ export class CdkTestStack extends Stack {
|
|
|
465
177
|
});
|
|
466
178
|
const cfnIns = instance.node.defaultChild as CfnInstance;
|
|
467
179
|
cfnIns.addPropertyOverride('DisableApiTermination', true);
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
},
|
|
473
|
-
]);
|
|
180
|
+
Validations.of(instance).acknowledge({
|
|
181
|
+
id: 'AwsSolutions-EC29',
|
|
182
|
+
reason: 'Remediated through property override.',
|
|
183
|
+
});
|
|
474
184
|
}
|
|
475
185
|
}
|
|
476
186
|
```
|
|
477
187
|
|
|
478
188
|
</details>
|
|
479
189
|
|
|
480
|
-
##
|
|
481
|
-
|
|
482
|
-
You can optionally create a condition that prevents certain rules from being suppressed. You can create conditions for any variety of reasons. Examples include a condition that always ignores a suppression, a condition that ignores a suppression based on the date, a condition that ignores a suppression based on the reason. You can read [the developer docs](./docs/IgnoreSuppressionConditions.md) for more information on creating your own conditions.
|
|
483
|
-
|
|
484
|
-
<details>
|
|
485
|
-
<summary>Example) Using the pre-built `SuppressionIgnoreErrors` class to ignore suppressions on any `Error` level rules.</summary>
|
|
486
|
-
|
|
487
|
-
```ts
|
|
488
|
-
import { App, Aspects } from 'aws-cdk-lib';
|
|
489
|
-
import { CdkTestStack } from '../lib/cdk-test-stack';
|
|
490
|
-
import { AwsSolutionsChecks, SuppressionIgnoreErrors } from 'cdk-nag';
|
|
491
|
-
|
|
492
|
-
const app = new App();
|
|
493
|
-
new CdkTestStack(app, 'CdkNagDemo');
|
|
494
|
-
// Ignore Suppressions on any errors
|
|
495
|
-
Aspects.of(app).add(
|
|
496
|
-
new AwsSolutionsChecks({
|
|
497
|
-
suppressionIgnoreCondition: new SuppressionIgnoreErrors(),
|
|
498
|
-
})
|
|
499
|
-
);
|
|
500
|
-
```
|
|
501
|
-
|
|
502
|
-
</details>
|
|
503
|
-
|
|
504
|
-
## Customizing Logging
|
|
190
|
+
## Audit Trail: CloudFormation Metadata
|
|
505
191
|
|
|
506
|
-
|
|
192
|
+
By default, cdk-nag writes violations to CDK's `policy-validation-report.json` in the cloud assembly. If you need the v2-compatible `cdk_nag` metadata block in your synthesized CloudFormation templates (for existing compliance tooling), enable `writeSuppressionsToCloudFormation`:
|
|
507
193
|
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
<details>
|
|
511
|
-
<summary>Example) Adding the `ExtremelyHelpfulConsoleLogger` example from the NagLogger docs</summary>
|
|
512
|
-
|
|
513
|
-
```ts
|
|
514
|
-
import { App, Aspects } from 'aws-cdk-lib';
|
|
515
|
-
import { CdkTestStack } from '../lib/cdk-test-stack';
|
|
516
|
-
import { ExtremelyHelpfulConsoleLogger } from './docs/NagLogger';
|
|
194
|
+
```ts nofixture
|
|
195
|
+
import { App, Validations } from 'aws-cdk-lib';
|
|
517
196
|
import { AwsSolutionsChecks } from 'cdk-nag';
|
|
518
197
|
|
|
519
198
|
const app = new App();
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
new AwsSolutionsChecks({
|
|
523
|
-
additionalLoggers: [new ExtremelyHelpfulConsoleLogger()],
|
|
524
|
-
})
|
|
525
|
-
);
|
|
199
|
+
// Writes acknowledged rules into CfnResource Metadata as cdk_nag: { rules_to_suppress: [...] }
|
|
200
|
+
Validations.of(app).addPlugins(new AwsSolutionsChecks(app, { writeSuppressionsToCloudFormation: true }));
|
|
526
201
|
```
|
|
527
202
|
|
|
528
|
-
|
|
203
|
+
This registers a `WriteNagSuppressionsToCloudFormationAspect` that runs during synthesis and copies `Validations.of().acknowledge()` data into the CloudFormation template Metadata section, preserving the same format as cdk-nag v2.
|
|
529
204
|
|
|
530
205
|
## Using on CloudFormation templates
|
|
531
206
|
|
|
532
207
|
You can use cdk-nag on existing CloudFormation templates by using the [cloudformation-include](https://docs.aws.amazon.com/cdk/latest/guide/use-cfn-template.html#use-cfn-template-import) module.
|
|
533
208
|
|
|
534
209
|
<details>
|
|
535
|
-
<summary>Example
|
|
536
|
-
|
|
537
|
-
Sample CloudFormation template with suppression
|
|
538
|
-
|
|
539
|
-
```json
|
|
540
|
-
{
|
|
541
|
-
"Resources": {
|
|
542
|
-
"rBucket": {
|
|
543
|
-
"Type": "AWS::S3::Bucket",
|
|
544
|
-
"Properties": {
|
|
545
|
-
"BucketName": "some-bucket-name"
|
|
546
|
-
},
|
|
547
|
-
"Metadata": {
|
|
548
|
-
"cdk_nag": {
|
|
549
|
-
"rules_to_suppress": [
|
|
550
|
-
{
|
|
551
|
-
"id": "AwsSolutions-S1",
|
|
552
|
-
"reason": "at least 10 characters"
|
|
553
|
-
}
|
|
554
|
-
]
|
|
555
|
-
}
|
|
556
|
-
}
|
|
557
|
-
}
|
|
558
|
-
}
|
|
559
|
-
}
|
|
560
|
-
```
|
|
210
|
+
<summary>Example) CloudFormation template</summary>
|
|
561
211
|
|
|
562
212
|
Sample App
|
|
563
213
|
|
|
564
|
-
```
|
|
565
|
-
import { App,
|
|
566
|
-
import { CdkTestStack } from '../lib/cdk-test-stack';
|
|
214
|
+
```ts nofixture
|
|
215
|
+
import { App, Validations } from 'aws-cdk-lib';
|
|
567
216
|
import { AwsSolutionsChecks } from 'cdk-nag';
|
|
568
217
|
|
|
218
|
+
declare const CdkTestStack: any;
|
|
219
|
+
|
|
569
220
|
const app = new App();
|
|
570
221
|
new CdkTestStack(app, 'CdkNagDemo');
|
|
571
|
-
|
|
222
|
+
Validations.of(app).addPlugins(new AwsSolutionsChecks(app));
|
|
572
223
|
```
|
|
573
224
|
|
|
574
225
|
Sample Stack with imported template
|
|
575
226
|
|
|
576
|
-
```
|
|
227
|
+
```ts nofixture
|
|
577
228
|
import { CfnInclude } from 'aws-cdk-lib/cloudformation-include';
|
|
578
|
-
import {
|
|
579
|
-
import { Stack, StackProps } from 'aws-cdk-lib';
|
|
229
|
+
import { Stack, StackProps, Validations } from 'aws-cdk-lib';
|
|
580
230
|
import { Construct } from 'constructs';
|
|
581
231
|
|
|
582
232
|
export class CdkTestStack extends Stack {
|
|
583
233
|
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
584
234
|
super(scope, id, props);
|
|
585
|
-
new CfnInclude(this, 'Template', {
|
|
235
|
+
const template = new CfnInclude(this, 'Template', {
|
|
586
236
|
templateFile: 'my-template.json',
|
|
587
237
|
});
|
|
588
|
-
//
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
'
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
id: 'AwsSolutions-S2',
|
|
595
|
-
reason: 'at least 10 characters',
|
|
596
|
-
},
|
|
597
|
-
]
|
|
598
|
-
);
|
|
238
|
+
// Acknowledge rules on imported resources
|
|
239
|
+
const bucket = template.getResource('rBucket');
|
|
240
|
+
Validations.of(bucket).acknowledge({
|
|
241
|
+
id: 'AwsSolutions-S1',
|
|
242
|
+
reason: 'Logging not required for this bucket.',
|
|
243
|
+
});
|
|
599
244
|
}
|
|
600
245
|
}
|
|
601
246
|
```
|
|
602
247
|
|
|
603
248
|
</details>
|
|
604
249
|
|
|
605
|
-
|
|
606
|
-
<summary>Example 2) CloudFormation template with granular suppressions</summary>
|
|
607
|
-
|
|
608
|
-
Sample CloudFormation template with suppression
|
|
609
|
-
|
|
610
|
-
```json
|
|
611
|
-
{
|
|
612
|
-
"Resources": {
|
|
613
|
-
"myPolicy": {
|
|
614
|
-
"Type": "AWS::IAM::Policy",
|
|
615
|
-
"Properties": {
|
|
616
|
-
"PolicyDocument": {
|
|
617
|
-
"Statement": [
|
|
618
|
-
{
|
|
619
|
-
"Action": [
|
|
620
|
-
"kms:Decrypt",
|
|
621
|
-
"kms:DescribeKey",
|
|
622
|
-
"kms:Encrypt",
|
|
623
|
-
"kms:ReEncrypt*",
|
|
624
|
-
"kms:GenerateDataKey*"
|
|
625
|
-
],
|
|
626
|
-
"Effect": "Allow",
|
|
627
|
-
"Resource": ["some-key-arn"]
|
|
628
|
-
}
|
|
629
|
-
],
|
|
630
|
-
"Version": "2012-10-17"
|
|
631
|
-
}
|
|
632
|
-
},
|
|
633
|
-
"Metadata": {
|
|
634
|
-
"cdk_nag": {
|
|
635
|
-
"rules_to_suppress": [
|
|
636
|
-
{
|
|
637
|
-
"id": "AwsSolutions-IAM5",
|
|
638
|
-
"reason": "Allow key data access",
|
|
639
|
-
"applies_to": [
|
|
640
|
-
"Action::kms:ReEncrypt*",
|
|
641
|
-
"Action::kms:GenerateDataKey*"
|
|
642
|
-
]
|
|
643
|
-
}
|
|
644
|
-
]
|
|
645
|
-
}
|
|
646
|
-
}
|
|
647
|
-
}
|
|
648
|
-
}
|
|
649
|
-
}
|
|
650
|
-
```
|
|
651
|
-
|
|
652
|
-
Sample App
|
|
653
|
-
|
|
654
|
-
```typescript
|
|
655
|
-
import { App, Aspects } from 'aws-cdk-lib';
|
|
656
|
-
import { CdkTestStack } from '../lib/cdk-test-stack';
|
|
657
|
-
import { AwsSolutionsChecks } from 'cdk-nag';
|
|
658
|
-
|
|
659
|
-
const app = new App();
|
|
660
|
-
new CdkTestStack(app, 'CdkNagDemo');
|
|
661
|
-
Aspects.of(app).add(new AwsSolutionsChecks());
|
|
662
|
-
```
|
|
250
|
+
## Migrating from v2
|
|
663
251
|
|
|
664
|
-
|
|
252
|
+
cdk-nag v3 replaces the custom `NagSuppressions` API with CDK's native `Validations.of().acknowledge()` mechanism.
|
|
665
253
|
|
|
666
|
-
|
|
667
|
-
|
|
668
|
-
|
|
669
|
-
|
|
670
|
-
|
|
254
|
+
| v2 | v3 |
|
|
255
|
+
|---|---|
|
|
256
|
+
| `NagSuppressions.addResourceSuppressions(construct, [{ id, reason }])` | `Validations.of(construct).acknowledge({ id, reason })` |
|
|
257
|
+
| `NagSuppressions.addStackSuppressions(stack, [{ id, reason }])` | `Validations.of(stack).acknowledge({ id, reason })` |
|
|
258
|
+
| `NagSuppressions.addResourceSuppressionsByPath(stack, path, [...])` | `Validations.of(construct).acknowledge({ id, reason })` |
|
|
259
|
+
| `appliesTo: ['Action::s3:*']` | `id: 'AwsSolutions-IAM5[Action::s3:*]'` |
|
|
260
|
+
| `{ id: 'CdkNagValidationFailure', reason: '...' }` | `Validations.of(construct).acknowledge({ id: 'RuleId', reason: '...' })` |
|
|
671
261
|
|
|
672
|
-
|
|
673
|
-
constructor(scope: Construct, id: string, props?: StackProps) {
|
|
674
|
-
super(scope, id, props);
|
|
675
|
-
new CfnInclude(this, 'Template', {
|
|
676
|
-
templateFile: 'my-template.json',
|
|
677
|
-
});
|
|
678
|
-
// Add any additional suppressions
|
|
679
|
-
NagSuppressions.addResourceSuppressionsByPath(
|
|
680
|
-
this,
|
|
681
|
-
'/CdkNagDemo/Template/myPolicy',
|
|
682
|
-
[
|
|
683
|
-
{
|
|
684
|
-
id: 'AwsSolutions-IAM5',
|
|
685
|
-
reason: 'Allow key data access',
|
|
686
|
-
appliesTo: ['Action::kms:ReEncrypt*', 'Action::kms:GenerateDataKey*'],
|
|
687
|
-
},
|
|
688
|
-
]
|
|
689
|
-
);
|
|
690
|
-
}
|
|
691
|
-
}
|
|
692
|
-
```
|
|
262
|
+
**Note on bulk suppression:** In v2, suppressing a rule without `appliesTo` would suppress all findings for that rule on the construct. In v3, each finding must be acknowledged individually (e.g., `AwsSolutions-IAM5[Action::s3:*]` and `AwsSolutions-IAM5[Resource::*]` are separate acknowledgments). Prefix matching (acknowledging `AwsSolutions-IAM5` to suppress all findings) is not yet supported — tracked via [issue link].
|
|
693
263
|
|
|
694
|
-
|
|
264
|
+
**Removed APIs:**
|
|
265
|
+
- `NagSuppressions` (use `Validations.of().acknowledge()`)
|
|
266
|
+
- `INagSuppressionIgnore` and all condition classes
|
|
267
|
+
- `NagPackSuppression` interface
|
|
268
|
+
- `CdkNagValidationFailure` concept
|
|
269
|
+
- `logIgnores` and `suppressionIgnoreCondition` props
|
|
695
270
|
|
|
696
271
|
## Contributing
|
|
697
272
|
|