2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

Zabbixの通知を追加投資なしでLINE WORKSに飛ばす方法(API2.0対応版)

Posted at

まずはじめに

前回の投稿同様、ネットに転がっている情報を切り貼りして作ったクソコードなので、利用する場合は自己責任でお願いします。

やりたいこと

  • ZABBIXのサーバ監視の通知をLINE WORKSで受け取りたい
  • コストかけずにやりたい

前提条件

  • ZABBIXをインストールしたLinuxサーバがある
  • ZABBIXのアクションとメディアタイプとユーザー>メディアの設定が完了している
  • LINE WORKSを使っていて管理者であること(フリープランでもOKらしい)
  • 固定IPは不要
  • なんでトーク送信するだけのBotにまで認証させるのおぉぉ!
  • API2.0なんてきらい!!!

当方の構成(参考)

  • AlmaLinux 8.8(仮想マシン)
  • Zabbix 5.0.37
  • LINE WORKS スタンダードプラン

全体の流れ

  1. ZABBIX導入(適当)
  2. ZABBIXの通知をカスタム、アクションとメディアタイプとメディアの設定をする(適当)
  3. LINE WORKS Developer ConsoleのAPIからアプリを新規追加
  4. LINE WORKS Developer ConsoleでBotを作る
  5. ShellScriptをかく
  6. 通知してみる

ZABBIX導入(適当)

別に難しい作業はないと思ってましたが、なんかちょっとめんどくさそうなので、Qiitaで見つけたページを貼っておきます。

2. ZABBIXの通知をカスタム、アクションとメディアタイプとメディアの設定をする(適当)

この辺は前回書いた記事と一緒。

LINE WORKS Developer ConsoleのAPIからアプリを新規追加

とても簡単

アプリの新規追加を押して
image.png

アプリ名を入れて
image.png

OAuth Scopeの中から「bot」を選んで
image.png

保存
image.png
※よく考えたらすぐ消すのにClient IDとかモザイク入れる意味なかったデス。

やったね!1個アプリが増えました。
image.png

このままではService Accountが発行されてないので、発行ボタンを押して発行しておきます。
image.png
最後にPrivate Keyを発行してAPI(アプリ)の設定は完了です。
image.png
ダウンロードしたら、ShellScriptを設置するサーバに保存しておきます。
今回は/usr/lib/zabbix/alertscripts/private.keyに保存してます。
その他にもClient IDClient SecretService Accountはコピーしておいてください。

LINE WORKS Developer ConsoleでBotを作る

これも簡単

右上の登録を押して
image.png

必須項目(Bot名、説明、主担当)を入力して保存
image.png
※今回のBotはただ単に通知をするだけのものなので、固定メニュー、Callback URL、トークルームへの招待は利用しません。
image.png
image.png
無事「通知するクン」(Bot番号:6531760)が追加されました。

ShellScriptをかく

今回使っているコマンド類は以下の通り。

  • date
  • tr
  • sed
  • base64
  • openssl
  • curl
  • jq

あと、今回ZABBIXから通知する際、スクリプトに以下の引数を渡す予定です。

  • 第一引数:ZABBIXのアラートタイトル
  • 第二引数:アラート本文
  • 第三引数:Bot番号(今回の例なら6531760)
  • 第四引数:通知を受けたいLINE WORKSのID

image.png
第三引数と第四引数をShellScriptに埋め込んでしまうことも可能ですが、複数人に通知したい場合はこっちの方がよいでしょう。

今更だけど、LINE WORKS DevelopersのドキュメントにあるService Account認証(JWT)のページを参照して、どういう風に動いているのかを把握しておいてください。
https://developers.worksmobile.com/jp/docs/auth-jwt

本ShellScriptでは、以下の流れで動かしています。

  1. JWTを生成する
  2. 生成したJWTでAccess Tokenの取得をリクエストする
  3. Access TokenとRefresh Tokenがレスポンスされる
  4. Access Tokenを使ってTalkをSend

このとき、Access Tokenは24時間、Refresh Tokenは90日の有効期限で発行されます。
Refresh Tokenの有効期限内なら、何度でもAccess Tokenを再発行できるので、当初はRefresh Tokenを使ってAccess Tokenの再発行をリクエストしようと思っていました。
が、LINE WORKS Developersのコミュニティをサッと検索すると、Refresh Tokenを使ってAccess Tokenの再発行リクエストを行っても、Refresh Tokenの有効期限が伸びず、結局90日に1回以上JWTでのAccess Token発行リクエストを出さなければならないようです。

上記の事情で本ShellScriptでは毎回JWTを生成してAccess Tokenの発行をリクエストしています。
(要検証だが90日も待てないわよアタシ)

