[Organizations]マルチアカウントのイベントを集約してChatbotもLambdaも使わずにEventBridgeの入力トランスフォーマーでSlackに通知する

マルチアカウント・マルチリージョンの通知もEventBridgeを駆使すればすばやく構築可能。しかもSlackへの通知もできる。EventBridge始まったな。
2021.10.31

こんにちは!オンジーこと恩塚(@onzuka_muscle)です。

AWS Organizationsを使っている環境でマルチアカウント・マルチリージョンのイベントを集約してChatbotを使わずにEventBridgeの入力トランスフォーマーでSlackに通知する方法を紹介します。

既に弊社ブログで色々紹介されている機能の合わせ技になるので参考リンク多めになります m(_ _)m

なお本ブログは「Chatbotに対応していない」 or 「一応通知はできるけどメッセージ内容が物足りない」イベントをSlackに送りたいという状況を想定してます。

Chatbotに対応しているイベント(GuardDutyやSecurity Hub、その他)の場合はEventBridgeの入力トランスフォーマー使わずにChatbot使ってSlack通知した方がラクだと思います!

今回は例としてCloudTrail insightsのイベントを取り上げます。

構成はこんな感じです。

以後、分かりやすくするために「集約アカウント」(図の右上)と「集約対象(のアカウント)」と呼びます。

イベントを集約するのは「集約アカウントの特定リージョンのイベントバスただ一つ」で良いです。

リージョン間に転送が可能になったためこのような構成でいけます。(神アプデ

また一つのイベントバスに集約しているため、Slackに送信するための入力トランスフォーマーの設定も一箇所で済みます。

前置きが長くなりましたがやっていきます。

やってみた

集約アカウント

こちらのブログを参考にして以下のリソースを作っています。

  • Slackアプリケーション
  • API送信先
    • イベントルールのターゲットになります。
  • イベントルール

作成中の画面等はこちらのブログで確認いただく想定で本ブログでは割愛してます。><

Slackアプリケーション

手順はざっくりこんな感じです。

  • ブラウザよりSlackのアプリ作成画面にいく
  • 「Create an app」を選択
  • 「From scratch」を選択
  • 「App Name」を決める
  • 「Pick a workspace to develop your app in」で対象のSlackワークスペースを選択
  • サイドバー「OAuth & Permissions」を選択
  • 作成したアプリの「Bot Token Scopes」の「Add an OAuth Scope」より「chat:write」を設定
  • 「Install to Workspace」
  • 「Bot User OAuth Token」を控える ※後で使う
  • 通知先のSlackチャンネルで設定画面を開き「インテグレーション」→「アプリを追加」→対象アプリを検索→追加

ワークスペースにインストール作成しただけではダメで対象のチャンネルへのアプリケーション追加が必要なことに注意してください。

API送信先

こちら作成後の画面です。EventBridgeのメニュー画面から辿り着けます。

APIキーの設定をする際に下記のように設定することにご注意ください。

Bearer <Slackアプリ作成時に確認したボットユーザーのOAuthトークン>

イベントバス

次は集約対象から飛んできたイベントを受け取るためのイベントバスを作成します。

ここで設定するリソースベースポリシーが大事です。

aws:PrincipalOrgIDでOrganization IDを指定して許可しているところがポイントです。

これによって対象のOrganizationsに所属しているアカウントであれば個別にアカウントを指定して許可しなくてもこのイベントバスにイベントを送信できるようになります。

つまりアカウントが増えていってもこのポリシーは書き換える必要がないってことです!

{
  "Version": "2012-10-17",
  "Statement": [{
    "Sid": "OrganizationsAllowStatement-dev",
    "Effect": "Allow",
    "Principal": {
      "AWS": "*"
    },
    "Action": "events:PutEvents",
    "Resource": "arn:aws:events:us-east-1:XXXXXXXXXXXXXX:event-bus/onzuka-test-eventbus",
    "Condition": {
      "StringEquals": {
        "aws:PrincipalOrgID": "o-xxxxxxxxxx"
      }
    }
  }]
}

権限周りがこれでオールOKかと言うとそうではなくて、集約アカウント・集約対象アカウントそれぞれのイベントルールに適切な権限を付与したIAMロールが必要です。こちらは後述します。

なおaws:PrincipalOrgIDはサービスプリンシパルの場合は使えないので注意してください。

本ブログのようにEventBridgeでイベントを受け付ける場合であればプリンシパルはアカウントになるので問題なく使えます。

イベントルール

先ほどのイベントバスに属するイベントルールを新規作成します。

通知するイベントなんでも良いのですが今回はCloudTrail insightsを通知してみます。

Chatbotで通知するとこんな感じです。(2021/10/31時点)

ちょっと情報量としては物足りないですよね。

イベントルールの作成画面です。

イベントパターンは下記の通りです。

{
  "source": ["aws.cloudtrail"],
  "detail-type": ["AWS Insight via CloudTrail"]
}

ターゲットには先ほど作成したAPI送信先を選択します。

入力トランスフォーマーを設定します(重要)

API送信先を呼び出すための権限を持ったロールは新規作成しました。

スクショでは見にくいですが入力トランスフォーマーには下記のように記載しています。

絵文字(:rotating_light:)や改行(\n)、太字(**)で見やすくしています。

{
  "account": "$.account",
  "awsRegion": "$.detail.awsRegion",
  "eventID": "$.detail.eventID",
  "eventName": "$.detail.insightDetails.eventName",
  "eventTime": "$.detail.eventTime",
  "id": "$.id",
  "insightType": "$.detail.insightDetails.insightType",
  "time": "$.time"
}
{
  "channel": "XXXXXXXXXXX",
  "text": " :rotating_light: *AWS Insight via CloudTrail* \n *id*: <id>\n *account*: <account>\n *time*: <time>\n *eventTime*: <eventTime>\n *awsRegion*: <awsRegion>\n *eventID*: <eventID>\n *eventName*: <eventName>\n *insightType*: <insightType>\n *URL*: https://console.aws.amazon.com/cloudtrail/home?region=<awsRegion>#/insights/<eventID>"
}

イベントのJSONを入力トランスフォーマーで変換する書き方はこちらのスライドが参考になります。

またIAMロールにアタッチされるポリシーは以下になります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": [
        "events:InvokeApiDestination"
      ],
      "Resource": [
        "arn:aws:events:us-east-1:XXXXXXXXXXX:api-destination/onzuka-test-slack-apidestinations/*"
      ]
    }
  ]
}

