チームメンバーの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_first
とdate_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仕様をよく確認すると、count
とpage
のオプションもある。なお、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_first
、date_last
を{ "type" : "date", "format": "epoch_second" }
にするのはポイントである。(ELK7からドキュメントのtype
は指定しなくて良い)
登録スクリプト
上記 Slack APIの出力結果はjsonフォーマットであるため、jq
を使い、各ログインエントリを取り出す、indexする。登録スクリプトの例(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を作成する。
まとめ
Slack APIを用い、チームのログイン情報をELKで可視化するの例をまとめた。ログイン情報において、ユーザ名やIP情報などの他に接続ISPやagentの種類なども入っていた。