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定義を用意する。
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);
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),
});
const api = new cdk.aws_apigateway.RestApi(this, "api", {
deployOptions: {
tracingEnabled: true,
stageName: "api",
},
});
api.root.addProxy({
defaultIntegration: new cdk.aws_apigateway.LambdaIntegration(apiFn),
});
}
}
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
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,
}
);
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定義出力できた。
参考