集約対象アカウント

集約アカウントの準備が整ったので集約対象アカウントにイベントルールを配っていきます!

ここではトランスフォーマーの記載がいらないです。

「入力トランスフォーマーを設定したイベントルールが紐づいている集約アカウントのイベントバス」めがけてイベントをそのまま投げましょう。

IAM ロール

その前にイベントルールに適切な権限が必要なので注意です。

IAMロールを事前に作成しておきましょう。

ポリシーは以下になります。

{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": [
        "events:PutEvents"
      ],
      "Resource": "arn:aws:events:us-east-1:XXXXXXXXXXXX:event-bus/onzuka-test-eventbus",
      "Effect": "Allow"
    }
  ]
}

集約アカウントのイベントバスを指定しています。

イベントルール

イベントパターンは同じですね。

イベントバスはデフォルトにしてます。

ターゲットは「別のアカウントまたはリージョンのイベントバス」を選択します。

その上で先ほど作った集約アカウントのイベントバスにイベントを送信する権限を持ったIAMロールを選択します。

これで作成して完了と言いたいところですが、マルチアカウント・マルチリージョンにイベントルールをマネジメントコンソールで作成していくのは流石に無理があります。

CloudFormations StackSetsを活用して一気に展開しましょう。

展開の仕方はこちらのブログをご参考ください。

また複数リージョンを並列に展開できるようになったので、マルチリージョンに展開する際は必ずこれを使いましょう。

スピードが全然違います!

StackSetsの作成画面はこんな感じです。

ということでマルチアカウント・マルチリージョンを集約対象としたChatbotもLambdaも使わないEventBridgeの入力トランスフォーマーでSlackへのイベント通知ができました。

だいぶ見やすくなりましたね!

Before(Chatbot)

After

おわり

長くなりましたが

  • マルチアカウント・マルチリージョンにイベントを集約して通知したい
  • StackSetsを使ってマルチアカウント・マルチリージョンにイベントルールなどのリソースを展開したい
  • Chatbot対応していないイベントを通知したいけどそのためだけにLambdaを書きたくない

といった人に部分的にでも参考になれば幸いです。

参考

今回、利用した機能含めてEventBridgeの全体を解説しているスライドと動画です!