AWS CLIでSecurityHubの検出結果とコントールをまとめて抑制してみた

2022.10.31

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。たかやまです。

SecurityHubで検出結果の棚卸し項目の対応をする時、問題ない項目については抑制機能を使うと思います。
SecurityHubの抑制対応をコンソールからポチポチしていたのですが、件数が多いとデータ読み込みが重かったり、ページ数が多かったりと管理が大変になります。

そこで今回はAWS CLIを使ったまとめて抑制する方法をご紹介したいと思います。

検出結果単位での抑制

コンプライアンスステータスが失敗のものをCLIで抽出する

AWSコンソールでフィルターしたときの内容...

こちらの内容をCLIで抽出するときのコマンドは以下のとおりです。
クエリ部分で表示したい内容を適宜調整してください。
(CLIは見たい内容だけqueryで選択できるのがいいですね)

aws securityhub get-findings \
--filters '{"ComplianceStatus":[{"Value":"FAILED","Comparison":"EQUALS"}],"RecordState":[{"Value":"ACTIVE","Comparison":"EQUALS"}],"WorkflowStatus":[{"Value":"NEW","Comparison":"EQUALS"},{"Value":"NOTIFIED","Comparison":"EQUALS"}]}' \
--query 'sort_by(Findings,&Compliance.SecurityControlId)[].[Compliance.SecurityControlId,Resources[] | [0].Id]' \
--output table

# 出力結果
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|                                                                                   GetFindings                                                                                   |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+
|  CloudFront.4    |  arn:aws:cloudfront::xxxxxxxxxxxx:distribution/xxxxxxxxxxxx                                                                                                  |
|  CloudFront.4    |  arn:aws:cloudfront::xxxxxxxxxxxx:distribution/xxxxxxxxxxxx                                                                                                  |
|  DynamoDB.1      |  arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/xxxxxxxxxxxx                                                                                             |
|  DynamoDB.2      |  arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/xxxxxxxxxxxx                                                                                             |
|  DynamoDB.6      |  arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/xxxxxxxxxxxx                                                                                             |
+------------------+--------------------------------------------------------------------------------------------------------------------------------------------------------------+

コンプライアンスステータスが失敗のものをまとめて抑制する

検出結果を確認して問題ない場合、まとめて抑制したいケースがあります。
コンソールでも複数選択でまとめて抑制可能ですが最大20件しか選択できないため、20件以上ある場合には複数回繰り返す必要があります。

以下のコマンドでは、先程抽出したコンプライアンスステータスが失敗のものをまとめて抑制するコマンドになります。

aws securityhub get-findings \
--filters '{"ComplianceStatus":[{"Value":"FAILED","Comparison":"EQUALS"}],"RecordState":[{"Value":"ACTIVE","Comparison":"EQUALS"}],"WorkflowStatus":[{"Value":"NEW","Comparison":"EQUALS"},{"Value":"NOTIFIED","Comparison":"EQUALS"}]}' \
--query 'sort_by(Findings,&Id)[].[Id,ProductArn]' \
--output text \
| while read finding_id product_arn; do
    aws securityhub batch-update-findings \
    --finding-identifiers Id=${finding_id},ProductArn=${product_arn} \
    --workflow Status='SUPPRESSED' \
    --query 'ProcessedFindings[].Id' \
    --output text
done

ワークフローステータスで抑制しているものをCLIで抽出する

抑制した後、抑制済みのものを確認する際には以下のコマンドを実施します。
このとき、こちらのブログのようにNoteを記載していると、あとの確認で抑制した理由がわかりやすくなるのでおすすめです。

aws securityhub get-findings \
--filters '{"RecordState":[{"Value":"ACTIVE","Comparison":"EQUALS"}],"WorkflowStatus":[{"Value":"SUPPRESSED","Comparison":"EQUALS"}]}' \
--query 'sort_by(Findings,&Compliance.SecurityControlId)[].[Compliance.SecurityControlId,Resources[] | [0].Id,Note.Text]' \
--output table

# 出力結果
# Noteを記載していないものはNoneで出力される
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|                                                                 GetFindings                                                                                                                                                         |
+---------------+------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+
|  CloudFront.4 |  arn:aws:cloudfront::xxxxxxxxxxxx:distribution/E16UxxxxxVS1BZ                                                                      |  オリジンはS3を採用しておりかつフェイルオーバーを実装するほどではないため抑制  |
|  DynamoDB.1   |  arn:aws:dynamodb:ap-northeast-1:xxxxxxxxxxxx:table/xxxxxxxxxxxxx-aha-DynamoDBTable-197F6M18IOT28                                  |  AHAで作成されるリソースのため                                                 |
|  KMS.2        |  arn:aws:iam::xxxxxxxxxxxx:role/cdk-hnb659fds-deploy-role-xxxxxxxxxxxx-ap-northeast-1                                              |  CDKで作成されるリソースのため                                                 |
|  SNS.2        |  arn:aws:sns:ap-northeast-1:xxxxxxxxxxxx:StorageStack-xxxxxxx                                                                      |  None                                                                          |
+---------------+------------------------------------------------------------------------------------------------------------------------------------+--------------------------------------------------------------------------------+

