インシデント Webhook プッシュ¶
Webhook は、インシデントの重要な変更をサードパーティシステムにプッシュするために使用します。インシデント情報を ITSM、自動化プラットフォーム、または社内業務システムに連携し、サードパーティが受信したデータに基づいてチケット作成、ステータス同期、自動化フローのトリガーなどを実行できます。
インシデントセンター > 設定管理 > Webhook で Webhook を作成・管理できます。
前提条件¶
まず、POST リクエストを受信可能なサードパーティのエンドポイントを用意してください。Webhook は HTTP および HTTPS アドレスをサポートします。本番環境では HTTPS の使用を推奨します。セキュリティ上の理由から、内部ネットワーク、ループバック、またはローカルホストアドレスは設定できません。
Webhook の設定¶
- Webhook ページで Webhook を作成 をクリックします。
- 名前とサードパーティの受信 URL を入力します。
-
自動プッシュするインシデントイベントを選択します:
イベント 説明 インシデント作成 新規インシデント作成時にプッシュします。 ステータス変化 インシデントステータスが変化したときにプッシュします。 重要度変更 インシデント重要度が変更されたときにプッシュします。 担当者変更 インシデント担当者が変更されたときにプッシュします。 集約変更 集約インシデントの関連イベントが変更されたときにプッシュします。インシデント集約ルールによって生成されたインシデントにのみ有効です。 -
Token を生成 をクリックします。Token は Guance プラットフォームでのみ生成されます。すぐにコピーし、サードパーティの受信サービスの鍵設定に安全に保存してください。
- 有効状態を設定して保存します。
自動トリガーイベントは選択しなくても構いません。Webhook が有効な場合、自動トリガーイベントが設定されていなくても、インシデント詳細ページから手動送信が可能です。
注意
- Token は Webhook の認証キーです。生成後、プラットフォーム上で一度だけ平文が表示され、以降のページではマスクされた値のみが表示されます。Token を再生成すると、以前の Token は直ちに無効になります。
- Webhook の配信に失敗しても、インシデントの作成、更新、復旧、クローズには影響しません。
- Webhook は固定のリクエスト方式、認証方式、およびタイムアウト時間を使用するため、追加設定は不要です。
テスト送信¶
Webhook を保存した後、該当 Webhook の操作項目から テスト をクリックし、イベントタイプを選択できます。システムは正式なリクエスト形式でテストデータを送信します。この際、Payload 内の isTest は true になります。
テスト結果は 送信履歴 で確認できます。テスト送信は実際のインシデントに影響を与えず、正式な送信統計にもカウントされません。
手動送信¶
インシデント詳細ページで Webhook を送信 をクリックすると、インシデントの最新スナップショットを有効な Webhook に即座に送信できます。Webhook を選択し、1~1000 文字の送信説明を入力して送信します。手動送信には以下の特徴があります:
- すべてのインシデントステータスに対応しており、該当 Webhook の自動トリガーイベント設定や集約ウィンドウの影響を受けません。
- 毎回選択できる Webhook は 1 つです。同一メンバーは 5 秒以内に同一インシデントと同一 Webhook に対して重複送信できません。
2xxステータスコードの返却を成功とみなします。ネットワーク異常、URL 無効、応答タイムアウト、または2xx以外のステータスコードは失敗とみなされます。- 送信結果は 送信履歴 に記録され、イベントタイプは「手動トリガー」、送信タイプは「正式」と表示されます。
- 送信失敗時の自動リトライは行われません。再送信が必要な場合は、インシデント詳細ページに戻って再度トリガーしてください。
手動送信の Payload はリクエストプロトコルとインシデントスナップショットの構造に従い、以下の情報が追加されます。
| フィールド | 説明 |
|---|---|
eventTypes |
incident.manual_triggered を含みます。 |
triggerSource |
固定値 manual。 |
manualContext |
手動送信コンテキスト。操作者、送信説明、操作時刻を含みます。 |
手動送信によって、インシデントのコラボレーション記録やアクティビティタイムラインに新しいレコードが追加されることはありません。
リクエストプロトコル¶
システムは POST メソッドで JSON データを送信します。リクエストのタイムアウト時間は 5 秒で、リダイレクトには追従しません。受信サービスが任意の 2xx ステータスコードを返した場合、配信成功とみなされます。
リクエスト Header¶
| Header | 説明 |
|---|---|
Content-Type |
固定値 application/json。 |
Authorization |
固定形式 Bearer <Token>。 |
X-Incidents-Event-Id |
今回の配信の一意の識別子。受信側での冪等処理に使用できます。 |
X-Incidents-Timestamp |
Unix 秒単位のタイムスタンプ。 |
X-Incidents-Signature |
HMAC-SHA256 署名。形式は v1=<signature>。 |
Payload サンプル¶
{
"eventId": "evt_01JXYZ...",
"eventTypes": [
"incident.created",
"incident.status_changed"
],
"eventTime": 1783000000,
"workspaceUUID": "wksp_xxx",
"incident": {
"uuid": "incident_xxx",
"name": "API service unavailable",
"level": "level_1",
"incidentsStatus": "working",
"resourceType": "incident_aggregation",
"aggregationRuleUUID": "rule_xxx",
"aggregationRuleNameSnapshot": "生产环境服务聚合",
"eventRelations": [
{
"df_fault_id": "fault_xxx",
"status": "critical",
"aggregationValues": {
"df_workspace_name": "production",
"df_dimension_tags.host": "web-01"
}
}
]
},
"isTest": false
}
フィールド説明:
| フィールド | 説明 |
|---|---|
eventId |
1 回の Webhook 配信バッチの一意の ID。元のイベント ID ではありません。 |
eventTypes |
今回のバッチに含まれるインシデント変化のタイプ。 |
eventTime |
今回の配信の Unix 秒単位のタイムスタンプ。 |
workspaceUUID |
インシデントが属するワークスペースの UUID。 |
incident |
インシデントの現在の完全なスナップショット。具体的なフィールドは後述を参照。resourceContent はプッシュされません。 |
isTest |
テスト送信かどうか。 |
incident フィールド説明¶
incident は送信時点のインシデントスナップショットです。インシデントの重要度、ステータス、担当者、関連イベントの変化に応じて更新されます。
| フィールド | 型 | 説明 |
|---|---|---|
id |
integer | インシデントレコードの内部数値 ID。 |
uuid |
string | インシデント UUID。形式は incident_xxx。サードパーティ側でのインシデント主キーとして推奨。 |
workspaceUUID |
string | インシデントが属するワークスペースの UUID。 |
name |
string | インシデントタイトル。 |
level |
string | 現在のインシデント重要度の UUID または重要度識別子。 |
description |
string | インシデントの説明。 |
incidentsStatus |
string | インシデント業務ステータス。一般的な値は open(未割り当て)、working(処理中)、resolved(解決済み)、closed(クローズ済み)。 |
assigner |
array | 現在の担当者アカウント UUID のリスト。未割り当ての場合は空の配列。 |
statusTime |
object | 各インシデント業務ステータスに対応するタイムスタンプレコード。 |
statusChangeTime |
integer | 直近のインシデント業務ステータス変更の Unix 秒単位のタイムスタンプ。 |
cumulativeTime |
integer | インシデント累積継続時間(秒単位)。 |
eventCount |
integer | 現在のインシデントに累積で関連付けられているイベント数。 |
eventUpdateAt |
integer | 直近の関連イベント更新の Unix 秒単位のタイムスタンプ。 |
eventRelations |
array | 現在の関連イベントスナップショット。フィールド説明は後述。 |
source |
string | インシデントソース識別子。 |
resourceCategory |
string | ソースリソースカテゴリ。 |
resourceType |
string | ソースリソースタイプ。集約ルールによって生成されたインシデントは固定値 incident_aggregation。 |
resourceUUID |
string | ソースリソース UUID。 |
resourceUrl |
string | ソースリソースのアクセス URL。URL がない場合は空文字。 |
resourceIdentity |
string | 同一ソースのインシデントを識別するためのリソース識別子。 |
aggregationRuleUUID |
string | 集約インシデントを生成したルールの UUID。集約インシデントのみ返却。 |
aggregationRuleNameSnapshot |
string | インシデント作成時に記録された集約ルールの名前スナップショット。集約インシデントのみ返却。ルール名が変更または削除された後でも、履歴ソースを特定するために使用可能。 |
dimensionTag |
object | インシデントに関連付けられたディメンションタグ。 |
dtHost |
string | 抽出されたホストのディメンション値。 |
dtService |
string | 抽出されたサービスのディメンション値。 |
dtResource |
string | 抽出されたリソースのディメンション値。 |
dtPodName |
string | 抽出された Pod 名のディメンション値。 |
dtAppName |
string | 抽出されたアプリケーション名のディメンション値。 |
dtAppId |
string | 抽出されたアプリケーション ID のディメンション値。 |
dtEnv |
string | 抽出された環境のディメンション値。 |
dtUrl |
string | 抽出された URL のディメンション値。 |
extend |
object | インシデント拡張情報。このオブジェクトは製品機能の進化に伴い拡張される可能性があります。サードパーティは認識できないフィールドを無視してください。 |
status |
integer | インシデントレコードの状態。レコードが有効かどうかを示します。インシデント業務ステータスとして使用しないでください。 |
creator |
string | インシデントレコードを作成したアカウント UUID またはシステム識別子。 |
updator |
string | インシデントレコードを最後に更新したアカウント UUID またはシステム識別子。 |
createAt |
integer | インシデントレコード作成時間(Unix 秒単位のタイムスタンプ)。 |
updateAt |
integer | インシデントレコード最終更新時間(Unix 秒単位のタイムスタンプ)。 |
deleteAt |
integer | インシデントレコード削除時間。削除されていない場合は通常負の値。 |
eventRelations の各要素は、現在関連付けられている 1 つのイベントを表します。安定して返却されるフィールドは次のとおりです。
| フィールド | 型 | 説明 |
|---|---|---|
df_fault_id |
string | 関連イベントのインシデント ID。 |
status |
string | 関連イベントの現在のステータス。例:critical や ok。 |
aggregationValues |
object | 集約キー値のスナップショット。キーはルール保存時の完全なフィールドパス、値は集約 ID 生成時に使用された正規化値。集約インシデントの関連イベントのみ返却。 |
イベントソースによっては、追加のフィールドが含まれる場合があります。サードパーティは df_fault_id で関連イベントを識別し、認識できない拡張フィールドは無視してください。過去の集約インシデントの場合、aggregationValues が欠落または空である可能性があるため、受信側は互換性を持って処理する必要があります。集約インシデントの関連イベントスナップショットまたは集約キー値が変更されると、「集約変更」イベントがトリガーされます。
リクエスト送信元の検証¶
サードパーティの受信サービスは、Token、タイムスタンプ、署名のすべてを同時に検証する必要があります。
署名の元となる文字列は次のとおりです。
ここで rawRequestBody は受信した生のリクエストバイトです。JSON を事前にフォーマットしたり再シリアライズしたりしないでください。現在時刻の前後 5 分以内のリクエストのみを受け入れ、eventId で重複を排除することを推奨します。
import hashlib
import hmac
import time
def verify_webhook(request, token):
raw_body = request.get_data(cache=True)
timestamp = request.headers.get("X-Incidents-Timestamp", "")
event_id = request.headers.get("X-Incidents-Event-Id", "")
signature = request.headers.get("X-Incidents-Signature", "")
authorization = request.headers.get("Authorization", "")
if not hmac.compare_digest(authorization, f"Bearer {token}"):
return False
if not timestamp.isdigit() or abs(time.time() - int(timestamp)) > 300:
return False
message = f"{timestamp}.{event_id}.".encode("utf-8") + raw_body
expected = "v1=" + hmac.new(
token.encode("utf-8"), message, hashlib.sha256
).hexdigest()
return hmac.compare_digest(expected, signature)
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
boolean verify(byte[] rawBody, String timestamp, String eventId,
String signature, String authorization, String token) throws Exception {
if (!MessageDigest.isEqual(
authorization.getBytes(StandardCharsets.UTF_8),
("Bearer " + token).getBytes(StandardCharsets.UTF_8))) return false;
byte[] prefix = (timestamp + "." + eventId + ".").getBytes(StandardCharsets.UTF_8);
byte[] content = new byte[prefix.length + rawBody.length];
System.arraycopy(prefix, 0, content, 0, prefix.length);
System.arraycopy(rawBody, 0, content, prefix.length, rawBody.length);
Mac mac = Mac.getInstance("HmacSHA256");
mac.init(new SecretKeySpec(token.getBytes(StandardCharsets.UTF_8), "HmacSHA256"));
String expected = "v1=" + java.util.HexFormat.of().formatHex(mac.doFinal(content));
return MessageDigest.isEqual(expected.getBytes(StandardCharsets.UTF_8),
signature.getBytes(StandardCharsets.UTF_8));
}
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
)
func verifyWebhook(rawBody []byte, timestamp, eventID, signature, authorization, token string) bool {
if !hmac.Equal([]byte(authorization), []byte("Bearer "+token)) {
return false
}
content := append([]byte(timestamp+"."+eventID+"."), rawBody...)
mac := hmac.New(sha256.New, []byte(token))
mac.Write(content)
expected := fmt.Sprintf("v1=%x", mac.Sum(nil))
return hmac.Equal([]byte(expected), []byte(signature))
}
配信と送信履歴¶
同一の Webhook が同一のインシデントに対して短時間に連続して複数の変化を発生させた場合、システムはこれらを 1 回の配信にまとめ、Payload の eventTypes に今回含まれる変化のタイプを返します。Payload は常に送信時点の最新のインシデントスナップショットを基準とします。
システムは自動リトライを行いません。送信履歴 では、送信ステータス、インシデント UUID、またはイベントタイプごとに配信結果を確認できます。失敗レコードには応答コードとエラー詳細が表示されるため、サードパーティの受信サービスのトラブルシューティングに役立ちます。自動プッシュに失敗した場合、再送信が必要な場合は、該当するインシデント詳細ページに移動して手動でトリガーしてください。