こんにちは!現場でボロボロになりながらも、システムの安定稼働のために日夜戦い続ける同志の皆さん。
今回は、多くの監視エンジニアが一度は頭を抱える「ZabbixのWebシナリオ監視で、OAuth2やJWT(JSON Web Token)を使ったモダンなWebアプリケーションをどうやって攻略するか」について、現場でそのまま使える実践的なノウハウをたっぷりとお伝えします。
「Zabbixの標準機能だけだと、ログイン画面で弾かれてしまう……」
「APIの認証トークンが動的に変わるから、死活監視が組めない……」
そんな悩みを抱えていませんか? 大丈夫、この記事を読めば、現代の複雑な認証基盤を持つシステムであっても、Zabbixで完璧に、そして美しく死活監視を回せるようになります。これをマスターすれば、あなたの運用ライフは劇的に楽になりますよ。肩の力を抜いて、一緒に紐解いていきましょう!
—
1. なぜモダンな認証監視はZabbix標準機能では太刀打ちできないのか?
まずは敵を知ることから始めましょう。Zabbixには「Webシナリオ」という強力な機能があります。ブラウザの動きを模倣して、ステップごとにURLを叩き、HTTPステータスコードやレスポンスの中身(文字列)をチェックできる優れものです。
しかし、これは「古き良きセッションID(Cookie)ベース」のWebアプリ全盛期の話。
今のモダンなWebアプリケーション、特にマイクロサービスアーキテクチャやシングルページアプリケーション(SPA)の裏側はどうなっているでしょうか?
- OAuth2 / OpenID Connect: 認証サーバー(Keycloak, Auth0, Azure ADなど)にリクエストを送り、認可コードやアクセストークンをやり取りする。
- JWT(JSON Web Token): 発行されたトークンをリクエストヘッダー(`Authorization: Bearer
`)に載せないと、APIエンドポイントが一切データを返してくれない。
Zabbix標準のWebシナリオ機能は「フォームの入力値(POST)」を設定することはできますが、「取得した動的なJSONレスポンスからトークンをパースし、次のリクエストのHTTPヘッダーに動的に埋め込む」という高度なプログラミング的処理を苦手としています(※古いバージョンや標準機能の組み合わせでは非常にトリッキーな実装が必要になります)。
だからこそ、私たちはZabbixの「JavaScriptオブジェクト(`HttpRequest`)」を使ったカスタムスクリプト監視という武器を使う必要があります。これを使えば、Zabbixの内部で小さなブラウザ(HTTPクライアント)を自由自在に操れるようになります。
—
2. 全体アーキテクチャ:OAuth2監視の仕組み
今回構築する監視のフローは、人間がブラウザやAPIクライアントで行っている認証プロセスを、Zabbixが忠実に再現するものです。
[Zabbix Server / Proxy]
│
├─ 1. POST /oauth/token (Client ID / Secret送信)
│ └─ 2. 応答としてJWTアクセストークンを取得
│
├─ 3. GET /api/v1/health (Headerに “Bearer
│ └─ 4. ステータスコード 200 OK を確認
│
└─ (成否をメトリクス化 / トリガーでアラート発報)
この一連の流れを、Zabbixの「HTTPエージェント」アイテムと「JavaScriptの前処理(Preprocessing)」を組み合わせて実装します。
—
3. 実践!OAuth2/JWT突破スクリプトの全体像
それでは、実際にZabbixに設定するスクリプトと手順を見ていきましょう。
今回は、以下のシナリオを想定します。
1. 認可エンドポイントへ `client_id` と `client_secret` をPOSTし、JWTアクセストークンを取得する。
2. 取得したトークンを使い、保護されたAPIのヘルスチェック用エンドポイントにGETリクエストを投げる。
3. レスポンスが正常(HTTP 200)か、あるいはJSON内のステータスが `UP` かを検証する。
ステップ1: Zabbixアイテムの作成
Zabbixの対象ホストに対して、新しいアイテムを追加します。
- 名前: `App Health Check with OAuth2`
- タイプ: `HTTPエージェント`
- キー: `app.health.oauth2`
- URL: `https://api.your-domain.com/api/v1/health` (最終的に叩きたい保護されたエンドポイント)
- リクエストの種類: `GET`
ステップ2: カスタムJavaScriptによる前処理(ここが核心!)
アイテムの設定画面にある「前処理 (Preprocessing)」タブを開き、「JavaScriptの実行」を追加します。ここに、すべての魔術を記述します。
以下のコードをコピーして、コメントを読みながら貼り付けてください。
// =================================================================
// Zabbix JavaScript Preprocessing for OAuth2 / JWT Health Check
// =================================================================
// 1. 認証情報の定義(環境に合わせて書き換えてください)
var tokenUrl = “https://auth.your-domain.com/oauth/token”;
var clientId = “zabbix_monitoring_client”;
var clientSecret = “your_super_secret_password_here”;
// HTTPクライアントのインスタンス化
var request = new CurlHttpRequest();
// タイムアウト設定(秒)
request.SetTimeout(10);
// 2. OAuth2 トークン取得リクエストの組み立て
// Content-Typeをapplication/x-www-form-urlencodedに設定
request.AddHeader(“Content-Type: application/x-www-form-urlencoded”);
var postData = “grant_type=client_credentials” +
“&client_id=” + encodeURIComponent(clientId) +
“&client_secret=” + encodeURIComponent(clientSecret);
Zabbix.log(4, “[OAuth2 Check] Requesting access token to: ” + tokenUrl);
// トークンエンドポイントへPOST送信
var tokenResponse = request.Post(tokenUrl, postData);
var responseCode = request.Status();
// トークン取得の成否チェック
if (responseCode !== 200) {
Zabbix.log(1, “[OAuth2 Check] Failed to get token. Status: ” + responseCode + “, Response: ” + tokenResponse);
throw “Failed to authenticate against OAuth2 server. HTTP Status: ” + responseCode;
}
// 3. 取得したJSONレスポンスからJWTアクセストークンを抽出
try {
var tokenData = JSON.parse(tokenResponse);
var accessToken = tokenData.access_token;
if (!accessToken) {
throw “Access token is missing in the OAuth2 response.”;
}
} catch (error) {
Zabbix.log(1, “[OAuth2 Check] JSON Parse Error: ” + error);
throw “Failed to parse OAuth2 token response: ” + error;
}
// 4. 保護されたAPIエンドポイントへのリクエスト準備
// 取得したJWTを Bearer トークンとしてヘッダーにセット
request.AddHeader(“Authorization: Bearer ” + accessToken);
request.AddHeader(“Accept: application/json”);
// Zabbixのアイテム設定で指定したURLに対してGETリクエストを実行
// (ZabbixのHTTPエージェントが保持している本体URLを呼び出すための特殊変数 value を利用することも可能ですが、
// 今回はスクリプト内で完結させるため、明示的にURLを指定します)
var targetApiUrl = “https://api.your-domain.com/api/v1/health”;
Zabbix.log(4, “[OAuth2 Check] Requesting protected API: ” + targetApiUrl);
var apiResponse = request.Get(targetApiUrl);
var apiResponseCode = request.Status();
// 5. 最終的な死活判定
if (apiResponseCode !== 200) {
Zabbix.log(1, “[OAuth2 Check] API health check failed. Status: ” + apiResponseCode);
// 異常時は 0 を返す、あるいはエラーをスローする
return 0;
}
// 必要に応じてAPIのレスポンスボディ(JSON)の中身まで検証する場合
try {
var healthData = JSON.parse(apiResponse);
// 例: {“status”: “UP”} を期待する場合
if (healthData.status && healthData.status === “UP”) {
return 1; // 正常
} else {
Zabbix.log(1, “[OAuth2 Check] API returned unhealthy status: ” + apiResponse);
return 0; // 異常
}
} catch (e) {
// JSONパースできなくてもHTTP 200ならとりあえず正常とするか、厳密に弾くかは設計次第
return 1;
}
—
4. この設計が現場で最強である理由(プロの知見)
このアプローチを採用することで、運用現場において以下のような圧倒的なメリットが生まれます。
1. セッションの肥大化・リークがない
Zabbixの標準Webシナリオは、ブラウザセッション(Cookie)を維持しようとしてセッションファイルがディスクを圧迫したり、予期せぬキャッシュが残るトラブルがありますが、このJavaScriptベースの `CurlHttpRequest` はステートレスに毎回トークンを取得して破棄するため、非常にクリーンでノイズがありません。
2. 障害の切り分けが容易になる
もしアラートが鳴ったとき、「認証サーバー(OAuth2)が死んでトークンが取れなかったのか」それとも「認証は通ったが肝心のAPIサーバーが500エラーを吐いたのか」を、Zabbixのログ(`Zabbix.log`)やスクリプト内の例外メッセージで一発で特定できます。
3. 柔軟な拡張性
例えば、APIリクエストの前に特定の署名(HMACなど)を計算してヘッダーに付与する必要がある場合でも、Zabbix内蔵のJavaScriptエンジン(EcmaScript 6相当)には `btoa` や各種ユーティリティがあるため、大体の要件をこの前処理スクリプト一つで完結させられます。
—
5. 動作確認とデバッグの極意
設定したら、必ず「テスト」ボタン(ZabbixのUI上にある、アイテム設定内のテスト機能)を使って動作確認をしてください。
- デバッグログを活用する:
スクリプト内の `Zabbix.log(4, …)` は、Zabbixサーバーのログファイル(通常 `/var/log/zabbix/zabbix_server.log`)にデバッグレベルで出力されます。もし上手くいかない場合は、Zabbixのログレベルを一時的に `DebugLevel=4` に引き上げて、どのようなリクエストが飛び、どこで弾かれているのかをリアルタイムで追跡しましょう。
- 証明書エラーへの対策:
検証環境などでオレオレ証明書(自己署名証明書)を使っている場合、デフォルトでは `CurlHttpRequest` はSSL/TLS証明書の検証に失敗して弾かれます。その場合は、必要に応じて内部的な証明書ストアの設定や、検証をバイパスする設定(もし安全な閉域網であれば)を考慮しますが、基本的には本番環境では正しく信頼された証明書チェーンを使用してください。
—
おわりに
いかがでしたでしょうか?
一見すると難しそうに見えるOAuth2やJWTを使ったモダンな認証フローも、ZabbixのJavaScript前処理を組み合わせることで、完全に手の内に入れることができます。
「監視ツールが進化しないからモダンなアプリの監視は諦める」のではなく、「監視ツール側の拡張性を理解してスマートにハックする」。これこそが、私たちインフラ・オブザーバビリティエンジニアの醍醐味です。
これをマスターすれば、開発チームから「新しい認証基盤に変えたから監視できないよ」と言われても、「余裕で対応できるよ」と涼しい顔で返すことができます。毎日の運用作業が、少しでも知的でワクワクするものになりますように。
それでは、次の現場でお会いしましょう!