Security Hubで任意コントロールを無効化する(全リージョン)

Security Hubで、任意コントロールを無効化してみました。 全リージョンで同時対応します。
2023.04.20

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

Security Hubで不要なコントロールを無効化するとき、リージョンごとに無効化します。 手間だったので、Pythonでスクリプトを作ってみました。

おすすめの方

  • Security Hubのコントロールを全リージョンで無効化したい方

Security Hubのコントロールを無効化する

無効化したいコントロールのARNを取得する

下記を参考にして、無効にしたいコントロールのStandardsControlArnを取得します。

なお、有効にしている「セキュリティ基準」が複数ある場合は、それぞれのStandardsControlArnを取得します。 見た目が同じコントロールであっても、セキュリティ基準ごとにStandardsControlArnが異なります。 (検出結果.jsonを確認しました)

Security Hubの検出結果

{
    "StandardsControlArn": "arn:aws:securityhub:us-west-2:123456789012:control/aws-foundational-security-best-practices/v/1.0.0/IAM.6"
}
{
    "StandardsControlArn": "arn:aws:securityhub:us-west-2:123456789012:control/cis-aws-foundations-benchmark/v/1.2.0/1.14"
}

コントロールを無効化するスクリプト(Python)

下記を最初に記載していますが、人間のわかり易さのために記載している項目もあります。

  • StandardsControlArn
  • ControlId
  • Title
  • Reason
  • AfterStatus

最小限にするなら、StandardsControlArnだけで十分です。 この場合は、Pythonスクリプトの内容を適宜変更してください。

また、StandardsControlArnの「AWSアカウントID」や「リージョン」が異なっても、実行時に目的の値に置換するようにしています。 そのため、AWSアカウント毎やリージョン毎にARNを用意する必要はありません。使い回せます。

app.py

import copy
import re
import sys
import time

import boto3
import botocore

DEFAULT_FIX_REGION_NAME = 'ap-northeast-1'
DEFAULT_FIX_AWS_ACCOUNT_ID = '123456789012'


# ここに書く
# 下記の「AWSアカウントID」や「リージョン」が異なっても、実行時に上記の内容で検索して、目的の値に置換します
TARGET_CONTROLS = [
    {
        "StandardsControlArn": "arn:aws:securityhub:ap-northeast-1:123456789012:control/aws-foundational-security-best-practices/v/1.0.0/IAM.6",
        "ControlId": "IAM.6",
        "Title": "Hardware MFA should be enabled for the root user",
        "Reason": "(理由の参考)rootアカウントは、ソフトウェアMFAで管理しています。",
        "AfterStatus": "DISABLED",
    },
    {
        "StandardsControlArn": "arn:aws:securityhub:ap-northeast-1:123456789012:control/cis-aws-foundations-benchmark/v/1.2.0/1.14",
        "ControlId": "CIS.1.14",
        "Title": "Ensure hardware MFA is enabled for the root user",
        "Reason": "(理由の参考)rootアカウントは、ソフトウェアMFAで管理しています。",
        "AfterStatus": "DISABLED",
    },
]



ec2 = boto3.client('ec2')


def main(aws_account_id):
    print('############################################')
    print(f'AWS ACCOUNT ID: {aws_account_id}')
    print('')

    update_all_region(aws_account_id)


def update_all_region(aws_account_id: str):
    print('====================')

    regions = ec2.describe_regions()['Regions']
    for region in regions:
        region_name = region['RegionName']
        print(region_name)
        print('')

        update(aws_account_id, region_name)

        print('')
        print('')



def update(aws_account_id: str, region_name: str):
    securityhub = boto3.client('securityhub', region_name=region_name)

    for target in TARGET_CONTROLS:
        print('----------')

        # AWSアカウントID と リージョン をすり替える
        tmp = copy.deepcopy(target)
        tmp['StandardsControlArn'] = re.sub(DEFAULT_FIX_REGION_NAME, region_name, tmp['StandardsControlArn'])
        tmp['StandardsControlArn'] = re.sub(DEFAULT_FIX_AWS_ACCOUNT_ID, aws_account_id, tmp['StandardsControlArn'])

        print(tmp)

        update_control(
            securityhub,
            tmp['StandardsControlArn'],
            tmp['AfterStatus'],
            tmp['Reason'],
        )

        print('')

        time.sleep(0.1)



def update_control(securityhub, standards_control_arn: str, status: str, reason: str):
    try:
        # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/securityhub/client/update_standards_control.html
        securityhub.update_standards_control(
            StandardsControlArn=standards_control_arn,
            ControlStatus=status,
            DisabledReason=reason,
        )
    except botocore.exceptions.ClientError as e:
        if e.response['Error']['Code'] == 'ResourceNotFoundException':
            # データなしのコントロールは、存在しない扱いのため、本APIが失敗する。
            # そのため、例外キャッチして無視する
            print(e)
        else:
            raise


if __name__=='__main__':
    if len(sys.argv) != 2:
        print('[usage] python app.py 123456789012')
        exit()

    aws_account_id = sys.argv[1]
    main(aws_account_id)

スクリプトを実行する

python app.py 123456789012

コントロールが無効になったことを確認する

見た目が反映されたり、既存の結果がアーカイブされるまで、数日の猶予があります。焦らないでください。

コントロールの確認画面を表示すれば、無効になったことを確認できます。

コントロール画面

コントロールが無効化された(コントロール画面)

セキュリティ基準画面

コントロールが無効化された(セキュリティ基準画面)

コントロールが無効化された(セキュリティ基準画面)

無効なコントロールを取得するコマンド

次のコマンドでも確認できます。

$ aws securityhub describe-standards-controls \
    --standards-subscription-arn "arn:aws:securityhub:ap-northeast-1:123456789012:subscription/aws-foundational-security-best-practices/v/1.0.0" \
    --query 'Controls[?ControlStatus==`DISABLED`]'

standards-subscription-arnの値は、下記を参考に適宜変更してください。

さいごに

Security Hubのコントロールを無効化してみました。 AWSアカウント毎、リージョン毎に変更する手間が少しでも楽になれば幸いです。

参考