AWS Health 組織ビューの情報をCSV出力するCLIツールをつくりました

:::note info
本記事で紹介しているツールは AWS Health API を使用しています。AWS Health APIを使用するには、ビジネスプラン以上の AWS Support 契約が必要です。
:::

## はじめに
全国の AWS Organizaitons 管理者の皆さん、AWS Health に通知されるイベントの管理はどうされていますか？ AWS を利用していると日々様々な通知が飛んでくるのではないかと思います。

これらのイベントは、システムの可用性や信頼性に影響を与える可能性があるため、適切に管理する必要があります。直近では Amazon RDS の証明書更新 (8月) や AWS Lambda の Python 3.8 ランタイムバージョンのサポート終了 (10月) など大きなイベントも待ち構えています。

組織内で多数のアカウントを管理している場合、手作業でイベントを確認し、必要な情報を収集するのはそれなりに手間がかかるのではないでしょうか。

## AWS Health Exporter という CLI ツールをつくりました

https://github.com/hayao-k/aws-health-exporter

AWS Health Exporterは、AWS Health の組織ビューから、イベント情報を取得するためのコマンドラインツールです。サービス名やステータスなどでイベントをフィルタリングし、対象アカウントおよびリソース ID の詳細を CSV ファイルにエクスポートできます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/3c7933a4-8505-b172-f8ed-8d4ab3ac5a73.png)

### 主な機能
* **AWS Organizations 対応:**
AWS Health の組織ビューから情報を取得します。スタンドアロンアカウントでは使用できませんが、単一アカウントの情報のみを出力するオプションがあります。

* **CSV エクスポート:**
データを CSV 形式で整形してエクスポートするため、保存、共有、分析が簡単です。

* **イベントフィルタリング:**
サービス名やステータスなどの条件でイベントをフィルタリングし、目的のイベントを見つけやすくします。

* **リソースフィルタリング:**
特定のステータスコード (IMPAIRED, UNIMPAIRED, UNKNOWN, PENDING, or RESOLVED) にマッチするリソースのみを取得できます。


### AWS Health の組織ビューについて
組織ビューを有効にすると、組織内のすべてのアカウントの AWS Health イベントを集約できます。データは 90 日間保持され、組織の管理アカウントまたは委任された管理者アカウントのユーザー/ロールが情報を参照できます。

AWS Health ダッシュボードの「組織の状態」から設定、参照できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/feb9d049-89ba-719f-8ed6-170a7675f823.png)

### このツールでエクスポートできる情報
組織ビューでは各イベントに対し、

* 影響を受けるアカウント
* 影響を受けるリソース数とステータスの内訳
* 各アカウント内で影響を受けるリソース

といった情報を確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/125105/6fcd9558-8a32-7206-e4ea-15955700304b.png)

これらの情報を CSV 形式で出力します。

## ツールを使用するための前提条件
* AWS Health の組織ビューの有効化が完了していること
* AWS Health および AWS Organizations にアクセスするための AWS 認証情報
    * 組織ビューを利用するため、管理者アカウントまたは委任された管理者アカウントの認証情報が必要
* ビジネスプラン以上の AWS サポート契約
    * AWS Helath API の利用に必要


## 使い方
GitHub リポジトリのリリースページから利用環境に合わせて最新のバイナリを取得してください。

https://github.com/hayao-k/aws-health-exporter/releases

```shell-session
wget https://github.com/hayao-k/aws-health-exporter/releases/download/v0.8.1/aws-health-exporter_0.8.1_linux_amd64.tar.gz
tar xvf aws-health-exporter_0.8.1_linux_amd64.tar.gz
```

任意のフラグを指定し、コマンドを実行します。2024/5/15 時点の最新バージョン (v0.8.1) で使用できるフラグは以下の通りです。

* `--event-filter`, `--filter`, `-f`: サービス、ステータスなどの条件でイベントをフィルタリングします
* `--status-code`, `-c`: ステータスコードで出力するリソースをフィルタリングします。指定可能な値は IMPAIRED, UNIMPAIRED, UNKNOWN, PENDING, RESOLVED です
* `--echo`, `-e`: CSV の内容を標準出力にもエコーします
* `--profile`, `-p`: 任意の AWS 認証情報のプロファイル名を指定します
* `--account-id`, `-i`: 単一のアカウント ID を指定して、そのアカウントの情報のみを処理します
* `--output-file`, `--file-name`, `o`: CSV に任意のファイル名を指定できます (指定しない場合はツールデフォルトのファイル名を使用)

### イベントのフィルタリング
`--event-filter`オプションを使用すると、以下のフィルタリング条件を指定できます。

| フィールド        | 説明                   | 指定可能な値                                                      |
|-------------------|------------------------|-------------------------------------------------------------------|
| `service`         | サービス名             | e.g., `LAMBDA`, `RDS`, `EKS`                                      |
| `status`          | イベントのステータス   | `open`, `closed`, `upcoming`                                      |
| `category`        | イベントのカテゴリ     | `issue`, `accountNotification`,<br> `scheduledChange`, `investigation`|
| `region`          | リージョン             | e.g., `us-east-1`                               |
| `startTime`       | イベントの開始時刻     | ISO 8601 date format                                              |
| `endTime`         | イベントの終了時間     | ISO 8601 date format                                              |
| `lastUpdatedTime` | イベントの最終更新日時 | ISO 8601 date format                                              |

`startTime`, `endTime`, `lastUpdatedTime` では、ISO 8601日付形式を使用して `from` と `to` で時間範囲を指定できます。

- `{from:YYYY-MM-DDTHH:MM:SSZ,to:YYYY-MM-DDTHH:MM:SSZ}`


