CDKのデプロイ前にセキュリティの静的解析ができるcdk-nagを試す
cdk-nagを触ってみた。
Security HubやAWS Configを使った設定チェックはデプロイ後のチェックになるのに比べ、cdk-nagはデプロイ前に静的解析できるのが特長。違反しているとそもそもデプロイできないので開発メンバーに確実にルールを守ってもらえる。CIにも組み込みやすい。
環境
- node 16.15.0
- typescript 5.0.2
- aws-cdk-lib 2.70.0
- constructs 10.1.289
- cdk-nag 2.23.5
サンプルコードを用意
こんな感じのAPIGW+Lambda定義を用意する。
// lib/apigateway-stack.ts import { Construct } from "constructs"; import * as cdk from "aws-cdk-lib"; export class ApigatewayStack extends cdk.Stack { constructor(scope: Construct, id: string, props?: cdk.StackProps) { super(scope, id, props); // APIGW Lambda関数 const apiFn = new cdk.aws_lambda_nodejs.NodejsFunction(this, "apiFn", { runtime: cdk.aws_lambda.Runtime.NODEJS_18_X, entry: "src/lambda/api-handler.ts", bundling: { sourceMap: true, }, timeout: cdk.Duration.seconds(29), }); // APIGW const api = new cdk.aws_apigateway.RestApi(this, "api", { deployOptions: { tracingEnabled: true, stageName: "api", }, }); api.root.addProxy({ defaultIntegration: new cdk.aws_apigateway.LambdaIntegration(apiFn), }); } }
// bin/aws-playground.ts #!/usr/bin/env node import "source-map-support/register"; import * as cdk from "aws-cdk-lib"; import { ApigatewayStack } from "../lib/apigateway-stack"; const region = "ap-northeast-1"; const app = new cdk.App(); new ApigatewayStack(app, "ApigatewayStack", { env: { region }, });
以下コマンドを実行:
npx cdk synth
特にエラー発生せずCFn定義が出力される。
cdk-nag設定を加える
cdk-nagによるチェックをかぶせてみる。ルールパックは特に何も考えず AwsSolutionsChecks
を適用。
// bin/aws-playground.ts #!/usr/bin/env node import "source-map-support/register"; import * as cdk from "aws-cdk-lib"; import { ApigatewayStack } from "../lib/apigateway-stack"; + import { AwsSolutionsChecks } from "cdk-nag"; const region = "ap-northeast-1"; const app = new cdk.App(); new ApigatewayStack(app, "ApigatewayStack", { env: { region }, }); + cdk.Aspects.of(app).add(new AwsSolutionsChecks());
コマンド実行:
npx cdk synth
そうすると以下のエラーがずらずらと出てくる:
[Error at /ApigatewayStack/apiFn/ServiceRole/Resource] AwsSolutions-IAM4[Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]: The IAM user, role, or group uses AWS managed policies. [Error at /ApigatewayStack/api/Resource] AwsSolutions-APIG2: The REST API does not have request validation enabled. [Error at /ApigatewayStack/api/CloudWatchRole/Resource] AwsSolutions-IAM4[Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AmazonAPIGatewayPushToCloudWatchLogs]: The IAM user, role, or group uses AWS managed policies. [Error at /ApigatewayStack/api/DeploymentStage.api/Resource] AwsSolutions-APIG1: The API does not have access logging enabled. [Warning at /ApigatewayStack/api/DeploymentStage.api/Resource] AwsSolutions-APIG3: The REST API stage is not associated with AWS WAFv2 web ACL. [Error at /ApigatewayStack/api/DeploymentStage.api/Resource] AwsSolutions-APIG6: The REST API Stage does not have CloudWatch logging enabled for all methods. [Error at /ApigatewayStack/api/Default/{proxy+}/ANY/Resource] AwsSolutions-APIG4: The API does not implement authorization. [Error at /ApigatewayStack/api/Default/{proxy+}/ANY/Resource] AwsSolutions-COG4: The API GW method does not use a Cognito user pool authorizer. [Error at /ApigatewayStack/api/Default/ANY/Resource] AwsSolutions-APIG4: The API does not implement authorization. [Error at /ApigatewayStack/api/Default/ANY/Resource] AwsSolutions-COG4: The API GW method does not use a Cognito user pool authorizer. Found errors
Errorに抑制もしくは対応していく(今回はWarningはスルー)。
エラーに対応する場合
[Error at /ApigatewayStack/api/DeploymentStage.api/Resource] AwsSolutions-APIG1: The API does not have access logging enabled. [Error at /ApigatewayStack/api/DeploymentStage.api/Resource] AwsSolutions-APIG6: The REST API Stage does not have CloudWatch logging enabled for all methods.
まず、上記ルールに対してリソース定義を追加することで対応してみる(正攻法)。
// 追加 const apiLogAccessLogGroup = new cdk.aws_logs.LogGroup( this, "apiAccessLogGroup", { logGroupName: `/aws/apigateway/apiAccessLogGroup`, retention: 365, } ); // APIGW const api = new cdk.aws_apigateway.RestApi(this, "api", { deployOptions: { tracingEnabled: true, stageName: "api", // 追加 loggingLevel: cdk.aws_apigateway.MethodLoggingLevel.INFO, accessLogDestination: new cdk.aws_apigateway.LogGroupLogDestination( apiLogAccessLogGroup ), accessLogFormat: cdk.aws_apigateway.AccessLogFormat.clf(), }, });
スタックレベルでエラー抑制する場合
続いて抑制する場合。
[Error at /ApigatewayStack/api/Default/{proxy+}/ANY/Resource] AwsSolutions-COG4: The API GW method does not use a Cognito user pool authorizer. [Error at /ApigatewayStack/apiFn/ServiceRole/Resource] AwsSolutions-IAM4[Policy::arn:<AWS::Partition>:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole]: The IAM user, role, or group uses AWS managed policies. [Error at /ApigatewayStack/api/Resource] AwsSolutions-APIG2: The REST API does not have request validation enabled.
上記ルールに対してスタックレベルで抑制をかける。
const apigatewayStack = new ApigatewayStack(app, "ApigatewayStack", { env: { region }, }); // 追加 NagSuppressions.addStackSuppressions(apigatewayStack, [ { id: "AwsSolutions-COG4", reason: "本サービスではCognitoを使用しない", }, { id: "AwsSolutions-IAM4", reason: "本サービスではAWS管理ポリシーをアタッチしても良い", }, { id: "AwsSolutions-APIG2", reason: "本サービスではリクエストバリデーションはLambda関数のロジックで行う", }, ]);
エラー内容を厳密に確認したわけではないので、上記理由が要領を得ていないかもしれない可能性がある(その場合すみませんがコメントください)。
リソースレベルでエラー抑制する場合
[Error at /ApigatewayStack/api/Default/ANY/Resource] AwsSolutions-APIG4: The API does not implement authorization.
上記ルールに対してリソースレベルで抑制をかける。
api.root.addProxy({ defaultIntegration: new cdk.aws_apigateway.LambdaIntegration(apiFn), }); // 追加 NagSuppressions.addResourceSuppressions( api, [ { id: "AwsSolutions-APIG4", reason: "本APIには認証機能を実装しない", }, ], // 子リソースにも適用する true );
以上で
npx cdk cynth
を実行するとエラー発生せずCFn定義出力できた。
参考
- cdklabs/cdk-nag: Check CDK applications for best practices using a combination of available rule packs
- AWS Cloud Development Kit と cdk-nag でアプリケーションのセキュリティとコンプライアンスを管理する | Amazon Web Services ブログ
- AWSインフラをCDKでIaC化したらcdk-nagでセキュリティスキャンしたくない?(特にサプレスの方法) - ISID テックブログ
- API Gateway REST APIのリクエスト検証機能を使って、不正なパラメーターのリクエストを弾く | DevelopersIO
- APIGW リクエスト検証とは?実装する方法までわかりやすく解説!-その1 - サーバーワークスエンジニアブログ
- [AWS CDK] API Gatewayのログ出力を有効にしてCloudWatch Logsでログを確認してみた | DevelopersIO
- cdk-nagを使用したAWS CDKのセキュリティチェック ~基本編~ - NRIネットコムBlog