ということで、コードは以下。
sedを使うな!とか、めちゃくちゃなコードじゃねーか!とかそういうご指摘はあろうかと思いますけど、本職はPCのキッティングとかしてる底辺社内SEなので許してね。
てか、誰かコード直してクレメンス

LineWorksApi2.0TalkSendBot.sh
# 今の時間(UNIX秒)
iat=`date +%s`

# 1時間後(UNIX秒)
exp=`date +%s -d "1 hour"`

# LINEWORKS Developer ConsoleのアプリのClient ID
iss="<Client ID>"

# LINEWORKS Developer ConsoleのアプリのService Account
sub="<Service Account>"

# LINEWORKS Developer ConsoleのアプリのClient Secret
c_sec="<Client Secret>"

# 認証リクエストヘッダ(JSON)
head="{\"alg\":\"RS256\",\"typ\":\"JWT\"}"

# 認証用JSON Claims Set(JSON)
claims="{\"iss\":\"$iss\",\"sub\":\"$sub\",\"iat\":$iat,\"exp\":$exp}"

# 秘密鍵(LINEWORKS Developer Consoleのアプリからダウンロードしたもの)
p_key="/usr/lib/zabbix/alertscripts/private.key"

# タイトル(ダブルクォーテーション削除、半角スペースエスケープ)
title=`echo $1 | tr -d '"' | tr ' ' '\ '`

# 本文(ダブルクォーテーション削除、半角スペースエスケープ)
body=`echo $2 | tr -d '"' | tr ' ' '\ '`

# 送信メッセージ全体
msg=$title'\n'$body

# Bot番号
bot=$3

# LINEWORKS_account
lwacc=$4

# ヘッダとクレームのbase64エンコード(URLセーフ化を含む)
head64=$(echo -n $head | base64 -w 0 | sed -e 's/=$//' -e 's/+/-/' -e 's/\//_/')
claims64=$(echo -n $claims | base64 -w 0 | sed -e 's/=$//' -e 's/+/-/' -e 's/\//_/')

# ヘッダとクレームを連結
head_claims="$head64.$claims64"

# ヘッダとクレームをデジタル署名してbase64エンコード(URLセーフ化を含む)
# ちゃんとしたいけどこれで動いてるから触りたくない(ここで結構ハマった)
jwt_sig=$(echo -n $head_claims \
        | openssl dgst -sign $p_key -sha256 -binary \
        | base64 -w 0 | sed -e 's/=$//' -e 's/+/-/' -e 's/\//_/'\
        | tr '+' '-' | tr '/' '_'\
        | sed -e 's/=$//' -e 's/+/-/' -e 's/\//_/')

# ヘッダ、クレーム、シグネチャを連結してJWTを生成
jwt="$head64.$claims64.$jwt_sig"

# 生成したJWTを使ってAccess Tokenを発行
jws=$(curl --location --request POST 'https://auth.worksmobile.com/oauth2/v2.0/token' \
 --header 'Content-Type: application/x-www-form-urlencoded' \
 --data-urlencode "assertion=${jwt}" \
 --data-urlencode "grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer" \
 --data-urlencode "client_id=${iss}" \
 --data-urlencode "client_secret=${c_sec}" \
 --data-urlencode "scope=bot")

# 認証リクエストした結果のうち、Access Tokenだけを変数に代入
acctkn=`echo $jws|jq -r '.access_token'`

# トークの中身(コンテンツ)
cont="{\"content\":{\"type\":\"text\",\"text\":\"$msg\"}}"

# トーク送信用URL
url="https://www.worksapis.com/v1.0/bots/${bot}/users/${lwacc}/messages"

# 送信処理
curl -v -H "Content-Type: application/json; charset=UTF-8" \
 -H "Authorization: Bearer ${acctkn}" \
 -X POST --data-binary "$cont" \
 $url

exit 0

通知してみる

[User@Hostname alertscripts]# sudo sh LineWorksApi2.0TalkSendBot.sh "タイトル" "本文" 6531760 <LINE WORKSのID>

どうでしょう?
通知できましたか?

さいごに

実は、API2.0への変更のタイミングで、もうZABBIXのLINE WORKS通知は諦めようと思っていました。
実際、旧APIが停止した7月くらいから10月までZABBIXの通知を止めていました。
しかし、障害発生時に通知が来ないのは不便、、というか危険だなと思い、重い腰を上げた次第です。

Botはプログラマさんが作るもの、という認識は間違いではないと思いますが、なにかの通知をトークに送信するだけの簡易なBotなら、私のようなニワカSEでも作れるくらい簡単です。
でも、その簡単なものもドキュメントやサンプルコードが整備されていないと途端に難しくなる。
特に、LINE WORKSのBotを簡易に動かすためのサンプルコードが不足していると感じます。

この記事が僅かでも誰かの役に立てば嬉しく思います。

2
2
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
2

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?