### コマンドの例
```sh
# ステータスがopenのRDSイベントをフィルタリング
./health-exporter ----event-filter service=RDS,status=open

# ステータスがupcomingのLAMBDA イベントをフィルタリングし、結果は標準出力にもエコーする
./health-exporter --event-filter service=LAMBDA,status=upcoming --echo

# 東京リージョンのイベントを最終更新日を指定してフィルタリング
./health-exporter ----event-filter "lastUpdatedTime={from=2024-04-01T00:00:00Z,to=2024-04-30T23:59:59Z},region=ap-northeast-1"

# 指定したファイル名で未対応のリソースのみをエクスポート
./health-exporter --status-code PENDING --output-file my_event_details.csv

# 任意の AWS Profile を指定
./health-exporter --profile my-profile

# 特定のアカウントのみをフィルタリングして出力
./health-exporter --account-id 123456789012
```

## 実行例
コマンドを実行すると、対話型のプロンプトが表示されます。以下の例では `--event-filter` フラグで AWS Lambda に関連する upcoming ステータスのイベントのみを抽出しています。

```shell-session
$ health-exporter --event-filter service=LAMBDA,status=upcoming --status-code PENDING
Use the arrow keys to navigate: ↓ ↑ → ← 
? Select an event: 
  ▸ LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (us-east-1, 2024-10-14 07:00:00)
    LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (ap-northeast-1, 2024-10-14 07:00:00)
    LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (ap-northeast-1, 2024-06-12 07:00:00)
    LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (ap-southeast-2, 2024-10-14 07:00:00)
↓   LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (us-east-1, 2024-06-12 07:00:00)
```

プロンプトから、出力したいイベントを選択します。選択後、ツールは関連するアカウントとエンティティの情報を収集し、CSVファイルに出力します。

```sh
✔ LAMBDA - AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT (us-east-1, 2024-10-14 07:00:00)
Event details have been written to AWS_LAMBDA_PLANNED_LIFECYCLE_EVENT_2024-10-14_07-00-00_us-east-1_PENDING.csv.
```

出力される CSV は以下のような内容です。この例ではコマンド実行時に `--status-code PENDING` を指定しているため、 PENDING ステータスのリソースのみが出力されます。

```text
Account ID,Account Name,Region,Identifier,Status,Last Updated
000000000000,account-0000,us-east-1,arn:aws:lambda:us-east-1:000000000000:function:Old_Runtime_Lambda_Function-1PBKPZPFSJ058,PENDING,2024-04-21 20:11:29
111111111111,account-1111,us-east-1,arn:aws:lambda:us-east-1:111111111111:function:Old_Runtime_Lambda_Function-uuTi2u7DbooD,PENDING,2024-04-21 20:11:29
111111111111,account-1111,us-east-1,arn:aws:lambda:us-east-1:111111111111:function:Old_Runtime_Lambda_Function-omdieC8Umobo,PENDING,2024-04-21 20:11:29
222222222222,account-2222,us-east-1,arn:aws:lambda:us-east-1:222222222222:function:Old_Runtime_Lambda_Function-ULZ27BYSQ0MN,PENDING,2024-04-21 20:11:29
222222222222,account-2222,us-east-1,arn:aws:lambda:us-east-1:222222222222:function:Old_Runtime_Lambda_Function-10YNGBMU46VP9,PENDING,2024-04-21 20:11:29
222222222222,account-2222,us-east-1,arn:aws:lambda:us-east-1:222222222222:function:Old_Runtime_Lambda_Function-CEgHAu41udFy,PENDING,2024-04-21 20:11:29
333333333333,account-3333,us-east-1,arn:aws:lambda:us-east-1:333333333333:function:Old_Runtime_Lambda_Function-zNKRpLWP0pXB,PENDING,2024-04-21 20:11:29
333333333333,account-3333,us-east-1,arn:aws:lambda:us-east-1:333333333333:function:Old_Runtime_Lambda_Function-24ES8MRQJ9R6,PENDING,2024-04-21 20:11:29
444444444444,account-4444,us-east-1,arn:aws:lambda:us-east-1:444444444444:function:Old_Runtime_Lambda_Function-134QIS8IYF84K,PENDING,2024-04-21 20:11:29
444444444444,account-4444,us-east-1,arn:aws:lambda:us-east-1:444444444444:function:Old_Runtime_Lambda_Function-B97VeyrZNXIy,PENDING,2024-04-21 20:11:29
```
出力された CSV には、アカウントID、アカウント名、リージョン、識別子、ステータス、最終更新日時といった情報が含まれています。

## 仕組み
主に 3 つの AWS Health API を使用しています。

* [DescribeEventsForOrganization API](https://docs.aws.amazon.com/health/latest/APIReference/API_DescribeEventsForOrganization.html)
* [DescribeAffectedAccountsForOrganization API](https://docs.aws.amazon.com/health/latest/APIReference/API_DescribeAffectedAccountsForOrganization.html)
* [DescribeAffectedEntitiesForOrganization API](https://docs.aws.amazon.com/health/latest/APIReference/API_DescribeAffectedEntitiesForOrganization.html)


### DescribeEventsForOrganization API
コマンドラインで指定されたフィルタ条件に基づいて DescribeEventsForOrganization API を呼び出し、該当するイベントを取得します。この API はイベントの概要のみが返されるため、影響を受けるアカウントや影響を受けるリソースの情報は含まれません。

### DescribeAffectedAccountsForOrganization API 
この API は選択されたイベントの影響を受ける組織内のアカウントのリストを取得します。

### DescribeAffectedEntitiesForOrganization API
この API は組織内の 1 つ以上のアカウントの 1 つ以上のイベントの影響を受けたエンティティのリストを返します。

対話型のプロンプトでユーザーがイベントを選択すると、これらの API から取得した情報を整形し、CSV ファイルとして出力します。

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