IncidentManagerの対応プランで複数サービスでも復旧可能なDocumentを作成しました

## これは何?
以前[インフラ技術基礎勉強会 #4](https://infra365.connpass.com/event/286297/)にてIncidentManager についてLTをさせていただきました。

<script defer class="speakerdeck-embed" data-id="0f6acf59b3fe4caab81db783c2ea27e4" data-ratio="1.7772511848341233" src="//speakerdeck.com/assets/embed.js"></script>


そこで対応プランで実行するランブック用のSSM Documentを自作したため、今回は1個の対応プランで複数サービスを復旧するための条件分岐について解説したいと思います。

## 何故つくろうと思ったのか？
EC2やRDSなどの対応プランごとにサービスを作れば作り込まなくて済むのはもちろんなんですが対応プランは1個作成するだけで月額で7ドル請求されます。

https://aws.amazon.com/jp/systems-manager/pricing/

そのため、小規模の案件や試験的に導入してみたい方などはだと運用費の方が高くなってしまうのでなるべくコストを抑える場合は1個の対応プランで複数サービスを実行する必要がありました。


## サービスごとの条件分岐はどうやってやるのか

以下のスライドのp13に条件分岐を掲載してます。
<script defer class="speakerdeck-embed" data-slide="13" data-id="0f6acf59b3fe4caab81db783c2ea27e4" data-ratio="1.7772511848341233" src="//speakerdeck.com/assets/embed.js"></script>


情報取得部分では、以下のドキュメントを参考に取得しています。
https://docs.aws.amazon.com/ja_jp/incident-manager/latest/userguide/tutorials-runbooks.html


上記のリンクをわかりやすく解説すると、インシデント発生時、インシデントに対して一意のインシデントレコードArnが払い出されます。インシデントの内容は以下のようになっていて時系列ごとにインシデントが起票されたとか、Automationが実行された等のイベントが羅列されます。

その中で「SSM Incident Trigger」と合致するeventTypeからeventIdを抽出します。
```
$ aws ssm-incidents list-timeline-events --incident-record-arn arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]
{
    "eventSummaries": [
        {
            "eventId": "xxxxxxxxxxxxxxxxxxxxxxxxxx",
            "eventTime": "2023-09-03T04:00:52.788000+09:00",
            "eventType": "SSM Contacts Page Acknowledgement for Incident",
            "eventUpdatedTime": "2023-09-03T04:00:53.183000+09:00",
            "incidentRecordArn": "arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]"
        },
        {
            "eventId": "yyyyyyyyyyyyyyyyyyyyyyyyyyy",
            "eventTime": "2023-09-03T04:00:14.418000+09:00",
            "eventType": "SSM Incident Record Update",
            "eventUpdatedTime": "2023-09-03T04:00:14.418000+09:00",
            "incidentRecordArn": "arn:aws:ssm-incidents::[アカウント]:incident-record/test-plan/[インシデントレコードArn]"
        },

...skipping...

        {
            "eventId": "zzzzzzzzzzzzzzzzzzzzzzzzzzz",
            "eventTime": "2023-09-03T03:58:23+09:00",
            "eventType": "SSM Automation Execution Update for Incident",
            "eventUpdatedTime": "2023-09-03T03:58:24.618000+09:00",
            "incidentRecordArn": "arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]"
        },
        {
            "eventId": "[SSM Incident Trigger イベントID]",
            "eventTime": "2023-09-03T03:58:22+09:00",
            "eventType": "SSM Incident Trigger",
            "eventUpdatedTime": "2023-09-03T03:58:23.595000+09:00",
            "incidentRecordArn": "arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]"
        }
    ]
}

```


「SSM Incident Trigger」のイベントIDを基にget-timeline-eventを実行するといかのような出力結果になります。
以下の内容は対応プランが呼び出されたCloudwatch Alarm のアラーム情報になります。
```bash
$ aws ssm-incidents get-timeline-event --event-id [イベントID] --incident-record-arn arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]
{
    "event": {
        "eventData": "{\"createdIncident\":true,\"incidentSource\":\"aws.cloudwatch\",\"triggerArn\":\"arn:aws:cloudwatch:ap-northeast-1:[アカウントID]:alarm:test-alert_cwa_process_httpd\",\"rawData\":\"{\\\"version\\\":\\\"0\\\",\\\"detail-type\\\":\\\"CloudWatch Alarm Incident Manager Action State Change\\\",\\\"source\\\":\\\"aws.cloudwatch\\\",\\\"account\\\":\\\"[アカウントID]\\\",\\\"time\\\":\\\"2023-09-02T18:58:22Z\\\",\\\"region\\\":\\\"ap-northeast-1\\\",\\\"resources\\\":[\\\"arn:aws:cloudwatch:ap-northeast-1:[アカウントID]:alarm:test-alert_cwa_process_httpd\\\"],\\\"detail\\\":{\\\"alarmName\\\":\\\"test-alert_cwa_process_httpd\\\",\\\"state\\\":{\\\"reason\\\":\\\"Threshold Crossed: 2 out of the last 2 datapoints [0.0 (02/09/23 18:53:00), 0.0 (02/09/23 18:48:00)] were less than or equal to the threshold (0.0) (minimum 2 datapoints for OK -> ALARM transition).\\\",\\\"reasonData\\\":\\\"{\\\\\\\"version\\\\\\\":\\\\\\\"1.0\\\\\\\",\\\\\\\"queryDate\\\\\\\":\\\\\\\"2023-09-02T18:58:22.757+0000\\\\\\\",\\\\\\\"startDate\\\\\\\":\\\\\\\"2023-09-02T18:48:00.000+0000\\\\\\\",\\\\\\\"statistic\\\\\\\":\\\\\\\"Average\\\\\\\",\\\\\\\"period\\\\\\\":300,\\\\\\\"recentDatapoints\\\\\\\":[0.0,0.0],\\\\\\\"threshold\\\\\\\":0.0,\\\\\\\"evaluatedDatapoints\\\\\\\":[{\\\\\\\"timestamp\\\\\\\":\\\\\\\"2023-09-02T18:53:00.000+0000\\\\\\\",\\\\\\\"sampleCount\\\\\\\":5.0,\\\\\\\"value\\\\\\\":0.0},{\\\\\\\"timestamp\\\\\\\":\\\\\\\"2023-09-02T18:48:00.000+0000\\\\\\\",\\\\\\\"sampleCount\\\\\\\":5.0,\\\\\\\"value\\\\\\\":0.0}]}\\\",\\\"timestamp\\\":\\\"2023-09-02T18:58:22.759+0000\\\",\\\"transitionTimestamp\\\":\\\"2023-09-02T18:58:22.759+0000\\\",\\\"value\\\":\\\"ALARM\\\"},\\\"previousState\\\":{\\\"reason\\\":\\\"Threshold Crossed: 2 out of the last 5 datapoints [5.0 (02/09/23 18:34:00), 5.0 (02/09/23 18:29:00)] were not less than or equal to the threshold (0.0) (minimum 2 datapoints for ALARM -> OK transition).\\\",\\\"reasonData\\\":\\\"{\\\\\\\"version\\\\\\\":\\\\\\\"1.0\\\\\\\",\\\\\\\"queryDate\\\\\\\":\\\\\\\"2023-09-02T18:39:12.988+0000\\\\\\\",\\\\\\\"startDate\\\\\\\":\\\\\\\"2023-09-02T18:29:00.000+0000\\\\\\\",\\\\\\\"statistic\\\\\\\":\\\\\\\"Average\\\\\\\",\\\\\\\"period\\\\\\\":300,\\\\\\\"recentDatapoints\\\\\\\":[5.0,5.0],\\\\\\\"threshold\\\\\\\":0.0,\\\\\\\"evaluatedDatapoints\\\\\\\":[{\\\\\\\"timestamp\\\\\\\":\\\\\\\"2023-09-02T18:34:00.000+0000\\\\\\\",\\\\\\\"sampleCount\\\\\\\":5.0,\\\\\\\"value\\\\\\\":5.0},{\\\\\\\"timestamp\\\\\\\":\\\\\\\"2023-09-02T18:29:00.000+0000\\\\\\\",\\\\\\\"sampleCount\\\\\\\":3.0,\\\\\\\"value\\\\\\\":5.0}]}\\\",\\\"timestamp\\\":\\\"2023-09-02T18:39:12.992+0000\\\",\\\"transitionTimestamp\\\":\\\"2023-09-02T18:39:12.992+0000\\\",\\\"value\\\":\\\"OK\\\"},\\\"configuration\\\":{\\\"metrics\\\":[{\\\"id\\\":\\\"02c52b9b-6a82-35c8-6a5a-xxxxxxxxxx\\\",\\\"metricStat\\\":{\\\"metric\\\":{\\\"namespace\\\":\\\"CWAgent\\\",\\\"name\\\":\\\"procstat_lookup_pid_count\\\",\\\"dimensions\\\":{\\\"exe\\\":\\\"httpd\\\",\\\"InstanceId\\\":\\\"i-xxxxx\\\",\\\"ImageId\\\":\\\"ami-xxxxx\\\",\\\"pid_finder\\\":\\\"native\\\",\\\"InstanceType\\\":\\\"t2.micro\\\"}},\\\"period\\\":300,\\\"stat\\\":\\\"AVERAGE\\\"},\\\"returnData\\\":true}]}}}\"}",
        "eventId": "[イベントID]",
        "eventTime": "2023-09-03T03:58:22+09:00",
        "eventType": "SSM Incident Trigger",
        "eventUpdatedTime": "2023-09-03T03:58:23.595000+09:00",
        "incidentRecordArn": "arn:aws:ssm-incidents::[アカウントID]:incident-record/test-plan/[インシデントレコードArn]"
    }
}
```

ここで注目したいのは「namespace」と「dimensions」の2つの情報になります。

「namespace」では、CWメトリクスの名前空間の情報を返します。そのため、　EC2のアラートなのか、RDSのアラートなのか等はここで判断することができます。

「dimensions」ではアラートがあったCWメトリクスがここに記載されます。そのため、CPUの高騰なのかディスクの枯渇なのかを判断することができます。またこのDimensionsからインスタンスIDなどを取得することもできるため、アラートがあったインスタンスを特定することができます。


上記の出力結果は、namespaceがCWAgentになっており、dimensionsが"exe:httpd"になってます。
そのため、EC2インスタンス上のCWAget から取得したカスタムメトリクスで、httpdのプロセス数が0になったため、アラートが発生したものになります。そのため、プロセス監視の異常であることが判断できます。

後は、[こちら](https://docs.aws.amazon.com/ja_jp/incident-manager/latest/userguide/tutorials-runbooks.html)のようにJsonDecodeなどを実行してデータを取り出すことができれば、いくらでも条件分岐は可能になります。


## 終わりに

条件分岐などを追加して自分なりに作成してみた結果、以下のようなランブックを作成しましたのでよろしければ是非。。
https://github.com/atsw0q0/aws_ssm_documents_templates/blob/0243f6ef3cc1f8d142f40cd67c4af7b0521a3c7a/templates/ssm-im/lt_20230903/im_runbook.yaml

1つのファイルで条件分岐や復旧コマンドを管理するのはかなりしんどくなるので別Automaiton化して呼び出すように今後は改善していきたい。。。