こんにちは、ちゃりおです。
CDKを色々なチームで使用していると、AWSにそこまで詳しくない人もCDKを書く機会が増えてきます。
そんなときには、危険な設定ができないようにするガードレールが欲しくなってきます。
SCPやPermissions Boundaryでアカウントレベルで、ルールを作るのもいいと思います。
しかし、上記の方法は「cdk deploy」するまでルールに準拠しているかわかりません。
そこで、AspectなどでTestを作ってテンプレート作成時点で検出するアプローチを行うことになると思います。
独自のルールをAspectで検出するのはいいと思うのですが、AWSのベストプラクティスのルールをすべて自分たちで定義するのは大変です。
そんなときに便利なのが、「cdk-nag」です。
今回は、「cdk-nag」について紹介します。
cdk-nagとは
githubで公開されています。
CDKで生成されるCloudFormationテンプレートにおけるベストプラクティスに沿っていない設定を検出してくれるツールです。
以下のルールに沿って、チェックしてくれます。
AWS Solutions
HIPAA Security
NIST 800-53 rev 4
NIST 800-53 rev 5
PCI DSS 3.2.1
デモ
cdk-nagを使って、ベストプラクティスに沿ったSQSを作成します。
SQSを普通に作ってcdk-nagでルールを検出してみる
cdk-nagをインストールします。
npm install cdk-nag
cdk v2を使っている場合は、「cdk-nag@^2.0.0」とかでv2のバージョンをインストールしてくれださい。(何も指定しないと2021/12時点では、v1のcdk-nagがインストールされます)
# bin/index.ts
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';
import { SqsStack } from '../lib/sqs-stack';
import { Aspects } from 'aws-cdk-lib';
import { AwsSolutionsChecks } from 'cdk-nag';
const app = new cdk.App();
new SqsStack(app, 'CkdNagStack', {});
Aspects.of(app).add(new AwsSolutionsChecks()); #cdk-nagを使う
#lib/sqs-stack.ts
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
export class SqsStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const queue = new sqs.Queue(this, 'Queue', {
visibilityTimeout: Duration.seconds(300),
});
}
}
上記のファイルを用意したら、コマンドを実行します。
npm run cdk synth
[Error at /CkdNagStack/Queue/Resource] AwsSolutions-SQS2: The SQS Queue does not have server-side encryption enabled.
[Error at /CkdNagStack/Queue/Resource] AwsSolutions-SQS3: The SQS queue does not have a dead-letter queue (DLQ) enabled or have a cdk_nag rule suppression indicating it is a DLQ.
ルールに沿っていない設定があり、エラーが表示されました。
エラーメッセージを見てみると、原因は以下のようです。
- サーバーサイドの暗号化がされていない
- DLQの設定がされていない
cdk-nagで検出された問題を修正する
問題を修正します。
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
export class SqsStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const dlQueue = new sqs.Queue(this, "DeadLetterQueue", {
encryption: sqs.QueueEncryption.KMS_MANAGED
})
const queue = new sqs.Queue(this, 'Queue', {
visibilityTimeout: Duration.seconds(300),
encryption: sqs.QueueEncryption.KMS_MANAGED, // 暗号化を有効化
deadLetterQueue: { // dlqを設定
maxReceiveCount: 10,
queue: dlQueue
}
});
}
}
しかし、DLQのエラーが残っています。
[Error at /CkdNagStack/DeadLetterQueue/Resource] AwsSolutions-SQS3: The SQS queue does not have a dead-letter queue (DLQ) enabled or have a cdk_nag rule suppression indicating it is a DLQ.
よく読んでみると、どうやらDLQをルールから除外する必要があるみたいですね。
cdk-nagのルールの例外を設定する
READMEのsuppressing-ruleのところを参考に修正しました。
修正後は、エラーが無くなりCloudformationテンプレートが表示されました。
import { Stack, StackProps, Duration } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as sqs from 'aws-cdk-lib/aws-sqs';
import { NagSuppressions } from 'cdk-nag';
export class SqsStack extends Stack {
constructor(scope: Construct, id: string, props?: StackProps) {
super(scope, id, props);
const dlQueue = new sqs.Queue(this, "DeadLetterQueue", {
encryption: sqs.QueueEncryption.KMS_MANAGED
})
const queue = new sqs.Queue(this, 'Queue', {
visibilityTimeout: Duration.seconds(300),
encryption: sqs.QueueEncryption.KMS_MANAGED, // 暗号化を有効化
deadLetterQueue: { // dlqを設定
maxReceiveCount: 10,
queue: dlQueue
}
});
// dlQueueを除外
NagSuppressions.addResourceSuppressions(dlQueue, [
{ id: "AwsSolutions-SQS3", reason: "DeadLetterQueue" }
])
}
}
まとめ
cdk-nagについてでした。
数行追加するだけで、「AWS Solutions」や「HIPAA Security」のルールに沿っているかチェックできるのは、かなり便利だと思いました。
cdk-nagを使うことで、危険な設定のリソースを作られるリスクを減らすことができます。
事前に定義したルールに則ってリソースを作成することができるのも、CDKを使うメリットだと思います。
うまく活用してガードレールを作っていきたいです。