新しくなった「AWS Health Dashboard」からのSlack通知をCDKで作成する

2022.08.19

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

こんにちは。CX事業本部Delivery部MADグループのきんじょーです。

先日、CloudFormationのデプロイがAPIのタイムアウトエラーでこけるということがあり、よく見るとAWS Health Dashboardに通知が来ていました。

ダッシュボードを見るまで気づけなかったので、Slack通知を仕込もうと思ったところ、CloudFormationで複数リージョンのHealth DashboardをSlackに通知する記事が出ていました。

CloudFormationでデプロイしても良かったのですが、せっかくなのでこの記事ではCDKで実装しました。 CDKはネイティブでStackSetsには対応していないので、今回は1リージョンへの展開を想定しています。

複数リージョンへ展開する場合、元記事の単位でSNSとEventBridgeのみのStackを作成してcdk synthしたテンプレートを、CfnStackSetsで各リージョンへデプロイすれば可能ですが、本記事では取り扱いません。

AWS Health Dashboardとは

2月末にリリースされた比較的新しいサービスです。
リリース前までは、リージョン規模の障害情報はService Health Dashboardアカウント規模の障害やイベント情報はPersonal Health Dashboardを参照する必要がありました。AWS Health Dashboardでは、その二つをこのサービス一つで確認できます。

詳細は以下のブログをご確認ください。

やってみた

AWS Chatbotにクライアントの設定

AWS Chatbotクライアントの設定は、GUIからのみ行えるため、AWS Chatbotのサービス画面を開いて行います。 この作業については、他にも画像付きで参考になる記事が多くあるので割愛します。

パラメーターストアにSlackのワークスペースとチャンネルIDを登録

CDKのコードに通知先のSlackのIDを残したくなかったのでパラメーターストアを使用しますl。 Slack側で確認したIDを事前に登録してください。

ssm-parameters

CDKの実装

全体のコードはこちらにも格納してあります。

CDKプロジェクトの作成

$ mkdir cdk-health-dashboard-notification && cd ./cdk-health-dashboard-notification

# CDKのプロジェクトをTypeScriptで作成
$ npx cdk init app --language typescript

リソースの定義

これまで、Service Health Dashboardのリージョン規模の障害情報の通知を作るには少し手間がかかりましたが、AWS Health DashboardはEventBridge連携できるのでシンプルです。

EventBridgeでaws:healthのイベントを全て拾ってSNSトピックへ通知し、トピックをサブスクライブしているAWS ChatbotからSlackへ連携します。

lib/cdk-health-dashboard-notification

import { Stack, StackProps } from "aws-cdk-lib";
import * as sns from "aws-cdk-lib/aws-sns";
import { Construct } from "constructs";
import * as events from "aws-cdk-lib/aws-events";
import * as targets from "aws-cdk-lib/aws-events-targets";
import { SlackChannelConfiguration } from "aws-cdk-lib/aws-chatbot";
import * as ssm from "aws-cdk-lib/aws-ssm";
import * as iam from "aws-cdk-lib/aws-iam";

export class CdkHealthDashboardNotificationStack extends Stack {
  constructor(scope: Construct, id: string, props?: StackProps) {
    super(scope, id, props);

    // SNSトピックの作成
    const topic = new sns.Topic(this, "CdkHealthDashboardNotificationTopic");

    // イベントルールの作成
    new events.Rule(this, "CdkHealthDashboardNotificationRule", {
      eventPattern: {
        source: ["aws.health"],
      },
      targets: [new targets.SnsTopic(topic)],
    });

    // Slack通知の作成
    const role = new iam.Role(this, "AWSChatBot", {
      assumedBy: new iam.ServicePrincipal("chatbot.amazonaws.com"),
    });
    role.addManagedPolicy(
      iam.ManagedPolicy.fromAwsManagedPolicyName("CloudWatchReadOnlyAccess")
    );
    new SlackChannelConfiguration(this, "SlackChannel", {
      slackChannelConfigurationName: "SlackChannelForAlert",
      // 通知先のSlackのIDは先ほどパラメーターストアに登録した値を使用します
      slackWorkspaceId: ssm.StringParameter.valueForStringParameter(
        this,
        `/SlackWorkSpaceId`
      ),
      slackChannelId: ssm.StringParameter.valueForStringParameter(
        this,
        `/SlackChannelId`
      ),
      notificationTopics: [topic],
      role,
    });
  }
}

デプロイ

$ npx cdk deploy

無事デプロイが完了したら動作確認をしていきます。

動作確認

テストメッセージの送信

SNSトピックにテストのメッセージを登録します。 登録する内容はEventBridgeサービスで確認できる、以下のテストイベントです。

{
  "version": "0",
  "id": "7bf73129-1428-4cd3-a780-95db273d1602",
  "detail-type": "AWS Health Event",
  "source": "aws.health",
  "account": "123456789012",
  "time": "2016-06-05T06:27:57Z",
  "region": "ap-southeast-2",
  "resources": [],
  "detail": {
    "eventArn": "arn:aws:health:ap-southeast-2::event/AWS_ELASTICLOADBALANCING_API_ISSUE_90353408594353980",
    "service": "ELASTICLOADBALANCING",
    "eventTypeCode": "AWS_ELASTICLOADBALANCING_API_ISSUE",
    "eventTypeCategory": "issue",
    "startTime": "Sat, 04 Jun 2016 05:01:10 GMT",
    "endTime": "Sat, 04 Jun 2016 05:30:57 GMT",
    "eventDescription": [{
      "language": "en_US",
      "latestDescription": "A description of the event will be provided here"
    }]
  }
}

sns-test-message

この時送信するメッセージは、EventBridgeのイベントパターンでないと、AWS Chatbotに通知が飛ばないので注意が必要です。

Slack通知を確認

通知が来ました?

slack-notification

終わりに

EventBridge連携のお陰でとても簡単でした。
あとは本番の通知が来るのを待ちたいと思います。