EventBridgeからSlackにメッセージを送る

# やリたいこと

EventBridgeから👇のフォーマットでSlackに送ると

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

こんな感じ👇のメッセージが投稿できる
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/b5a957e9-3023-67c5-5ff6-caf9b0ab110f.png)

# 調べてみた

EventBridgeからSlackにメッセージを送るサンプル（公式）は👇にある

https://docs.aws.amazon.com/ja_jp/AWSCloudFormation/latest/UserGuide/aws-resource-events-apidestination.html#aws-resource-events-apidestination--examples

がしかし、うまく動かなかったので、理解しながら作り替えてみた。

とりあえず”動くこと”を確認したいので、トリガーとして１分に一回起動するようにした。

# 事前準備

+ SlackにHUBOTを入れる
+ HUBOTをチャンネルに参加させる
+ HUBOTからAPIトークンを取得する

※　AWS Secrets Managerも使うことになります

# 概要

+ １、EventBridge用のIAMロールを作る
+ ２、"接続"(APIの送信先)を作る
+ ３、APIの送信先を作る
+ ４、イベントルールを作る


<details>
<summary> ←（ここをクリックすると展開）　CFnテンプレ全体はこちら</summary>

``` yaml
AWSTemplateFormatVersion: 2010-09-09
Description: "EventBridge to Slack"
Parameters:
  HubotAPIToken:
    Type: String
    NoEcho: true
    Description: APIToken from Slack HUBOT. ex.. xoxb-399999-9999999-hogefugahoge
Resources:
  SlackRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: '/service-role/'
      Policies:
        - PolicyName: eventbridge-api-destinations
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - events:InvokeApiDestination
                Resource: !GetAtt SlackDestination.Arn
  SlackConnection:
    Type: AWS::Events::Connection
    Properties:
      AuthorizationType: API_KEY
      AuthParameters:
        ApiKeyAuthParameters:
          ApiKeyName: Authorization
          ApiKeyValue: !Sub "Bearer ${HubotAPIToken}"
  SlackDestination:
    Type: AWS::Events::ApiDestination
    Properties:
      ConnectionArn: !GetAtt SlackConnection.Arn
      HttpMethod: POST
      InvocationEndpoint: https://slack.com/api/chat.postMessage
      InvocationRateLimitPerSecond: 10
  SlackRule:
    Type: AWS::Events::Rule
    Properties:
      State: DISABLED
      ScheduleExpression: "rate(1 minute)"
      Targets:
        - Id: slack-destination
          Arn: !GetAtt SlackDestination.Arn
          RoleArn: !GetAtt SlackRole.Arn
          InputTransformer:
            InputPathsMap:
              "channel": "$.detail"
            InputTemplate: |
              {
                "channel": "#test",
                "username": "hogehoge",
                "icon_emoji": ":tea:",
                "text":"ホゲホゲText"
              }
```

</details>

# 詳細

HUBOTからAPIトークンを取得する

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/08cd9d46-7004-8b0f-9bc9-4c4ba01511e0.png)

## １、EventBridge用のIAMロールを作る

EventBridgeに対して、"events:InvokeApiDestination"の実行権限を渡す
（参考サイトのママ）

``` yaml
  SlackRole:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: '2012-10-17'
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action:
              - sts:AssumeRole
      Path: '/service-role/'
      Policies:
        - PolicyName: eventbridge-api-destinations
          PolicyDocument:
            Version: '2012-10-17'
            Statement:
              - Effect: Allow
                Action:
                  - events:InvokeApiDestination
                Resource: !GetAtt SlackDestination.Arn
```


## ２、"接続"(APIの送信先)を作る

パラメータで設定したHUBOT　APIトークン文字列の前に "Bearer"をつけたものが、AWS Secrets Managerに登録されます。

※　APIキーは安全に取り扱いください。。
（公式サンプルでは、何から小難しいことをしているので）

``` yaml
  SlackConnection:
    Type: AWS::Events::Connection
    Properties:
      AuthorizationType: API_KEY
      AuthParameters:
        ApiKeyAuthParameters:
          ApiKeyName: Authorization
          ApiKeyValue: !Sub "Bearer ${HubotAPIToken}"
```


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/1b4f1adb-bb4c-fefc-ce5f-8934ceecbcf5.png)



## ３、APIの送信先を作る

上記の”接続”を使って、HUBOT指定のURLにPOSTするように設定

``` yaml
  SlackDestination:
    Type: AWS::Events::ApiDestination
    Properties:
      ConnectionArn: !GetAtt SlackConnection.Arn
      HttpMethod: POST
      InvocationEndpoint: https://slack.com/api/chat.postMessage
      InvocationRateLimitPerSecond: 10
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/9609c3d1-a54f-673b-ae29-d96574abb0b6.png)


## ４、イベントルールを作る

このサンプルでは、とりあえずSlackにメッセージ投稿できれば良いので、
１分に一回起動するようにした
あと、初期状態ではルールを無効化しているので、管理コンソールから有効化する


``` yaml
  SlackRule:
    Type: AWS::Events::Rule
    Properties:
      State: DISABLED
      ScheduleExpression: "rate(1 minute)"
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/8ca5e6b9-9857-0aa0-5e4d-169d221810ef.png)



Slackに送信する部分。
入力パラメータをよしなに変換して、”APIの送信先”に送る
（このサンプルではスケジュール起動なので、入力パラメータは無い）


``` yaml
      Targets:
        - Id: slack-destination
          Arn: !GetAtt SlackDestination.Arn
          RoleArn: !GetAtt SlackRole.Arn
          InputTransformer:
            InputPathsMap:
              "channel": "$.detail"
            InputTemplate: |
              {
                "channel": "#test",
                "username": "hogehoge",
                "icon_emoji": ":tea:",
                "text":"ホゲホゲText"
              }

```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/15635711-f3e1-5d3d-5e75-c6078115e78d.png)


**InputTemplate:** の部分を👇のフォーマットで送るって感じで。

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

このサンプルでは、スケジュールトリガーとしていますが、
トリガーと変換ルールを組み合わせれば、いい感じに仕上がるんじゃないかと


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/b5a957e9-3023-67c5-5ff6-caf9b0ab110f.png)



## モニタリング

←呼び出しされた回数 　 実行した回数→

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/185989/8010f17b-a546-e39c-cb16-9db785179219.png)

うまくいかない場合、このグラフでなんとなくわかること
・そもそも呼び出されていない
・呼び出されたけど実行されていない
・呼び出されて実行した（実行した先でエラーになってる）