はじめに
CDK でパワーをかけずにセキュリティチェックしたい!って時ありますよね。
cdk-nag を使用することで、簡単にセキュリティスキャンができますので、使用方法などを簡単にまとめておきます。
cdk-nag とは
一言でいうと、CDK のリソースセキュリティ・コンプライアンスをチェックできるツールです。
セキュリティ・コンプライアンスのルールが記載されたルールを選択し、そのルールに準拠しているかを確認することができます。
また、準拠していない場合、デプロイを停止することができます。
現在は、次のルールセットがあります。
- AWS Solutions
- HIPAA Security
- NIST 800-53 rev 4
- NIST 800-53 rev 5
- PCI DSS 3.2.1
特にセキュリティの要件などなければAWS Solutions
ルールを使用するのがよいかと思います。
使い方
前提条件
-
typescript
の言語の使用方法になります。 -
AWS Solutions
ルールに焦点を当てた使用方法になります。
準備
次のコマンドで CDK アプリを作成します。
mkdir cdk-nag-confirm
cd cdk-nag-confirm
cdk init app --language typescript
次のコマンドで cdk-nag パッケージをインストールします。
npm install -D cdk-nag
lib/cdk-nag-confirm-stack.ts
のコメントアウトを外します。
const queue = new sqs.Queue(this, "CdkNagConfirmQueue", {
visibilityTimeout: cdk.Duration.seconds(300),
});
cdk-nag の導入
bin/cdk-nag-confirm.ts
の内容を以下の内容に置き換え、AWS Solutions
ルールに準拠しているか確認するようにします。
import "source-map-support/register";
import * as cdk from "aws-cdk-lib";
import { AwsSolutionsChecks } from "cdk-nag";
import { CdkNagConfirmStack } from "../lib/cdk-nag-confirm-stack";
const app = new cdk.App();
cdk.Aspects.of(app).add(new AwsSolutionsChecks());
new CdkNagConfirmStack(app, "CdkNagConfirmStack", {});
ルールに沿っているかの確認
次のコマンドを実行し、ルールに沿っているか確認します。
cdk synth
エラーが 2 つ出力されました。
[Error at /CdkNagConfirmStack/CdkNagConfirmQueue/Resource] AwsSolutions-SQS3: The SQS queue is not used as a dead-letter queue (DLQ) and does not have a DLQ enabled.
[Error at /CdkNagConfirmStack/CdkNagConfirmQueue/Resource] AwsSolutions-SQS4: The SQS queue does not require requests to use SSL.
メッセージ内容を確認すると、DLQ を有効にしていないことと
SQS のリクエストに、SSL を強制していないので出力されているようです。
このエラーを修正および抑制していきます。
なお、cdk.out/AwsSolutions-CdkNagConfirmStack-NagReport.csv
の方にもコンソールと同様の内容が出力されます。
エラーの修正
SQS のリクエストに SSL を強制するように修正し、cdk synth
を再実行します。
const queue = new sqs.Queue(this, "CdkNagConfirmQueue", {
visibilityTimeout: cdk.Duration.seconds(300),
+ enforceSSL: true,
});
SSL のエラーが出力されなくなったことが確認できました。
[Error at /CdkNagConfirmStack/CdkNagConfirmQueue/Resource] AwsSolutions-SQS3: The SQS queue is not used as a dead-letter queue (DLQ) and does not have a DLQ enabled.
エラーの抑制
ルールはあくまでベストプラクティス集のため、特定のルールについては抑制したい場合があると思います。
この場合、サプレスすることによって特定のルールを抑制することができます。
以下は DLQ を抑制する記載方法になります。
import * as cdk from "aws-cdk-lib";
import { Construct } from "constructs";
import * as sqs from "aws-cdk-lib/aws-sqs";
+ import { NagSuppressions } from "cdk-nag";
export class CdkNagConfirmStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const queue = new sqs.Queue(this, "CdkNagConfirmQueue", {
visibilityTimeout: cdk.Duration.seconds(300),
enforceSSL: true,
});
+ NagSuppressions.addResourceSuppressions(queue, [
+ {
+ id: "AwsSolutions-SQS3",
+ reason: "Demonstrate a resource level suppression.",
+ },
+ ]);
}
}
サプレスに、対象のルールID
を渡し、抑制の理由を記述します。
これで再度cdk synth
を実行すると、エラーが解消され、CloudFormation テンプレートが
出力されるようになるはずです。
cdk-nag のテストの記載方法
エラーや警告が 1 つもないかを確認するようにテストコードを記述することで、ルールに準拠しているかをテストすることができます。
以下は、テストコードの例になります。
import { Annotations, Match } from "aws-cdk-lib/assertions";
import { App, Aspects, Stack } from "aws-cdk-lib";
import { CdkNagConfirmStack } from "../lib/cdk-nag-confirm-stack";
import { AwsSolutionsChecks } from "cdk-nag";
describe("cdk-nag Aws Solutions Pack", () => {
let stack: Stack;
let app: App;
beforeAll(() => {
app = new App();
stack = new CdkNagConfirmStack(app, "test-stack");
Aspects.of(stack).add(new AwsSolutionsChecks());
});
test("No unsuppressed Warnings", () => {
const Warnings = Annotations.fromStack(stack).findWarning(
"*",
Match.stringLikeRegexp("AwsSolutions-.*")
);
expect(Warnings).toHaveLength(0);
});
test("No unsuppressed Errors", () => {
const errors = Annotations.fromStack(stack).findError(
"*",
Match.stringLikeRegexp("AwsSolutions-.*")
);
expect(errors).toHaveLength(0);
});
});
さいごに
cdk-nag はすぐに導入でき、体力をかけずにセキュリティ・コンプライアンス要件をチェックできるので、積極的に使っていきたいと思います!