CloudWatch AlarmをSlackに通知する


# まえがき

https://qiita.com/afukuma/items/865623e768e5a4db4d7d

👆このやり方でノンコーディングでSlackにメッセージ投稿できることがわかった
とりあえず”動けばよかった”ので、１分に一回起動するようにしていた。

EventBridgeでは、AWSリソースの状態変更を取得してイベント発生できるので、いろんなことができそうです。
ここでは、
**CloudWatch Alarmの状態変更があったらSlackに通知する**
をします

# 概要

１、イベントを捕捉する：EventPattern
２、イベントメッセージの項目を拾う：InputPathsMap
３、メッセージを出力する：InputTemplate


<details><summary><b>----------------------------------------<br>&nbsp;&nbsp;&nbsp;全体を表示（折りたたみ）<br>&nbsp;------------------------------------------</b></summary><div>

``` yaml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  AlertNamePrefix:
    Type: String
  SlackChannelName:
    Type: String
  SlackDestinationArn:
    Type: String
  EventBridgeRoleArn:
    Type: String
Resources:
  SlackAlarmALARMRule:
    Type: AWS::Events::Rule
    Properties:
      State: ENABLED
      EventPattern: !Sub
        - |
          {
            "source": ["aws.cloudwatch"],
            "detail-type": ["CloudWatch Alarm State Change"],
            "detail": {
              "alarmName": [{"prefix": "${AlarmName}"}],
              "state": {
                "value": ["ALARM"]
              }
            }
          }
        - {AlarmName: !Ref AlertNamePrefix}
      Targets:
        - Id: slack-destination
          Arn: !Ref SlackDestinationArn
          RoleArn: !Ref EventBridgeRoleArn
          InputTransformer:
            InputPathsMap: 
                "AlarmName": "$.detail.alarmName"
                "PrevState": "$.detail.previousState.value"
                "State": "$.detail.state.value"
                "Reason": "$.detail.state.reason"
            InputTemplate: !Sub
              - |
                {
                  "channel": "${ChannelName}",
                  "username": "監視bot",
                  "icon_emoji": ":tea:",
                  "text":"異常ですよ <AlarmName>  <PrevState> -> <State>",
                  "attachments": [{
                    "text": "<Reason>",
                    "color": "danger",
                    "footer": "EventBridge"
                  }]
                }
              - {ChannelName: !Ref SlackChannelName} 
```


</div></details>


## 起動パラメータ

|  |  |
|:--|:--|
| AlertNamePrefix  | 捕捉するCloudWatch Alarm名称（先頭一致）  |
| SlackChannelName | Slackチャンネル名  |
| SlackDestinationArn | API送信先のARN [前記事参照](https://qiita.com/afukuma/items/865623e768e5a4db4d7d)  |
| EventBridgeRoleArn  | EventBridge用IAMロール [前記事参照](https://qiita.com/afukuma/items/865623e768e5a4db4d7d) |

``` yaml
AWSTemplateFormatVersion: "2010-09-09"
Parameters:
  AlertNamePrefix:
    Type: String
  SlackChannelName:
    Type: String
  SlackDestinationArn:
    Type: String
  EventBridgeRoleArn:
    Type: String

```


``` yaml
Resources:
  SlackAlarmALARMRule:
    Type: AWS::Events::Rule
    Properties:
      State: ENABLED
```

## １、イベントを捕捉する：EventPattern

```yaml
      EventPattern: !Sub
        - |
          {
            "source": ["aws.cloudwatch"],
            "detail-type": ["CloudWatch Alarm State Change"],
            "detail": {
              "alarmName": [{"prefix": "${AlarmName}"}],
              "state": {
                "value": ["ALARM"]
              }
            }
          }
        - {AlarmName: !Ref AlertNamePrefix}
```

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-event-patterns.html

複雑な抽出はできないので命名規則とかよく考える必要がありそうですな

## ２、イベントメッセージの項目を拾う：InputPathsMap

```yaml
      Targets:
        - Id: slack-destination
          Arn: !Ref SlackDestinationArn
          RoleArn: !Ref EventBridgeRoleArn
          InputTransformer:
            InputPathsMap: 
                "AlarmName": "$.detail.alarmName"
                "PrevState": "$.detail.previousState.value"
                "State": "$.detail.state.value"
                "Reason": "$.detail.state.reason"
```

https://docs.aws.amazon.com/ja_jp/eventbridge/latest/userguide/eb-transform-target-input.html

一旦変数に入れる感じですな

## ３、メッセージを出力する：InputTemplate

```yaml
            InputTemplate: !Sub
              - |
                {
                  "channel": "${ChannelName}",
                  "username": "監視bot",
                  "icon_emoji": ":tea:",
                  "text":"異常ですよ <AlarmName>  <PrevState> -> <State>",
                  "attachments": [{
                    "text": "<Reason>",
                    "color": "danger",
                    "footer": "EventBridge"
                  }]
                }
              - {ChannelName: !Ref SlackChannelName} 
```

出力方法。。Slackの👇この形にあわせてやれば良いのです

https://api.slack.com/methods/chat.postMessage

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-properties-events-rule-inputtransformer.html

# あとがき

イベントの対象抽出方法や、変換でできることが限られている（条件式とか使えない）ので、パターン別のルールを作るとか考える必要がありそうですな

今までイベント発生をSNS経由でLambdaでSlack通知するように書いていたので、これは楽ちん