エンジニア

2023.03.01

AWS Chatbotを使ってSlackに通知をさせてみた結果(CloudFormation編)

AWS Chatbotを使ってSlackに通知をさせてみた結果(CloudFormation編)

こんにちは、あるがです。

今回は、過去に書いた「AWS Chatbotを使ってSlackに通知をさせてみた結果(導入〜テスト編)」記事の続編となります。
よろしくお願いいたします。


serverless.yml の記述


以前はコンソール上で行っていた ChatBot 作成ですが、いちいち、手で作るのは非常に面倒ですし、
忘れた頃に、消さなければいけなくなったとき、どれをどのようにどこで作ったのか
資料があればよいですが、なければ、消すのにもそうとうな時間を要します。
また昨今では、こういった処理もコードで管理するのが主流となってますよね。

ある種、作成手順書にもなる yml ファイルですが、
その作成したファイル「aws-health-check-chatbot.yml」の中身がこちらになります。

AWSTemplateFormatVersion: "2010-09-09"
Description: aws-health-check-chatbot

Parameters:
  SlackWorkspaceId:
    Type: String
    Default: ""
  SlackChannelId:
    Type: String
    Default: ""

Resources:
  # IAM role
  HealthCheckIAMloreChatbot:
    Type: AWS::IAM::Role
    Properties:
      AssumeRolePolicyDocument:
        Version: "2012-10-17"
        Statement:
          - Effect: Allow
            Principal:
              Service:
                - chatbot.amazonaws.com
            Action:
              - "sts:AssumeRole"
      Policies:
        - PolicyName: policies
          PolicyDocument:
            Version: "2012-10-17"
            Statement:
              - Effect: "Allow"
                Action:
                  - cloudwatch:Describe*
                  - cloudwatch:Get*
                  - cloudwatch:List*
                Resource: "*"

  # AWS Chatbot
  HealthCheckChatbotConfiguration:
    Type: AWS::Chatbot::SlackChannelConfiguration
    Properties:
      ConfigurationName: HealthCheckChatbotConfiguration
      GuardrailPolicies:
        - arn:aws:iam::aws:policy/AdministratorAccess
      IamRoleArn: !GetAtt HealthCheckIAMloreChatbot.Arn
      SlackChannelId: !Ref SlackChannelId
      SlackWorkspaceId: !Ref SlackWorkspaceId
      SnsTopicArns:
        - !Ref HealthCheckSNSTopic

  # EventBridge
  HealthCheckEventBridgeRule:
    Type: AWS::Events::Rule
    Properties:
      Name: HealthCheckEventBridgeRule
      EventPattern:
        source:
          - aws.health
        detail-type:
          - AWS Health Event
      Targets:
        - Arn: !Ref HealthCheckSNSTopic
          Id: sns-topic

  # SNS topic
  HealthCheckSNSTopic:
    Type: AWS::SNS::Topic
    Properties:
      TopicName: HealthCheckSNSTopic

  HealthCheckTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Statement:
          - Sid: AllowServices
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action: "sns:Publish"
            Resource:
              - !Ref HealthCheckSNSTopic
      Topics:
        - !Ref HealthCheckSNSTopic


ハマったところ


まずはこちらのブログ「AWSCloudformationでEventBridgeからSNSを設定したが通知がこないそこのあなたへ【コードあり】」をご覧ください。
ここにハマったところの詳細が書かれております。

SNSトピックからメッセージの発行ボタンで、Slackに通知するところまでは行ったのですが、
実際にEC2のアクションを、EventBridgeを通じて、SNSが通知をしてくれるところが
うまく機能しませんでした。

つまり、コンソールで作っていたときは自動で設定してくれていた
下記の処理を、AWS CloudFormation 用にあらためて書かなければなりませんでして、
それに気づくまでは Slack 通知がうまくできませんでした。

  HealthCheckTopicPolicy:
    Type: AWS::SNS::TopicPolicy
    Properties:
      PolicyDocument:
        Statement:
          - Sid: AllowServices
            Effect: Allow
            Principal:
              Service:
                - events.amazonaws.com
            Action: "sns:Publish"
            Resource:
              - !Ref HealthCheckSNSTopic
      Topics:
        - !Ref HealthCheckSNSTopic

調べてみるとAWS公式にも、Q&Aがありましたのでご紹介しておきます。

AWS Chatbot が Amazon SNS からメッセージを受信しないのはなぜですか?

Amazon SNS トピックのアクセスポリシーが、別の AWS のサービスがトピックにメッセージを発行するために必要な許可を付与していることを確認する

1.Amazon SNS コンソールを開きます。

2.左側のナビゲーションペインで、[Topics] (トピック) を選択します。

3.AWS Chatbot がサブスクライブしたトピックを選択します。その後、[Edit] (編集) を選択します。

4.[Access policy] (アクセスポリシー) タブを選択します。その後、アクセスポリシーの [Statement] (ステートメント) セクションを確認します。適切な AWS のサービスが SNS:Publish API アクションを実行することをポリシーが許可していることを確認します。

5.適切なサービスがトピックにイベントを発行することを Amazon SNS アクセスポリシーが許可していない場合は、次の手順を実行してポリシーを更新します。
トピックページの [Details] (詳細) セクションで、[Edit] (編集) を選択します。
[アクセスポリシー] セクションを展開し、必要な許可を追加します。

また、インベント通知用の Slack チャンネルを作っておくことをおすすめいたします。


デプロイ方法


deployコマンドはこちらになります。
Slack のチャネルIDをデプロイ時に指定することで、yml にベタ書きする必要がなく
セキュリティ面強化が図れます。

※ 我社では、AWSアカウントが複数ありまして、その中に、本番用・開発用が存在しており、
 万が一、デプロイで本番用に行かないように、aws s3 ls などのコマンドで
 自分がデプロイする先(つまり、コピーしたAWSのCredentialsは
 どこから持ってきたのか、s3のファイル一覧を見て、devという名称のファイルがあれば
 開発用だなということ)を事前に確認しておきましょう。

皆さんのAWS環境は、本番用と開発用にわかれていますでしょうか?

aws cloudformation deploy --template ./aws-health-check-chatbot.yml --stack-name health-check-chatbot --capabilities CAPABILITY_NAMED_IAM --parameter-overrides SlackChannelId='xxxxxxxxxx' SlackWorkspaceId='xxxxxxx'

※ チャンネルIDとworkspaceidは過去に書いた「AWS Chatbotを使ってSlackに通知をさせてみた結果(導入〜テスト編)」記事を参考にして調べてください
※ すでにchatbotに登録されているslackチャンネルは指定できないのでご注意ください


削除コマンド


もし、間違ってデプロイしてしまったり、やり直したい場合は、
まずはこちらのコマンドで消してください。

aws cloudformation delete-stack --stack-name health-check-chatbot

一覧に戻る