Help us understand the problem. What is going on with this article?

Slackログイン情報をKibanaで可視化する

チームメンバーのSlackログイン情報(ユーザ名、IP等)を可視化する必要がある。Slack API からデータを取り出し、ELKのkibanaで可視化方法を紹介する

環境

  • ELK 7
  • Slack有償バージョン

Slackから情報を取り出す

Slackからログイン情報についてどこまで出せるかわからなかったので調べてみた。Slack APIページから以下の例を見つけた

...
        {
            "user_id": "U12345",
            "username": "white_rabbit",
            "date_first": 1422922493,
            "date_last": 1422922493,
            "count": 1,
            "ip": "127.0.0.1",
            "user_agent": "SlackWeb Mozilla/5.0 (iPhone; CPU iPhone OS 8_1_3 like Mac OS X) AppleWebKit/600.1.4 (KHTML, like Gecko) Version/8.0 Mobile/12B466 Safari/600.1.4",
            "isp": "BigCo ISP",
            "country": "US",
            "region": "CA"
        }
...

みた通り、面白い情報が色々入った。IP情報以外、user_agentや接続するISP情報も見える。ログにおいて重要な時間情報はdate_firstdate_lastとなる。これらのフィルドはどんな意味するかもうちょっと調べた結果、時刻 date_first(Unix epoch)から時刻 date_lastの間に count イベントが発生したことがわかった。このAPIでは、詳細のアクションは記録されないが、ログイン数のみは記録されている。

既存の環境でAPIを叩いてみる結果は以下である。ここで$TOKENはslackから発行されたAPI tokenで、xoxp-xxxxxxxxx-xxxxのフォーマットである。

$ curl -s "https://slack.com/api/team.accessLogs?token=$TOKEN&pretty=1"
{
    "ok": true,
    "logins": [
        {
            "user_id": "XXXXXXXXX",
            "username": "user1",
            "date_first": 1583519339,
            "date_last": 1583519340,
            "count": 3,
            "ip": "x.x.x.x",
            "user_agent": "SlackWeb\/0 Mozilla\/5.0 (Windows NT 10.0; Win64; x64; rv:73.0) Gecko\/20100101 Firefox\/73.0",
            "isp": null,
            "country": null,
            "region": null
        },
        {
            "user_id": "XXXXXXXXX",
            "username": "user2",
            "date_first": 1583518935,
            "date_last": 1583518935,
            "count": 3,
            "ip": "x.x.x.x",
            "user_agent": "SlackWeb\/0 Mozilla\/5.0 (Macintosh; Intel Mac OS X 10_15_3) AppleWebKit\/537.36 (KHTML, like Gecko) Slack\/4.3.3 Chrome\/78.0.3904.130 Electron\/7.1.11 Safari\/537.36 MacAppStore\/19.3.0 Sonic Slack_SSB\/4.3.3",
            "isp": null,
            "country": null,
            "region": null
        },
...

注意: このAPI使えるのは有償バージョンのSlackのみである。

このログ情報をELKにインジェストすれば、自由に可視化できる。しかし、ログ情報はどこまで遡って取れるかわからない。API仕様をよく確認すると、countpageのオプションもある。なお、countはデフォルトで100、最大で1000の値を設定でき、pageデフォルトで1、最大100である。ということは最大、100x1000=10万`のエントリーを出力(遡る)可能である。

実際、50人ぐらいのチームだと、5分間隔で1000エントリを取れば十分である。5分ごと、APIで直近の1000エントリーをとると、重複の可能性がある。APIの仕様によって、ログを取得期間を指定することができないことは悩ましい。但し、同じエントリーを上書きすれば、問題ない。解決として、同じepoch時刻で、複数ユーザがログインしないと前提し、first_dateの値をELKドキュメントのindexにした。

ELKでインジェストする

テンプレート作成

日付ごとに slack-logins-2020-03-05のようなindexを自動作成するのテンプレートを登録する。

$ curl -s -XPUT https://example.com:9200/_template/slack-logins-template
{
  "index_patterns": ["slack-logins-*"],
  "settings" : {
        "number_of_shards" : 3,
        "number_of_replicas" : 2
    },
    "mappings" : {
      "properties": {
          "user_id" : { "type" : "keyword" },
          "username" : { "type" : "keyword" },
          "ip" : { "type" : "keyword" },
          "isp" : { "type" : "keyword" },
          "country" : { "type" : "keyword" },
          "region" : { "type" : "keyword" },
          "date_first" : { "type" : "date", "format": "epoch_second" },
          "date_last" : { "type" : "date", "format": "epoch_second" }
      }
    }
}

ここで、時間フィルド date_firstdate_last{ "type" : "date", "format": "epoch_second" }にするのはポイントである。(ELK7からドキュメントのtypeは指定しなくて良い)

登録スクリプト

上記 Slack APIの出力結果はjsonフォーマットであるため、jqを使い、各ログインエントリを取り出す、indexする。登録スクリプトの例(update.sh)は以下である

update.sh
#!/bin/sh
TOKEN=xoxp-xxxxx-xxxx

# 日付からindex名を決定
INDEX=$(date +%Y-%m-%d)

# APIの結果
TMP=data.json

# Slackログインデータ取得
curl -s -x $PROXY "https://slack.com/api/team.accessLogs?token=$TOKEN&count=1000" | jq ' .logins' > $TMP

# ログインエントリを取り出し、ELKへ登録する
LEN=$(cat $TMP | jq length)
for i  in $(seq 0 $(($LEN - 1)) ); do
    ID=$(cat $TMP | jq ".[$i] | .date_first")
    cat $TMP | jq ".[$i]" | curl -s -XPOST "https://example.com:9200/slack-logins-$INDEX/_doc/$ID" -H 'Content-Type: application/json' -d @-
done

尚、-d @-stdinからjsonデータを入力できるcurlの便利なオプションである。ELK7からtypeを指定の代わりに、_docを使う。

上記のスクリプトを crontabへ登録すれば、定期的にデータをELKへ登録できる(スクリプトの絶対パスは
/home/robot/work/elk/slack-login/update.sh とする)

*/5 * * * *             /home/robot/work/elk/slack-login/update.sh > /dev/null 2>&1

可視化する

KibanaのDiscoverツールでindexを作成されることが確認できたら、date_firstをドキュメントのtimestampとしてindex patternを登録すれば、従来の手順で、グラフやdashboardを作成する。

例えば、我々はこのようなdashboardを作成した。
スクリーンショット 2020-03-07 5.04.17.png

まとめ

Slack APIを用い、チームのログイン情報をELKで可視化するの例をまとめた。ログイン情報において、ユーザ名やIP情報などの他に接続ISPやagentの種類なども入っていた。

参考情報

bachng
エンジニア
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away