コントロール単位での抑制

さきほどは検出結果単位で抑制していましたが、今度はコントロール単位の抑制方法をご紹介します。

全リージョンのコントロールをまとめて無効する

アカウント内で抑制しても問題ないコントロールがあった場合、コントロール単位の場合、SecurityHubを有効化しているリージョンごとに無効化対応をする必要があります。
以下のコマンドでは指定したコントロールを全リージョンで無効化する処理を行います。

control_ids=( # 無効対象のコントロールIDを記載する(複数可)
  CloudFormation.1
  S3.1
)
reasons=( # 無効理由を記載(複数可) ※コントロールIDの対になる順番で記載すること
  CloudFormation通知の対応は必須ではないため無効化
  バケットレベルでブロックパブリックアクセスを有効にするため無効化
)
account_id=$(aws sts get-caller-identity --query Account --output text)
aws ec2 describe-regions --query Regions[].[RegionName] --output text \
| while read region; do
    echo "### ${region} ###";
    for ((i=0; i<${#control_ids[@]}; i++)); do
      aws securityhub update-standards-control --standards-control-arn arn:aws:securityhub:${region}:${account_id}:control/aws-foundational-security-best-practices/v/1.0.0/${control_ids[i]} \
      --control-status DISABLED \
      --disabled-reason ${reasons[i]} \
      --region ${region}
    done
  done

# 実行結果 リージョンによっては存在しないコントロールもあるのでエラーあり
### eu-north-1 ###

An error occurred (ResourceNotFoundException) when calling the UpdateStandardsControl operation: StandardsControl not found
### ap-south-1 ###
### eu-west-3 ###

An error occurred (ResourceNotFoundException) when calling the UpdateStandardsControl operation: StandardsControl not found
### eu-west-2 ###

コントロールステータスで無効にしているものをCLIで抽出する

無効化済みのコントロールを確認はこちらのコマンドを実行します。

account_id=$(aws sts get-caller-identity --query Account --output text)
aws ec2 describe-regions --query Regions[].[RegionName] --output text \
| while read region; do
    echo "### ${region} ###";
    aws securityhub describe-standards-controls \
    --standards-subscription-arn arn:aws:securityhub:${region}:${account_id}:subscription/aws-foundational-security-best-practices/v/1.0.0 \
    --query 'sort_by(Controls,&ControlId)[?ControlStatus==`DISABLED`].[ControlId,ControlStatus,DisabledReason]' \
    --output table \
    --region ${region}
done

#実行結果
### eu-north-1 ###
--------------------------------------------------------------------------------------------------
|                                    DescribeStandardsControls                                   |
+--------------+-----------+---------------------------------------------------------------------+
|  CloudTrail.5|  DISABLED |  Classmethod SecureAccount Settings                                 |
|  Config.1    |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  EC2.8       |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  IAM.6       |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  S3.1        |  DISABLED |  バケットレベルでブロックパブリックアクセスを有効にするため無効化   |
+--------------+-----------+---------------------------------------------------------------------+
### ap-south-1 ###
------------------------------------------------------------------------------------------------------
|                                      DescribeStandardsControls                                     |
+------------------+-----------+---------------------------------------------------------------------+
|  CloudFormation.1|  DISABLED |  CloudFormation通知の対応は必須ではないため無効化                   |
|  CloudTrail.5    |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  Config.1        |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  EC2.8           |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  IAM.6           |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  S3.1            |  DISABLED |  バケットレベルでブロックパブリックアクセスを有効にするため無効化   |
+------------------+-----------+---------------------------------------------------------------------+
### eu-west-3 ###
--------------------------------------------------------------------------------------------------
|                                    DescribeStandardsControls                                   |
+--------------+-----------+---------------------------------------------------------------------+
|  CloudTrail.5|  DISABLED |  Classmethod SecureAccount Settings                                 |
|  Config.1    |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  EC2.8       |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  IAM.6       |  DISABLED |  Classmethod SecureAccount Settings                                 |
|  S3.1        |  DISABLED |  バケットレベルでブロックパブリックアクセスを有効にするため無効化   |
+--------------+-----------+---------------------------------------------------------------------+
### eu-west-2 ###
...

最後に

件数が多いとAWSコンソールだけで対応するのはきついものがありましたが、AWS CLIを使うことでSecurity Hubの棚卸しがちょっと楽にできると思います。
ぜひ、データ件数が多い場合にはAWS CLIをご活用いただければと思います。

やりすぎない程度に抑制機能を活用して、SecurityHub 100%を目指していきましょう!

以上、たかやま(@nyan_kotaroo)でした。