cdk-nag
Version:
Check CDK v2 applications for best practices using a combination on available rule packs.
139 lines (115 loc) • 5.42 kB
Markdown
<!--
Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
SPDX-License-Identifier: Apache-2.0
-->
# Conditionally Ignoring Suppressions
As a [NagPack](./NagPack.md) author or user, 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.
## Creating A Condition
Conditions implement the `INagSuppressionIgnore` interface. They return a message string when the `createMessage()` method is called. If the method returns a non-empty string the suppression is ignored. Conversely, if the method returns an empty string the suppression is allowed.
Here is an example of a re-usable condition class that ignores a suppression if the suppression reason doesn't contain the word `Arun`
```ts
import { INagSuppressionIgnore, SuppressionIgnoreInput } from 'cdk-nag';
class ArunCondition implements INagSuppressionIgnore {
createMessage(input: SuppressionIgnoreInput) {
if (!input.reason.includes('Arun')) {
return 'The reason must contain the word Arun!';
}
return '';
}
}
```
You could also create the same condition without a class and by just implementing the interface
```ts
({
createMessage(input: SuppressionIgnoreInput) {
return !input.reason.includes('Arun')
? 'The reason must contain the word Arun!'
: '';
},
});
```
### Applying Conditions
There are 3 ways of applying conditions to rules. Users have 1 way, they can supply an additional global condition that gets applied to all rules. `NagPack` authors have 2 ways, they can individually apply conditions to rules and/or apply a global condition to all rules. All present conditions are evaluated together using a `SuppressionIgnoreOr`(review [this section](#creating-complex-conditions) for more details on complex conditions).
Here is an example of a `NagPack` author applying both a global condition and an individual condition to the prebuilt `S3BucketSSLRequestsOnly` S3 Rule.
```ts
import { CfnResource } from 'aws-cdk-lib';
import { Bucket } from 'aws-cdk-lib/aws-s3';
import {
NagMessageLevel,
NagPack,
NagPackProps,
NagSuppressions,
SuppressionIgnoreInput,
rules,
} from 'cdk-nag';
import { IConstruct } from 'constructs';
export class ExampleChecks extends NagPack {
constructor(props?: NagPackProps) {
super(props);
this.packName = 'Example';
this.packGlobalSuppressionIgnore = {
createMessage(input: SuppressionIgnoreInput) {
return !input.reason.includes('Arun')
? 'The reason must contain the word Arun!'
: '';
},
};
}
public visit(node: IConstruct): void {
if (node instanceof CfnResource) {
this.applyRule({
info: 'My brief info.',
explanation: 'My detailed explanation.',
level: NagMessageLevel.ERROR,
rule: rules.s3.S3BucketSSLRequestsOnly,
ignoreSuppressionCondition: {
createMessage(input: SuppressionIgnoreInput) {
return !input.reason.includes('Donti')
? 'The reason must contain the word Donti!'
: '';
},
},
node: node,
});
}
}
}
```
A user would see the following output when attempting to synthesize an application using a non-compliant suppression on a S3 Bucket
```bash
[Info at /Test/bucket/Resource] The suppression for Example-S3BucketSSLRequestsOnly was ignored for the following reason(s).
The reason must contain the word Arun!
The reason must contain the word Donti!
[Error at /Test/bucket/Resource] Example-S3BucketSSLRequestsOnly: My brief info.
```
## Creating Complex Conditions
`cdk-nag` exposes both a `SuppressionIgnoreAnd` class and a `SuppressionIgnoreOr` to help developers create more complicated conditions
- `SuppressionIgnoreAnd`: Ignores the suppression if **ALL** of the given INagSuppressionIgnore return a non-empty message (logical and)
- `SuppressionIgnoreOr`: Ignores the suppression if **ANY** of the given INagSuppressionIgnore return a non-empty message (logical or)
Here is an example `SuppressionIgnoreAnd` that ignores a suppression if both a 'ticket' CloudFormation metadata entry does not exist on the resource and the current year is after 2022.
```ts
import { SuppressionIgnoreAnd, SuppressionIgnoreInput } from 'cdk-nag';
new SuppressionIgnoreAnd(
{
createMessage(input: SuppressionIgnoreInput) {
return !input.resource.getMetadata('ticket')
? 'Must provide a ticket for an exception!'
: '';
},
},
{
createMessage(_input: SuppressionIgnoreInput) {
return Date.now() > Date.parse('31 Dec 2022 23:59 UTC')
? 'Suppressions are only allowed before the year 2023'
: '';
},
}
);
```
A user would see the following output when attempting to synthesize an application using a non-compliant suppression on a rule evaluating a S3 Bucket.
```bash
[Info at /Test/bucket/Resource] The suppression for Example-S3BucketSSLRequestsOnly was ignored for the following reason(s).
Must provide a ticket for an exception!
Suppressions are only allowed before the year 2023
[Error at /Test/bucket/Resource] Example-S3BucketSSLRequestsOnly: My brief info.
```