Sumo LogicのアラートをSlackと連携させてみた

オペレーション部 江口です。

この前投稿したSumo Logicで社内の基幹AWS環境の情報を可視化してみた(CloudTrail編)の続き的な記事です。

前掲の記事ではSumo LogicのダッシュボードでCloud Trailの情報を可視化しましたが、可視化できるようになると次にやりたくなるのはアラートの設定です。 ついでにいうとアラートはSlackに投げるのが便利だよね〜ということで、実際やってみました。

幸いSumo Logicは標準でSlackの連携機能があります!

ただ、そうはいっても手順は割と多いので、この記事で簡単に紹介してみたいと思います。

作業の流れ

作業の大まかな流れは以下のような感じです。

【Slack側設定】

  1. 連携用のSlack Appを作る
  2. 作成したSlack AppでIncoming Webhooksを有効にする

【Sumo側設定】

  1. Slack用のConnectionを作成する
  2. アラート用のサーチ文を作成する
  3. 作成したサーチを保存してスケジュールを設定する

では実際に見てみましょう。

Slack側の設定

Sumo Logicの標準のSlack連携機能では、SlackのIncoming Webhooksを利用してメッセージを送信します。Incoming Webhooksを利用するにはSlack Appが必要なため、まずはこれを作成します。

連携用のSlack Appを作る

  • https://api.slack.com/apps へアクセスし、 [Create New App]をクリックします。
  • [App Name]にアプリケーション名、[Development Slack Workspace]に利用するSlackワークスペースを入力して[Create App]をクリックします。

作成したSlack AppでIncoming Webhooksを有効にする

上記手順でAppを作成すると、Appの設定画面に遷移します。 この時点ではまだIncoming Webhooksは有効になっていないため、下記の手順で設定を行なって有効にします。

  • [Add features and functionality]内の項目 [Incoming Webhooks]をクリックします。
  • Incoming WebhooksをOFFからONに変更し、有効化します。
  • [Add New Webhook to Workspace]をクリックします。
  • チャンネルの選択画面が表示されるので、アラート通知を投稿するチャンネルを選択します。
  • Webhook URLを生成されます。

これで、このWebhook URLにデータを送ればSlackの指定チャンネルに投稿できるようになりました。 続けてSumo側で設定を行なっていきます。

Sumo側設定

Sumo側では、まず上記で作成したWebhook URLと連携する接続設定(Connection)を作成します。 その後アラートを作成し、アラートにこのConnectionを紐付ける形です。ということでまずはConnectionから作っていきます。

Slack用のConnectionを作成する

  • Sumoにログインし、[Manage Data]-[Settings]に移動します。
  • [Connections]タブに移動し、[+]をクリックして新しいコネクションを追加します。
  • Connectionのタイプを選択する画面が表示されるので、[Slack]を選択します。
  • パラメータを設定し、[Save]をクリックしてConnetionを保存します。

    • Nameには任意の名前を指定します。
    • URLにはSlack Appで生成したWebhook URLを指定します。
    • PayloadはSlackに送るJSONデータを指定します。(下記参照)

Payloadについての解説

Payloadについてですが、SlackでIncoming Webhook経由で投稿を行う際、投稿データはJSONで指定します。そのデータの指定となります。 デフォルトは以下のような感じです。

{
    "attachments": [
        {
            "pretext": "Sumo Logic Alert: *{{SearchName}}*",
            "fields": [
                {
                    "title": "Description",
                    "value": "{{SearchDescription}}"
                },
                {
                    "title": "Query",
                    "value": "<{{SearchQueryUrl}}|{{SearchQuery}}>"
                },
                {
                    "title": "Time Range",
                    "value": "{{TimeRange}}"
                }
            ],
            "mrkdwn_in": ["text", "pretext"],
            "color": "#29A1E6"
        }
    ]
 }

なんとなく、titleとそれに対応するvalueを指定すればいいのだな、ということが分かりますね。 [Test Connection]というボタンがあるのでクリックしてみると、Slackへの投稿が行われます。

pretextというKeyに設定したテキストが上部に表示され、その後にtitlevalueの組み合わせの情報が表示されています。

で、valueに指定されている{{xxxxx}}といった値はいったいなんなんでしょう?

これはSumoで用意している変数で、実際に通知を行う際は、Sumo側で指定した値に置き換えを行います。

Payloadの項目の横にる[Help]をクリックすると、利用できる変数がリストされます。以下にコピペしたものを引用しておきます。(訳そうと思いましたが分量が多いので英語のままでご容赦ください、、、)

{{SearchName}}: Name of the saved search or monitor.
{{SearchDescription}}: Description of the saved search or monitor.
{{SearchQuery}}: The query for the saved search or metrics query.
{{SearchQueryUrl}}: The URL link to the search or metrics query.
{{TimeRange}}: Time range used to run the search or time range that triggered the metrics alert.
{{FireTime}}: The start time of the search or time that metrics alert triggered.
Metrics Only
{{AlertID}}: The ID of the triggered alert.
{{AlertStatus}}: Current status of the time series that triggered (i.e., Critical or Warning).
{{AlertThreshold}}: The condition that triggered the alert (e.g., above 90 at least once in the last 5 minutes).
{{AlertSource}}: The metric and sourceHost that triggered the alert.
{{AlertSource.fieldname}}: The value returned from the AlertSource object for the specified field name.
Logs Only
{{NumRawResults}}: The total number of results returned by the search.
{{RawResultsJson}}: JSON object containing the first 10 raw message search results.
{{AggregateResultsJson}}: JSON object containing the first 200 aggregate search results.
{{Results.fieldName}}: The first 200 search result values for the specified field name.

これらの変数を利用して、Slackに投稿したい情報を考えてPayloadを設定します。

