CloudWatchダッシュボードを作成してみよう！！


# 作成するもの

CloudWatchのダッシュボードでカスタムウィジットという機能があります。Lambda関数を作成後、CloudWatchダッシュボードにLambda関数を登録します。CloudWatchダッシュボードを参照するとLambda関数が実行されて実行結果がダッシュボードに表示される仕組みです。今回は下記の様にSecurity Hubのレコードの件数を表示する機能を作成してみます。機能はSecurity HubのワークフローステータスがNEWでレコード状態がACTIVEなものをフィルタリング後、重要度で集計してレコード件数を表形式に表示するものになります。

![cw01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/c7b3004e-2e91-4293-9ba3-2e3be1c2accb.png)


# 作成手順

Lambdaコンソールに移動後、関数の作成をクリックします。下記項目を入力後、関数の作成をクリックします。

関数名：適当な関数名
ランタイム：Python3.12

![cw02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/5bd1a60a-92cf-4084-8d71-7245c560709e.png)

Lambda関数が作成されます。関数の設定を3か所変更します。最初はタイムアウト値です。一般設定からタイムアウト値を選択して、デフォルトの3秒から1分に変更します。

![cw03.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/9ba900cd-a759-4332-9f04-90e6f8f50156.png)

次はIAMロールへの権限追加を行います。アクセス権限のタブからロール名をクリックします。

![cw04.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/b78959a8-2eae-401d-9859-3ef514a2512b.png)

IAMロールの頁に移動します。許可を追加⇒ポリシーをアタッチを選択後、AWSSecurityHubFullAccessにチェックして許可を追加をクリックします。

![cw05.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/d358a599-4e5e-4608-aa88-48c04fc87169.png)

最後にLambdaのコードを記述します。コードタブに移動後、下記コードをコピペしてDeployをクリックします。これでLambda関数の用意は完了です。

![cw06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/7216abef-44ca-4dc4-9ec3-7976630f934c.png)

```python
import boto3
from collections import Counter, OrderedDict

securityhub = boto3.client('securityhub')

def lambda_handler(event, context):
    securityhub_findings = []
    next_token = None

    while True:
        if next_token:
            response = securityhub.get_findings(NextToken=next_token)
        else:
            response = securityhub.get_findings()

        filtered_findings = [
            finding for finding in response.get('Findings', [])
            if finding.get("WorkflowState") == "NEW" and finding.get("RecordState") == "ACTIVE"
        ]

        securityhub_findings.extend(filtered_findings)
        next_token = response.get('NextToken')

        if not next_token:
            break

    severity_counts = Counter(
        finding.get("Severity", {}).get("Label", "UNKNOWN") for finding in securityhub_findings
    )

    severity_order = ["CRITICAL", "HIGH", "MEDIUM", "LOW", "INFORMATIONAL"]
    sorted_counts = OrderedDict((key, severity_counts.get(key, 0)) for key in severity_order)

    severity_colors = {
        "CRITICAL": "#FFB3B3",
        "HIGH": "#FFFFB3",
        "MEDIUM": "#B3FFB3",
        "LOW": "#D3D3D3",
        "INFORMATIONAL": "#E6E6FA"
    }

    table_html = """
    <table border="1" style="border-collapse: collapse; text-align: center;">
        <tr>
            <th>Severity</th>
            <th>Count</th>
        </tr>
    """

    for label, count in sorted_counts.items():
        color = severity_colors.get(label, "#FFFFFF") 
        table_html += f"""
        <tr style="background-color: {color};">
            <td>{label}</td>
            <td>{count}</td>
        </tr>
        """

    table_html += "</table>"

    return table_html

```

ここからCloudWatchのダッシュボードを作成していきます。CloudWatchコンソールに移動後、ダッシュボード⇒ダッシュボードの作成の順にクリックします。適当なダッシュボード名を入力後、ダッシュボードの作成をクリックします。

![cw07.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/73df6ff2-bfb4-41b2-a914-39583a91a2f3.png)

カスタムウィジットを選択します。

![cw08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/49598f5a-e871-4edc-b247-eefb7ea566e4.png)

何も選択せず次へをクリックします。

![cw09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/2e96318a-2ed5-4c63-811b-f069b69947f6.png)

Lambda関数のタブで先ほど作成したLambda関数を選択します。

![cw10.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/4d30a207-8534-43c1-8ccf-f3034db852d9.png)

常に許可をクリックします。

![cw11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/6d8310c5-1d9f-4f04-9ee6-4ca73fe12a92.png)

ダッシュボードが表示されました。

![cw01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2523652/c7b3004e-2e91-4293-9ba3-2e3be1c2accb.png)