AWSのELBを死活監視し、アラームをslackに通知する

# 目的
EC2へのパケット転送を行うELBの死活監視を行い、SNS(slack)に通知させて障害対応を早めるため、AWSのサービスで実装しました。

# 概要
全体の構成は以下の通りです。ターゲットグループとしてEC2を１台指定したELB(アプリケーションELB)に対して、CloudWatchで死活監視を行い、ダウンを検知したらlambdaを起動させ、SNS経由でslackに通知させるという内容です。lambdaで指定するslackのURLをKMSで暗号/復号化しています。
![fess2_qiita (1).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/73a5ea11-011f-1420-f5c5-e9f34d225d13.png)


# 手順
概要図のサービスの矢印の順に作成していくイメージです。
1. CloudWatchでの死活監視の実装
2. slackの設定
3. lambda用のKMS作成
4. KMS用のIAMポリシーを作成
5. lambdaからSNSへの通知設定の実装

### CloudWatchでの死活監視の実装
CloudWatchにて「アラームの作成」を選択し、メトリクスとして作成したELBの「HealthyHostCount」を選択します。
HealthyHostCountは「正常と見なされるターゲットの数」をカウントしており、私の環境ではターゲットが１台なので、閾値として「0以下」の時を指定して検知させます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/b8b6b37c-11f2-710f-ff82-89a140d0c1b0.png)
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/003e31ad-7ecf-172c-f302-030feefe3057.png" width=70%>


メトリクスを選択し、監視のパラメータを設定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/2659b3fc-7bbf-e7f3-065f-efa90af8d406.png)

アクションの設定として「新しいSNSトピック」を指定します。
※画像では既存のSNSトピックを選択し、エンドポイントとしてEメールも指定していますが、この画面から新しくSNSトピックを作成することが可能です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/1c7b98bf-7338-54f6-ee05-3927ed16f659.png)


### slackの設定
参考にしたのは以下のサイトです。
https://dev.classmethod.jp/cloud/sns-messaging-slack/

以下のSlack APIのYour Apps画面から通知用のアプリを作成します。
https://api.slack.com/apps
アプリ名と通知させたいworkspaceを選択して下さい。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/65333f69-4e53-fbb1-d1e2-faa088851a8c.png" width=50%>

slack側から許可を求められますので、確認して許可してください。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/a2d1ed85-4216-14bd-b34a-07d7e20a0a22.png" width=50%>

アプリが作成されると、Basic Informationページに遷移します。今回のアプリではLambdaからslack宛にメッセージを送信したいので、Incoming Webhooksを選択してください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/da9f218d-db14-c5c4-d160-082ad6107cba.png)

Incoming Webhooksページにて、Activate Incoming WebhooksのスイッチをOnにしてAdd New Webhook to Workspaceをクリックし、チャンネル名を選択し、許可するをクリックします。
許可が完了すると以下の画面のようにslackの指定したチャンネルに対してpostでメッセージを投稿することが出来るようになります。  
Webhook URLは後でlambdaの環境変数に指定するのでコピーしておいてください。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/8164f742-313e-ced8-fe75-f54f9a456fa7.png)
サンプル通りcurlを実行すると、対象のチャンネルに「Hello,World!」が投稿出来ることが確認できます。
<img src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/323a9ef6-2a04-2ca7-1c29-46c061375c21.png" width=50%>
lambdaの関数内でslackのURLを指定する際にKMSでURLを暗号/復号化する必要があるので、KMSで暗号鍵を作成します。

### lambda用のKMS作成
AWSコンソールからKMSを選択し、カスタマー管理型のキーとしてキーの作成を選択します。キーのタイプは対照を選びます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/6ad8c51b-cf0c-71f9-0151-34d7b8dd4cae.png)

IAMロール作成時に指定するので、KMSのARNをコピーしておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/4a021543-551f-f8bf-3e52-d041be5ec4cd.png)

### lambda用のIAMポリシーを作成
AWSコンソールからIAMポリシーを選択し、KMS用のIAMであることが分かるポリシー名をつけ、JSONタブにて以下の通りKMSのARNを指定して貼り付け、IAMポリシーを作成します。

```
{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "1",
            "Effect": "Allow",
            "Action": [
                "kms:Decrypt"
            ],
            "Resource": [
                "KMSのARN"
            ]
        }
    ]
}
```

作成後、以下の３つのポリシーをまとめてアタッチしてIAMロールを作成します。

- CloudWatchReadOnlyAccess → 　　　Cloudwatch参照用
- AWSLambdaBasicExecutionRole → 　　lambda実行用
- 自作のKMSポリシー → 　　　　KMSキーの暗号/復号化用
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/6ad9f834-10ff-3a5a-f9e1-75b05be7e604.png)

先ほど作成したKMSのキー管理者/キーユーザーとして、IAMロールを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/e4cf1eba-bea9-c6a4-4fd1-8ae20d60e76a.png)

### lambdaからSNSへの通知設定の実装
AWSコンソールからlambdaを選択し、既存の設計図「cloudwatch-alarm-to-slack-python」を検索して使用します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/1342e812-f8a9-878f-a6fa-e131f5d5570d.png)

関数名を指定し、実行ロールとして作成したロールを指定し、SNSトリガーとしてCloudWatchで指定したSNSトピックを指定します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/89a464e7-362d-570d-de51-c4e7ff2f2bf3.png)

lambdaの環境変数だけ指定すれば、Pythonの関数を修正しなくてもslackへの投稿が可能になります。

|key|Value|
|:--|:--|
|Slack channel|通知したいチャンネル名|
|kmsEncrptedHookUrl|slackのwebhookURL|

入力後にkmsEncrptedHookUrlの横の「Encrypt」をクリックするとURLがKMSキーで暗号化されます。関数内でこのURLを複合化し、slackに投稿を行います。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/e1a1ae5c-41d5-b787-6f72-984cec69f64a.png)

# 結果
ELBがダウンした際には、slackの指定したチャンネルにアラートが飛ぶようになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/252317/f5c0766e-97f6-c803-58fb-c2b4411378f5.png)