こんにちは。X(クロス) イノベーション 本部 ソフトウェアデザインセンター セキュリティグループの耿です。これは 電通国際情報サービス Advent Calendar 2022 12/14の記事です。 プログラミング言語 で クラウド インフラをIaC化できるライブラリとして、 AWS Cloud Development Kit (CDK) が使われることが増えています。CDKではリソースのデフォルト値が設定され、便利に短く記述できる一方で、デフォルト値が必ずしも推奨されるセキュリティ構成になっていない場合があります。 Security Hubのセキュリティ基準 を利用していると、リソースをデプロイした後にアラートに気付いて修正をすることもあるのではないでしょうか。 そこでこの記事では、Security Hubのセキュリティ基準でアラートを出さないためのCDKによるリソースの記述方法を、主要なサービスの種類ごとにまとめました。CDKでリソースを作成するときに、どのような設定を気にした方が良いのか、Security Hubアラートとの マッピング として使っていただけると幸いです。 なお、矛盾しているように聞こえるかもしれませんが、Security Hubのチェックルールは 全てクリアすること自体を目的とするものではない と考えています。 AWS も全てのルールをクリアすることを期待していないでしょう。例えばS3 バケット については、 アクセスログ を出力するようにチェックするルールがありますが(S3.9)、 アクセスログ を格納する バケット の アクセスログ は出力しないため、全くアラートが上がらない状態にはできませんね。闇雲に全てのSecurity Hubアラートをクリアしようとするのではなく、 アラートからリスクを評価し、対応するかどうかを総合的に判断する プロセスが必要です。「知らずに設定していなかった」ではなく、「知った上で設定するかどうか判断する」状態にするために、Security Hubを活用するのが良いと思います。 おことわり セキュリティ基準として、記事執筆時点の AWS Foundational Security Best Practices を対象とします AWS Foundational Security Best Practices では、30以上の AWS サービスについてのコン トロール (チェックルール)がありますが、この記事ではよく使われるサービスで、CDKで作成することが多いと思われる13種のサービスのみを取り上げます 全てのコン トロール を網羅していません。CDKのデフォルト設定で対応できていないコン トロール を中心に扱います。また可用性に関わるコン トロール や、要件に応じて特別な構成が必要なコン トロール は除外しているものがあります 設定自体の意味、設定することによる影響は割愛しているため、公式ドキュメントなどでご確認ください 設定することによって追加でかかる費用については、記事内では言及していません 記載しているコードは実装方法の一つの例であり、他にも実装方法がある場合があります コード例は分かりやすさのため、関連する最小限のリソースプロパティのみ記載しています CDKで対応できる範囲、かつSecurity Hubのセキュリティ基準の範囲のセキュリティ対策であるため、当然ながらこれらの設定だけをすれば他にセキュリティ対策が不要というわけではありません CDK v2.50.0 で検証しています。今後のアップデートにより実装方法が変更になったり、デフォルトの挙動が変わる可能性があります。 AWS ドキュメントでは一部不自然な日本語訳があるため、わかりやすさのため独自の日本語訳にしているコン トロール があります。 おことわり VPC EC2.2 EC2.6 EC2.18、EC2.19 ELB ELB.4 ELB.5 ELB.6 CloudFront CloudFront.1 CloudFront.2 CloudFront.3 CloudFront.4 CloudFront.5 CloudFront.6 CloudFront.7、CloudFront.8 EC2 EC2.3 EC2.8 SSM.1 ECS ECS.5 ECS.12 ECR ECR.1 ECR.2 ECR.3 RDS RDS.3 RDS.7、RDS.8 RDS.9 RDS.10、RDS.12 RDS.11 RDS.13 RDS.14 RDS.23 RDS.24、RDS.25 DynamoDB DynamoDB.2 S3 S3.4 S3.5 S3.8 S3.9 S3.13 EFS EFS.1 SNS SNS.1 SNS.2 SQS SQS.1 API Gateway APIGateway.1 APIGateway.4 APIGateway.5 VPC EC2.2 英語タイトル:The VPC default security group should not allow inbound and outbound traffic 日本語訳: VPC のデフォルトのセキュリティグループでは、インバウンド トラフィック とアウトバウンド トラフィック を許可しないようにする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-2 (2023/6/27更新). CDK v2.78.0より、 Vpc で restrictDefaultSecurityGroup プロパティが利用できるようになったため、対応が簡単になりました。 new Vpc ( this , "Vpc" , { restrictDefaultSecurityGroup: true , } ); ======以下は過去の対応方法です。====== CDKでは簡単にデフォルトのセキュリティグループのルールを変更できないため、現時点では この投稿 の通り、カスタムリソースを利用してルールを削除することになります。 まずは Vpc を継承した BaseVpc というクラスを作り(名前自由)、セキュリティグループのルールを削除するカスタムリソースを含めます。 コードを表示 import { Stack } from "aws-cdk-lib" ; import { CfnVPC , Vpc , VpcProps } from "aws-cdk-lib/aws-ec2" ; import { AwsCustomResource , AwsCustomResourcePolicy , PhysicalResourceId } from "aws-cdk-lib/custom-resources" ; import { Construct } from "constructs" ; export class BaseVpc extends Vpc { constructor( scope: Construct , id: string , props: VpcProps ) { super( scope , id , props ); const cfnVpc = this .node.defaultChild as CfnVPC ; const stack = Stack. of( this ); const ingressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , UserIdGroupPairs: [ { GroupId: cfnVpc.attrDefaultSecurityGroup , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupIngress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupIngress" , parameters: ingressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-ingress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupIngress" , parameters: ingressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); const egressParameters = { GroupId: cfnVpc.attrDefaultSecurityGroup , IpPermissions: [ { IpProtocol: "-1" , IpRanges: [ { CidrIp: "0.0.0.0/0" , } , ] , } , ] , } ; new AwsCustomResource ( this , "RestrictSecurityGroupEgress" , { onCreate: { service: "EC2" , action: "revokeSecurityGroupEgress" , parameters: egressParameters , physicalResourceId: PhysicalResourceId. of( `restrict-egress- ${ this .vpcId } - ${ cfnVpc.attrDefaultSecurityGroup } ` ), } , onDelete: { service: "EC2" , action: "authorizeSecurityGroupEgress" , parameters: egressParameters , } , policy: AwsCustomResourcePolicy.fromSdkCalls ( { resources: [ `arn:aws:ec2: ${ stack.region } : ${ stack.account } :security-group/ ${ cfnVpc.attrDefaultSecurityGroup } ` ] , } ), } ); } } それを Vpc の代わりに利用するだけです。 new BaseVpc ( this , "Vpc" , {} ); ======過去の対応方法ここまで====== EC2.6 英語タイトル: VPC flow logging should be enabled in all VPCs 日本語訳:すべての VPC で VPC フローログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-6 VPCフローログ を有効にします。以下の例ではS3 バケット に出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const vpc = new ec2.Vpc ( this , "Vpc" , {} ); new ec2.FlowLog ( this , "VpcFlowLog" , { resourceType: ec2.FlowLogResourceType.fromVpc ( vpc ), destination: ec2.FlowLogDestination.toS3 ( logBucket , "vpc/" ), trafficType: ec2.FlowLogTrafficType.ALL , } ); EC2.18、EC2.19 英語タイトル:[EC2.18] Security groups should only allow unrestricted incoming traffic for authorized ports 日本語訳:セキュリティグループは、許可されたポートのみに対して制限されていない着信 トラフィック を許可してください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-18 英語タイトル:[EC2.19] Security groups should not allow unrestricted access to ports with high risk 日本語訳:セキュリティグループは、リスクの高いポートへの無制限アクセスを許可してはいけません https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-19 この2つは関連するコン トロール であり、チェック対象となるポート番号だけが異なるので一緒に扱います。 セキュリティグループにHTTP(80)、 HTTPS (443)以外のポートへのインバウンドルールを追加する時は無制限アクセス(0.0.0.0/0)を許可するのではなく、送信元 IPアドレス か特定のセキュリティグループに制限します。 const sshSecurityGroup = new ec2.SecurityGroup ( this , "SecurityGroup" , { vpc , } ); const anotherSecurityGroup = new ec2.SecurityGroup ( this , "AnotherSecurityGroup" , { vpc , } ); // 許可するIPアドレスレンジを制限する sshSecurityGroup.addIngressRule ( ec2.Peer.ipv4 ( "xx.xx.xx.xx/32" ), ec2.Port.tcp ( 22 )); // 別のセキュリティグループに制限する sshSecurityGroup.addIngressRule ( anotherSecurityGroup , ec2.Port.tcp ( 22 )); ELB ELB.4 英語タイトル:Application load balancers should be configured to drop HTTP headers 日本語訳:Application Load Balancer は、HTTP ヘッダーを削除するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-4 dropInvalidHeaderFields プロパティ(CDK v2.47.0~)を利用し、 無効なHTTPヘッダーの削除設定 を有効にします。 new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , dropInvalidHeaderFields: true , } ); ELB.5 英語タイトル:Application and Classic Load Balancers logging should be enabled 日本語訳:Application Load Balancer および Classic Load Balancer のログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-5 ロードバランサーのアクセスログ をS3 バケット に保存します。以下の例はALBの場合です。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , } ); alb.logAccessLogs ( logBucket , "alb" ); ELB.6 英語タイトル:Application Load Balancer deletion protection should be enabled 日本語訳:Application Load Balancer で削除保護を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-elb-6 deletionProtection プロパティを利用し、 削除保護 を有効にします。 const alb = new elbv2.ApplicationLoadBalancer ( this , "Alb" , { vpc: vpc , deletionProtection: true , } ); CloudFront CloudFront.1 英語タイトル:CloudFront distributions should have a default root object configured 日本語訳:CloudFront ディストリビューション では、デフォルトのルートオブジェクトが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-1 以下の例はS3 バケット がオリジンの場合です。あらかじめ ルートオブジェクト をアップロードした上で、 defaultRootObject プロパティでオブジェクトパスを指定します。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , defaultRootObject: "index.html" , } ); CloudFront.2 英語タイトル:CloudFront distributions should have origin access identity enabled 日本語訳:CloudFront ディストリビューション では、オリジンアクセス アイデンティティ を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-2 CDKではCloudFront ディストリビューション のオリジンをS3 バケット に指定するだけで、 OAI が自動的に設定され、特別な実装は必要ありません。 なお、OAIに代わる OAC については、記事執筆時点では CDKのL2コンストラクトでは未対応 です。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , } ); CloudFront.3 英語タイトル:CloudFront distributions should require encryption in transit 日本語訳:CloudFront ディストリビューション では、転送中に暗号化が必要となります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-3 viewerProtocolPolicy を REDIRECT_TO_HTTPS もしくは HTTPS_ONLY にすることで対応できます。 new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), viewerProtocolPolicy: cloudfront.ViewerProtocolPolicy.REDIRECT_TO_HTTPS , } , } ); CloudFront.4 英語タイトル:CloudFront distributions should have origin failover configured 日本語訳:CloudFront ディストリビューション では、オリジンフェイルオーバーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-4 フェイルオーバー 用のオリジンを別途作成し、 OriginGroup で primaryOrigin と fallbackOrigin を設定します。(「フェイルオーバー」と「フェイルバック」の用語が統一されていませんが、同じものを指していると考えて良いでしょう) const fallbackBucket = new s3.Bucket ( this , "FallbackBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.OriginGroup ( { primaryOrigin: new cloudfrontOrigins.S3Origin ( originBucket ), fallbackOrigin: new cloudfrontOrigins.S3Origin ( fallbackBucket ), } ), } , } ); CloudFront.5 英語タイトル:CloudFront distributions should have logging enabled 日本語訳:CloudFront ディストリビューション では、ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-5 logBucket と logFilePrefix プロパティを指定し、 CloudFrontのログ を出力します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , logBucket: logBucket , logFilePrefix: "cloudfront/" , } ); CloudFront.6 英語タイトル:CloudFront distributions should have AWS WAF enabled 日本語訳:CloudFront ディストリビューション では、 AWS WAF を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-6 AWS WAFのWeb ACL を作成し、CloudFront ディストリビューション に関連付けます。 コードを表示 const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAclCloudFront" , { defaultAction: { allow: {} } , // scopeは CLOUDFRONT とする scope: "CLOUDFRONT" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "WafV2WebAclCloudFront" , } , rules: [ // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ { name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , webAclId: wafWebAcl.attrArn , } ); CloudFront.7、CloudFront.8 英語タイトル:[CloudFront.7] CloudFront distributions should use custom SSL / TLS certificates 日本語訳:CloudFront ディストリビューション では、カスタム SSL / TLS 証明書を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-7 英語タイトル:[CloudFront.8] CloudFront distributions should use SNI to serve HTTPS requests 日本語訳:CloudFront ディストリビューション では、SNI を使用して HTTPS リク エス トを処理する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-cloudfront-8 TLS 証明書を発行し、CloudFront ディストリビューション に関連付けます。 こうすることで自動的にSNIも有効になります。 コードを表示 const hostedZone = route53.PublicHostedZone.fromHostedZoneAttributes ( this , "MyHostedZone" , { hostedZoneId: hostedZoneId , // ホストゾーンID zoneName: hostedZoneName , // ホストゾーン名 } ); const cloudfrontCertificate = new certificatemanager.DnsValidatedCertificate ( this , "CloudFrontCertificate" , { domainName: "my-domain.com" , hostedZone: hostedZone , validation: certificatemanager.CertificateValidation.fromDns ( hostedZone ), } ); new cloudfront.Distribution ( this , "Distribution" , { defaultBehavior: { origin: new cloudfrontOrigins.S3Origin ( originBucket ), } , certificate: cloudfrontCertificate , domainNames: [ "my-domain.com" ] , } ); EC2 EC2.3 英語タイトル:Attached EBS volumes should be encrypted at rest 日本語訳:アタッチされた EBS ボリュームは、保管時の暗号化を有効に必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-3 AWS マネージドキーでの暗号化であれば blockDevices の encrypted プロパティで実現できます( 参考 )。 なお、リージョンで EBSボリュームのデフォルト暗号化 を設定しておくことによって、 blockDevices の encrypted プロパティを明示的に指定しなくても暗号化されるようになるので楽です。 コードを表示 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , blockDevices: [ { deviceName: "/dev/xvda" , mappingEnabled: true , volume: ec2.BlockDeviceVolume.ebs ( 30 , { deleteOnTermination: true , volumeType: ec2.EbsDeviceVolumeType.GP2 , encrypted: true , } ), } , ] , } ); EC2.8 英語タイトル:EC2 instances should use IMDSv2 日本語訳:EC2 インスタンス は IMDSv2 を使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ec2-8 requireImdsv2 プロパティで IMDSv2 のみを有効にします。EC2 インスタンス の通信内容によっては動作に問題が発生する可能性があるため、慎重な検証が必要です。 const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); new ec2.Instance ( this , "Instance" , { vpc , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , requireImdsv2: true , } ); SSM.1 英語タイトル:EC2 instances should be managed by AWS Systems Manager 日本語訳:EC2 インスタンス は AWS Systems Manager により管理される必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ssm-1 SSMでEC2 インスタンス を管理するためには いくつか条件 がありますが、特にハマりやすいのは以下の3点だと思います。( 参考 ) インスタンス にSSM エージェントがインストールされている SSMサービスへの通信ルートがある( VPC エンドポイント or インターネット経由) VPC エンドポイントの場合、 ssm 、 ec2messages 、 ssmmessages の3つが必要 インスタンス ロールが AmazonSSMManagedInstanceCore ポリシーを含んでいる 以下は SSM エージェントがインストールされている Amazon Linux 2を使用し、 VPC エンドポイントでSSMサービスに接続している例です。 コードを表示 const vpc = new ec2.Vpc ( this , "Vpc" , { subnetConfiguration: [ { name: "private-with-egress" , subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS , cidrMask: 20 , } , ] , } ); vpc.addInterfaceEndpoint ( "SSMEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "SSMMessagesEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.SSM_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); vpc.addInterfaceEndpoint ( "EC2MESSAGESEndpoint" , { service: ec2.InterfaceVpcEndpointAwsService.EC2_MESSAGES , subnets: { subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS } , } ); const ami = new ec2.AmazonLinuxImage ( { generation: ec2.AmazonLinuxGeneration.AMAZON_LINUX_2 , cpuType: ec2.AmazonLinuxCpuType.X86_64 , } ); const role = new iam.Role ( this , "Role" , { assumedBy: new iam.ServicePrincipal ( "ec2.amazonaws.com" ), managedPolicies: [ iam.ManagedPolicy.fromAwsManagedPolicyName ( "AmazonSSMManagedInstanceCore" ) ] , } ); new ec2.Instance ( this , "Instance" , { vpc , role , instanceType: ec2.InstanceType. of( ec2.InstanceClass.T2 , ec2.InstanceSize.MICRO ), machineImage: ami , } ); ECS ECS.5 英語タイトル:ECS containers should be limited to read-only access to root filesystems 日本語訳:ECS コンテナは、ルート ファイルシステム への読み取り専用アクセスに制限する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-5 ECSタスク定義のコンテナ定義で、 readonlyRootFilesystem を true とすることで ルートファイルシステムへのアクセスを読み取り専用 にします。ただしこの設定をするとコンテナの ファイルシステム に書き込むことができなくなり、 ECS Exec も使用できなくなります。 const taskDefinition = new ecs.FargateTaskDefinition ( this , "TaskDefinition" , { family: "my-task-definition" , runtimePlatform: { operatingSystemFamily: ecs.OperatingSystemFamily.LINUX } , } ); taskDefinition.addContainer ( "Container" , { containerName: "my-container" , image: ecs.ContainerImage.fromRegistry ( "my-ecr" ), readonlyRootFilesystem: true , } ); ECS.12 英語タイトル:ECS clusters should have Container Insights enabled 日本語訳:ECS クラスタ ーでは、Container Insights を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecs-12 ECS クラスタ ーの containerInsights プロパティを true にすることで、 Container Insights を有効にできます。 new ecs.Cluster ( this , "Cluster" , { vpc: vpc , containerInsights: true , } ); ECR ECR.1 英語タイトル:ECR private repositories should have image scanning configured 日本語訳:ECR プライベー トリポジ トリでは、イメージスキャニングが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-1 ECR リポジトリ の imageScanOnPush プロパティを true にすることで、 プッシュ時の基本スキャン を有効にできます。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageScanOnPush: true , } ); ECR.2 英語タイトル:ECR private repositories should have tag immutability configured 日本語訳:ECR プライベー トリポジ トリでは、タグのイミュータビリティが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-2 imageTagMutability を IMMUTABLE にすることで、 タグを変更不可 にします。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , imageTagMutability: ecr.TagMutability.IMMUTABLE , } ); ECR.3 英語タイトル:ECR repositories should have at least one lifecycle policy configured 日本語訳:ECR リポジトリ には、少なくとも 1 つのライフサイクルポリシーが設定されている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-ecr-3 lifecycleRules プロパティを設定することで、 ECRリポジトリのライフライクルポリシー を設定します。 new ecr.Repository ( this , "Repository" , { repositoryName: "my-repository" , lifecycleRules: [{ maxImageCount: 5 }] , } ); RDS RDS.3 英語タイトル:RDS DB instances should have encryption at rest enabled 日本語訳:RDS DB インスタンス では、保管時の暗号化が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-3 storageEncrypted プロパティでストレージの暗号化を有効化します。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , storageEncrypted: true , } ); RDS.7、RDS.8 英語タイトル:[RDS.7] RDS clusters should have deletion protection enabled 日本語訳:RDS クラスタ ーでは、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-7 英語タイトル:[RDS.8] RDS DB instances should have deletion protection enabled 日本語訳:RDS DB インスタンス で、削除保護が有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-8 deletionProtection か removalPolicy のどちらかのプロパティを使用して、削除保護を有効にします。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // deletionProtection か removalPolicy のどちらかを使用する deletionProtection: true , removalPolicy: cdk.RemovalPolicy.RETAIN , } ); RDS.9 英語タイトル:Database logging should be enabled 日本語訳:データベースログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-9 MySQL と PostgreSQL でルールをクリアするために有効にしなければならないログが異なります。 試した際には、 MySQL では「エラーログ」「一般ログ」「スロークエリログ」の3つを最低限出力していればルールはクリアになりました。 PostgreSQL では「 PostgreSQL ログ」と「アップグレードログ」の両方を出力する必要がありました。 const mysqlParameterGroup = new rds.ParameterGroup ( this , "MysqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.mysql ( { version: rds.MysqlEngineVersion.VER_8_0 , } ), parameters: { general_log: "1" , slow_query_log: "1" , log_output: "FILE" , } , } ); new rds.DatabaseInstance ( this , "Mysql" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: mysqlParameterGroup , // 監査ログも含める場合は "audit" を追加 cloudwatchLogsExports: [ "error" , "general" , "slowquery" ] , } ); const postgresParameterGroup = new rds.ParameterGroup ( this , "PostgresqlParameterGroup" , { engine: rds.DatabaseInstanceEngine.postgres ( { version: rds.PostgresEngineVersion.VER_14 , } ), parameters: { log_statement: "all" , } , } ); new rds.DatabaseInstance ( this , "Postgresql" , { vpc , engine: rds.DatabaseInstanceEngine.POSTGRES , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , parameterGroup: postgresParameterGroup , cloudwatchLogsExports: [ "postgresql" , "upgrade" ] , } ); (2023/4/19追記)ログ出力に際し、パラメータグループの設定が抜けていたため追記しました。詳細は以下。 https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.MySQL.LogFileSize.html https://docs.aws.amazon.com/ja_jp/AmazonRDS/latest/UserGuide/USER_LogAccess.Concepts.PostgreSQL.html RDS.10、RDS.12 英語タイトル:[RDS.10] IAM authentication should be configured for RDS instances 日本語訳:IAM 認証は RDS インスタンス 用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-10 英語タイトル:[RDS.12] IAM authentication should be configured for RDS clusters 日本語訳:IAM 認証は RDS クラスタ ー用に設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-12 iamAuthentication プロパティを true にすることで、RDSへの接続に IAM認証 を利用できます。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { vpc , engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , iamAuthentication: true , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , iamAuthentication: true , } ); RDS.11 英語タイトル: Amazon RDS instances should have automatic backups enabled 日本語訳: Amazon RDS インスタンス では、自動バックアップが有効になっている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-11 backupRetention プロパティを使用して 自動バックアップ を設定し、7日以上にすることでルールをクリアできます。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , // 7日以上にする backupRetention: cdk.Duration.days ( 7 ), } ); RDS.13 英語タイトル:RDS automatic minor version upgrades should be enabled 日本語訳:RDS 自動マイナーバージョンアップグレードを有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-13 CDKでRDS インスタンス を作成すると、DBエンジンのマイナーバージョンアップグレードはデフォルトで有効ですが、メンテナンスウィンドウは自動的に選択されるため、 preferredMaintenanceWindow で指定すると良いでしょう。なお、 UTC で記載する必要があることにご注意ください。 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , autoMinorVersionUpgrade: true , // デフォルトでも true preferredMaintenanceWindow: "sat:18:00-sat:18:30" , // メンテナンスウィンドウ (UTC) } ); RDS.14 英語タイトル: Amazon Aurora clusters should have backtracking enabled 日本語訳: Amazon Aurora クラスタ ーはバックト ラッキング を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-14 Aurora クラスタ ーの backtrackWindow プロパティでバックトラックウィンドウを指定することで、 バックトラック を有効にできます。 new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , backtrackWindow: cdk.Duration.hours ( 24 ), } ); RDS.23 英語タイトル:RDS databases and clusters should not use a database engine default port 日本語訳:RDS データベースと クラスタ ーはデータベースエンジンのデフォルトポートを使用しないでください https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-23 port プロパティにより接続ポートをデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , port: 13306 , } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , port: 13306 , } ); RDS.24、RDS.25 英語タイトル:[RDS.24] RDS database clusters should use a custom administrator username 日本語訳:RDS データベース クラスタ ーはカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-24 英語タイトル:[RDS.25] RDS database instances should use a custom administrator username 日本語訳:RDS データベース インスタンス はカスタム管理者ユーザーネームを使用する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-rds-25 credentials プロパティで、管理者ユーザー名をデフォルト値以外に変更できます。RDS インスタンス / クラスタ ー作成後の変更は不可です。 // Aurora new rds.DatabaseCluster ( this , "Aurora" , { engine: rds.DatabaseClusterEngine.AURORA_MYSQL , instanceProps: { vpc , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); // Aurora以外 new rds.DatabaseInstance ( this , "DB" , { vpc , engine: rds.DatabaseInstanceEngine.MYSQL , vpcSubnets: { subnetType: ec2.SubnetType.PRIVATE_ISOLATED , } , credentials: rds.Credentials.fromUsername ( "customName" ), } ); DynamoDB DynamoDB.2 英語タイトル:DynamoDB tables should have point-in-time recovery enabled 日本語訳:DynamoDB テーブルでは、ポイントインタ イムリ カバリが有効になっている必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-dynamodb-2 pointInTimeRecovery プロパティで ポイントインタイムリカバリ を有効にできます。 new dynamodb.Table ( this , "Table" , { partitionKey: { name: "pk" , type : dynamodb.AttributeType.STRING } , sortKey: { name: "sk" , type : dynamodb.AttributeType.STRING } , pointInTimeRecovery: true , } ); S3 S3.4 英語タイトル:S3 buckets should have server-side encryption enabled 日本語訳:S3 バケット では、サーバーサイドの暗号化を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-4 以下の例はS3マネージドの鍵(SSE-S3)を使ってS3 バケット の サーバサイド暗号化 を設定する例です。 new s3.Bucket ( this , "Bucket" , { encryption: s3.BucketEncryption.S3_MANAGED , } ); S3.5 英語タイトル:S3 buckets should require requests to use Secure Socket Layer 日本語訳:S3 バケット では、Secure Socket Layer を使用するためのリク エス トの要求が必要です https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-5 暗号化されていない通信を拒否する にはS3 バケット ポリシーを設定しますが、CDKでは enforceSSL プロパティで簡単に バケット ポリシーを追加してくれます。 new s3.Bucket ( this , "Bucket" , { enforceSSL: true , } ); S3.8 英語タイトル:S3 Block Public Access setting should be enabled at the bucket level 日本語訳:S3 ブロックパブリックアクセス設定は、 バケット レベルで有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-8 4つの ブロックパブリックアクセス 設定を全て有効にするには、 blockPublicAccess プロパティに BLOCK_ALL を指定します。 new s3.Bucket ( this , "Bucket" , { blockPublicAccess: s3.BlockPublicAccess.BLOCK_ALL , } ); S3.9 英語タイトル:S3 bucket server access logging should be enabled 日本語訳:S3 バケット サーバー アクセスログ 記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-9 serverAccessLogsBucket プロパティでS3 バケット の サーバーアクセスログ を出力する先のS3 バケット を、 serverAccessLogsPrefix プロパティで プレフィックス を指定します。 const logBucket = new s3.Bucket ( this , "LogBucket" , {} ); new s3.Bucket ( this , "Bucket" , { serverAccessLogsBucket: logBucket , serverAccessLogsPrefix: "prefix" , } ); S3.13 英語タイトル:S3 buckets should have lifecycle policies configured 日本語訳:S3 バケット では、ライフサイクルポリシーを設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-s3-13 lifecycleRules プロパティでS3 バケット の ライフサイクルポリシー を設定します。以下の例は30日後にIAクラスにオブジェクトを移動し、90日後にオブジェクトを削除するポリシーです。 new s3.Bucket ( this , "Bucket" , { lifecycleRules: [ { id: "log lifecycle" , transitions: [ { storageClass: s3.StorageClass.INFREQUENT_ACCESS , transitionAfter: cdk.Duration.days ( 30 ), } , ] , expiration: cdk.Duration.days ( 90 ), } , ] , } ); EFS EFS.1 英語タイトル: Amazon EFS should be configured to encrypt file data at rest using AWS KMS 日本語訳: Amazon EFS は、 AWS KMS を使用して保管中のファイルデータを暗号化するように設定する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-efs-1 encrypted プロパティで暗号化を設定しますが、CDK v2 ではデフォルト true なので、特別な実装は必要ありません。 (ドキュメントでは @aws-cdk/aws-efs:defaultEncryptionAtRest フィーチャーフラグを有効にしない限り encrypted のデフォルトは false である、とありますが、CDK v2ではこのフィーチャーフラグは廃止されており、有効になっているのと同じ動きになっています) new efs.FileSystem ( this , "FileSystem" , { vpc , encrypted: true , // CDK v2 ではデフォルトで true } ); SNS SNS .1 英語タイトル: SNS topics should be encrypted at rest using AWS KMS 日本語訳: SNS トピックは、 AWS KMS を使用して保管時に暗号化する必要があります。 https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-1 次のように暗号化に利用するKMSキーを取得し、 masterKey プロパティに渡すことで暗号化されます。 ※トピックがCloudWatch AlarmやEventbridgeルールのターゲットの場合、デフォルトキー(alias/ aws / sns )を利用できないため要注意です。 https://repost.aws/ja/knowledge-center/cloudwatch-receive-sns-for-alarm-trigger https://repost.aws/ja/knowledge-center/sns-not-getting-eventbridge-notification const key = kms.Key.fromLookup ( this , "SNSKey" , { aliasName: "alias/aws/sns" } ); new sns.Topic ( this , "Topic2" , { masterKey: key , } ); SNS .2 英語タイトル:Logging of delivery status should be enabled for notification messages sent to a topic 日本語訳:トピックに送信される通知メッセージでは、配信ステータスのログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sns-2 配信ステータスのログ記録 はCloudFormationでもサポートされておらず、CDKで実装するにはカスタムリソースで SDK 呼び出しをする必要があり( 参考 )、大変です。今後のアップデートに期待します。 SQS SQS.1 英語タイトル: Amazon SQS queues should be encrypted at rest 日本語訳: Amazon SQS キューは保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-sqs-1 2022年10月より、新しく作成されるSQSキューは デフォルトで暗号化される ようになったため、特別な実装は不要になりました。 new sqs.Queue ( this , "Queue" , { // 指定しなくても新規作成されるキューはデフォルトで暗号化される encryption: sqs.QueueEncryption.SQS_MANAGED , } ); API Gateway APIGateway.1 英語タイトル: API Gateway REST and WebSocket API logging should be enabled 日本語訳: API Gateway REST および WebSocket API ログ記録を有効にする必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-1 CloudWatch Logs ロググループを作成し、 loggingLevel 、 accessLogDestination 、 accessLogFormat プロパティで ログの出力 を設定します。 const log = new logs.LogGroup ( this , "ApiGatewayLog" , { logGroupName: "api-gateway-log" , retention: logs.RetentionDays.SIX_MONTHS , } ); new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , loggingLevel: apigateway.MethodLoggingLevel.INFO , accessLogDestination: new apigateway.LogGroupLogDestination ( log ), accessLogFormat: apigateway.AccessLogFormat.clf (), } , } ); APIGateway.4 英語タイトル: API Gateway should be associated with an AWS WAF web ACL 日本語訳: API Gateway は、 AWS WAF ウェブ ACL に関連付けられている必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-4 AWS WAFのWeb ACL を作成し、 API Gateway のステージに関連付けます。 コードを表示 const api = new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , } , } ); const wafWebAcl = new wafv2.CfnWebACL ( this , "WafV2WebAcl" , { defaultAction: { allow: {} } , // scopeは REGIONAL とする scope: "REGIONAL" , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "wafWebAcl" , } , rules: [ { // このサンプルではルールは AWSManagedRulesCommonRuleSet のみ name: "AWSManagedRulesCommonRuleSet" , priority: 1 , statement: { managedRuleGroupStatement: { vendorName: "AWS" , name: "AWSManagedRulesCommonRuleSet" , } , } , overrideAction: { none: {} } , visibilityConfig: { cloudWatchMetricsEnabled: true , sampledRequestsEnabled: true , metricName: "AWSManagedRulesCommonRuleSet" , } , } , ] , } ); const webAclAssociation = new wafv2.CfnWebACLAssociation ( this , "WebAclAssociation" , { resourceArn: `arn:aws:apigateway: ${ region } ::/restapis/ ${ api4.restApiId } /stages/dev` , webAclArn: wafWebAcl.attrArn , } ); webAclAssociation.addDependsOn ( wafWebAcl ); webAclAssociation.addDependsOn ( api.deploymentStage.node.defaultChild as cdk.CfnResource ); APIGateway.5 英語タイトル: API Gateway REST API cache data should be encrypted at rest 日本語訳: API Gateway REST API のキャッシュデータは、保管中に暗号化する必要があります https://docs.aws.amazon.com/ja_jp/securityhub/latest/userguide/securityhub-standards-fsbp-controls.html#fsbp-apigateway-5 cachingEnabled を true にすることでこのルールの検出対象になり、 cacheDataEncrypted プロパティでキャッシュデータの暗号化を有効にできます。 new apigateway.RestApi ( this , "RestApi" , { deployOptions: { stageName: "dev" , cachingEnabled: true , cacheDataEncrypted: true , } , } ); 大変長い記事になりました。読んでいただき、ありがとうございました。 私たちは同じチームで働いてくれる仲間を大募集しています!たくさんのご応募をお待ちしています。 セキュリティエンジニア(セキュリティ設計) 執筆: @kou.kinyo 、レビュー: Ishizawa Kento (@kent) ( Shodo で執筆されました )