ただ、このPayloadはアラート側の設定で上書きすることが可能です。 アラートの種類によって出力したい情報は異なると思いますので、ここはデフォルトのままにしておいてアラート側でPayloadの指定を行う形にしても構わないと思います。今回はこのアプローチを取ろうと思います。

というわけでPayloadの内容の検討は一旦置いておいて、アラートの設定に進みます。

アラート用のサーチ文を作成する

Sumo Logicのアラートについて

Sumoのアラートは、保存したサーチ文(Saved Search)を一定間隔で実行し、その結果を指定した方法で通知する、というものです。 もちろん通知する条件の指定も可能ですし、サーチ実行時常に通知させることもできます。

サーチ文の検討

さて、アラートのためのサーチ文ですが、今回は、「大量にログインに失敗している」アカウントの情報をCloudTrailから引っ張ってくるようにします。 ユーザ名・エラーコード、それにUserAgentの組み合わせでエラーが発生した回数をカウントするクエリを作ってみることにします。適当ですが、この組み合わせで1日10回以上失敗したものがあった場合にアラートで通知することにしてみましょう。 UserAgentを含めたのは、前回の記事で紹介したように、「IntelliJ IDEAからのアクセスで大量のエラーが出ている」といったことが分かる場合があるためです。

これを普通に書くと下記のようなサーチ文になります。

_sourceCategory = cm-core/cloudtrail
| json "userAgent","errorCode" 
| json "userIdentity.userName" as userName 
| count by userName, userAgent, errorCode
| where _count > 10 | sort _count

まあ出力される情報としてはこれで十分なのですが、Slackの通知に今テーブルで表示されているような情報が載ると嬉しいですよね。 先ほど書いたSlack通知用に利用できる変数では、{{Results.fieldName}}で指定フィールドの情報(の最初の200行)が取得できます。

※ fieldNameは実際には取得したフィールド名が入ります。例えばフィールド_countを取得する場合、実際は{{Results._count}}となります。

ただ、問題はこの変数で取得できるのは単一フィールドの情報だということです。 複数のフィールドの情報を表示したいのですが、どうすればいいでしょう・・・

何か使えるコマンドはないかなーとSumoのサーチ用コマンドをちょっと調べてみると、「format」というコマンドがあることが分かりました。

https://help.sumologic.jp/05Search/Search-Query-Language/Search-Operators/format

format オペレータを使用すると、パースしたフィールドのデータをフォーマットして組み合わせることができます。数値、文字列、および日付をユーザ定義の文字列にフォーマットできます。これにより、ログに埋もれて解読が困難なデータ (日付や金額) を、人間が読みやすい形式にフォーマットできます。

(略)

構文 format(, [, , , ...]) as

これを利用すると複数のフィールドの値を文字列として結合できるようです。 実行例は以下のような感じでした。

format("%s : %s","Five Minute Rate is :" , rate) as formattedVal

なるほど、C言語などのprintfに近い感じですね!

ということで、先ほどのサーチ文の後ろにこのformat文を入れて、各値を結合したフィールドを作りました。

_sourceCategory = cm-core/cloudtrail
| json "userAgent","errorCode" 
| json "userIdentity.userName" as userName 
| count by userName, userAgent, errorCode
| where _count > 10 | sort _count 
| format ("%d | %s | %s | %s", _count, userName, userAgent, errorCode) as aggField

このaggFieldをSlack通知用に渡してあげれば良さそうです。

ということでクエリも決まったので、続いては定期的にこのクエリを実行してSlackに通知するよう設定を行なっていきます。

作成したサーチを保存してスケジュールを設定する

  • [Save As]で先ほど作成したクエリを保存します。
  • [Schedule This Search]をクリックします。
  • [Run frequency]で実行間隔を設定します。デフォルト値のNeverから変更して間隔を設定すると下にアラート通知用の設定項目が追加で表示されるので、各種パラメータを入力します。

    • [Alert Type]をWebhookに設定し、[Connection]に先ほど作成したSlackのConnectionを指定します。
    • デフォルトでは、指定間隔でクエリが実行されると無条件で通知が送られます。通知を送る条件を指定したい場合は、[Send Notification]でif the following condition is met、[Alert condition]に条件を設定します。例えばクエリの結果が10件以上の場合のみ通知したいのであれば、[Alert condition]にGreater than、[Number of results]に10を設定します。
    • Slack通知用のPayloadをConnectionで設定したものと異なるものにしたい場合は[Customize Payload]をOnにし、Payloadを改めて指定します。

前述のようにクエリの結果のフィールドaggFieldをSlackに投稿したいので、Payloadは下記のように設定してみました。

{
    "attachments": [
        {
            "pretext": "CM基幹アカウント ログインに多数失敗したアカウント情報",
            "fields": [
                {
                    "title": "検索範囲",
                    "value": "{{TimeRange}}"
                },
                {
                    "title": "結果",
                    "value": "{{Results.aggField}}"
                }
            ],
            "mrkdwn_in": ["text", "pretext"],
            "color": "#29A1E6"
        }
    ]
}

結果

ここまでの設定で、SumoのアラートをSlackに投稿できるようになりました。 指定した時間になると、無事下記のようにSlackに投稿が行われていました。

きちんとした表で表示されるということなしなのですが、まあそこそこ整っている出力なので良しとしておきます。

終わりに

文章に書き起こすと結構長かったのですが、Slack連携の設定自体はSumo側で標準で実装していることもあり、それほど難しいものではありませんでした。 投稿するためのPayloadの検討は若干大変ではあったのですが、用意した変数を利用してSlackに飛ばしたい内容をある程度制御できるので、それなりに柔軟に使えるかなと思います。

以上、SumoのアラートとSlackの連携についての紹介でした。