AWS Security Hub 『基礎セキュリティのベストプラクティス』で失敗している検出結果をCSV出力したい【Python, Boto3】

2024.04.04

Security Hub 『基礎セキュリティのベストプラクティス』にて どのコントロールでどれだけのリソースが失敗しているのか を把握したいです。

もちろんマネジメントコンソールにて確認できますが、 細かいフィルタリングや分析を行うには、CSVなどの シート形式でまとまっていたほうが便利ですよね。

そこで今回は Python(Boto3)スクリプトを書いて、 失敗している検出結果をCSV出力してみます。

(補足) 一応 マネジメントコンソールからCSVを取得する機能はあります。ですが現時点では「全コントロールの検出結果を取得する」となると、各コントロールのページにてCSVダウンロードを押下しないといけなくて、大変です。

書いたスクリプト

以下に作成した Pythonスクリプトを記載します。 追加で pip install が必要なパッケージは boto3 のみです。

securityhub-inventory-failed-resources.py

import boto3
import csv
import logging
from operator import itemgetter
from datetime import datetime

logging.basicConfig(level=logging.INFO)
sh_client = boto3.client('securityhub')

def generate_sh_failed_findings_csv(file_path):
    header = ['ControlID', 'ControlTitle', 'Severity',
              'AccountName', 'AccountID',
              'ResourceType', 'ResourceID', 'ResourceNameTag',
              'ComplianceStatus', 'RecordStatus', 'WorkflowStatus']
    findings = []
    # securityhub.GetFindings 実行
    paginator = sh_client.get_paginator('get_findings')
    response_iterator = paginator.paginate(
        Filters={
            'ProductFields': [
                {
                    'Key': 'StandardsArn',
                    'Value': 'arn:aws:securityhub:::standards/aws-foundational-security-best-practices/v/1.0.0',
                    'Comparison': "EQUALS"
                }
            ],
            'ComplianceStatus': [
                {
                    'Value': 'FAILED',
                    'Comparison': 'EQUALS'
                }
            ],
            'RecordState': [
                {
                    'Value': 'ACTIVE',
                    'Comparison': 'EQUALS'
                }
            ]
        }
    )
    # CSV作成のための配列作成
    page_count = 0
    for page in response_iterator:
        page_count = page_count + 1
        logging.info(f'fetching page#{page_count}...')
        for finding in page.get('Findings'):
            resource_name = ''
            if finding.get('Resources')[0].get('Tags'):
                resource_name = finding.get('Resources')[0].get('Tags').get('Name')
            findings.append([
                finding.get('Compliance').get('SecurityControlId'),
                finding.get('Title'),
                finding.get('Severity').get('Label'),
                finding.get('AwsAccountName'),
                finding.get('AwsAccountId'),
                finding.get('Resources')[0].get('Type'),
                finding.get('Resources')[0].get('Id'),
                resource_name,
                finding.get('Compliance').get('Status'),
                finding.get('RecordState'),
                finding.get('Workflow').get('Status')
            ])
    # CSV出力
    rows = [header] + sorted(findings, key=itemgetter(0,3))
    with open(file_path, 'w', newline='') as csvfile:
        writer = csv.writer(csvfile, quoting=csv.QUOTE_ALL)
        writer.writerows(rows)

def main():
    datetime_now = datetime.now().strftime('%Y-%m-%d_%H-%M-%S')
    file_path = f'securityhub_{datetime_now}.csv'
    logging.info(f'[start] timestamp: {datetime_now}')
    generate_sh_failed_findings_csv(file_path)
    logging.info(f'[end] output: {file_path}')

main()

実行例

実行するにあたって、以下AWSアクションの権限が必要です。

  • SecurityHub:GetFindings

上記権限を持った認証情報を事前にセットして、 スクリプトを実行します。 以下実行サンプルです。

$ python3 ./securityhub-inventory-failed-resources.py
# INFO:botocore.credentials:Found credentials in environment variables.
# INFO:root:[start] timestamp: 2024-04-04_16-33-20
# INFO:root:fetching page#1...
# INFO:root:fetching page#2...
# INFO:root:fetching page#3...
# INFO:root:fetching page#4...
# INFO:root:[end] output: securityhub_2024-04-04_16-33-20.csv

securityhub_%Y-%m-%d_%H-%M-%S.csv といったCSVファイルが出力されます。 (以下 Excelで体裁調整して、 EC2.15 のみにフィルタを絞って表示させたものです)

img

各列の属性は以下のとおりです。

# 列名 内容
1 ControlID コントロールID
2 ControlTitle コントロールのタイトル
3 Severity 重要度(CRITICAL, HIGH, MEDIUM など)
4 AccountName アカウント名(注意1)
5 AccountID アカウントID
6 ResourceType リソースタイプ
7 ResourceID リソースID(ARN)
8 ResourceNameTag Nameタグの値
9 ComplianceStatus コンプライアンスステータス(FAILEDのみ)
10 RecordStatus レコードステータス(ACTIVEのみ)
11 WorkflowStatus ワークフローステータス(NEW, NOTIFIED, SUPPRESSED など)

(注意1) アカウント名は Organizations統合を利用していないと取得できない可能性があります。

Security Hub の管理アカウント上でスクリプトを実行することで、 複数アカウント横断で「失敗している検出結果」を取得できます。

おわりに

Security Hub のセキュリティチェック状況を棚卸ししてみました。 このCSVを使って コントロールのチューニングや、QuickSight 可視化などができると良さそうです。

以上、参考になれば幸いです。

補足

実行環境

  • OS: macOS Sonoma 14.3.1
  • Python: 3.12.2
  • boto3: 1.34.77

参考