0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ServiceNow MCP に脆弱性対応(VR/USEM)ツール群を追加してみた

0
Last updated at Posted at 2026-06-27

ServiceNow を AI から自然言語で操作する MCP サーバーに、脆弱性対応(Vulnerability Response / USEM) 専用のツール群を追加しました。
脆弱性アイテム(VI)・修復タスク・NVD・統合フィード・SLA・通知・例外承認まで、SecOps の一連の運用を AI から扱えます。

GitHub: https://github.com/tedorigawa001/ServiceNow-MCP

追加した機能

src/tools/ に USEM 系モジュールを足しました。
secops_analyst というツールパッケージに集約してあります。

モジュール 主なツール
usem.ts VI/修復タスク/NVD/脆弱性グループの一覧・取得・作成・更新
usem-config.ts アサインメント/修復タスク/TTR/承認/自動クローズ/除外の各ルール操作
usem-integration.ts 統合フィード(NVD/Qualys/CSAF…)のカタログ・実行履歴・ログ・有効化
usem-sla.ts TTR ベースの SLA 状況・コミット日設定・VR 通知の発見
usem-approval.ts 例外申請の可視化と、承認/却下による state 遷移

以下は私が実装していく上でハマった落とし穴です。。。

落とし穴1: 「修復タスク」は2つある

USEM のデータモデルを調べ始めて最初に混乱したのがこれです。
USEMには「Remediation Task」と名の付くものが2系統あります。

  • sn_vul_remediation_task … 新しめのモデル。task テーブルを継承していないベーステーブル。人間可読キーは number ではなく task_number
  • sn_vul_vulnerability … 「Vulnerability Group」。実は sys_class のラベルが文字通り "Remediation Task"、番号プレフィクスは VUL。そしてこちらは task を継承している

最初、私は前者だけを「修復タスク」として実装し、後者の継承を見落としていました。
レビューで「sn_vul_vulnerability は task を継承しているはず」と指摘され、実機で確認:

sn_vul_vulnerability      -> task   ← task 継承(ご指摘どおり)
sn_vul_app_vulnerability  -> task
sn_vul_remediation_task           (継承なし)
sn_vul_vulnerable_item            (継承なし)

これが重要なのは、task 継承=task_sla が効くからです。
VI/RT 自身は task ではないので task_sla(汎用の get_sla_details)が使えませんが、グループは使えます。record_typevi/rt/vg の3種を用意し、グループは task_sla とTTR の両方を返すようにしました。

教訓: 「修復タスク」という UI ラベルだけで実テーブルを推測しない。sys_db_object.super_class を辿って継承を確認する。

落とし穴2: VI/RTのstate は直接 PATCH できない

グループの作成・更新ツールを実装し、書き込み権限ももらって実機で create→update を流したところ、state への更新だけが INSUFFICIENT_PRIVILEGES で弾かれました。フィールド単位で切り分けると:

create                         : OK
update(short_description)      : OK
update(state)                  : FAIL (INSUFFICIENT_PRIVILEGES)
delete                         : OK

さらに VI の deferral 用フィールド(ignore_reason/ignore_date)を直接書いてみると、「受理されるが業務ルールで即時リバート」(state は Open のまま、ignore も空に戻る)。

つまり VR では state は Table API のフィールド書き込みでは動かせない設計です。
state を動かすのはワークフロー(承認)の役割でした。

教訓: VR レコードは「自動化が主導」。state はワークフロー経由でしか動かない。

落とし穴3: 例外承認は sysapproval を埋めない

「state を動かすのは承認」と分かったので、承認(sysapproval_approver)を一覧するツールを作りました。最初は素直に sysapproval.sys_class_name で VR レコード由来の承認を絞り込む実装に。

ところが実機で Exception Request を起票すると 0 件
承認レコードを1件ダンプして気づきました:

sysapproval        : (空)
source_table       : sn_sec_exception_change_approval
document_id        : Change Approval: CA0010004
approval_source    : sn_vul_vulnerability   ← 最終的な VR レコードのクラス

VR の例外承認は sysapproval埋めません
代わりに source_table + document_id で例外レコードに紐づき、approval_source に最終的な VR クラスが入ります。フィルタを source_table ベースに直したら、無事に保留中の承認が取れました。

// 修正後: source_table で VR 由来の承認を絞る
const VR_APPROVAL_CLASSES = [
  'sn_sec_exception_change_approval',
  'sn_vul_vulnerability', 'sn_vul_vulnerable_item', /* ... */
];
query = `source_tableIN${VR_APPROVAL_CLASSES.join(',')}^state=requested`;

そして承認/却下は、検証済みの汎用承認と同じく sysapproval_approver.state を更新するだけ。これがワークフローを進め、結果として VR レコードの state を遷移させます。実機で 承認→state approved→requested に復元 のラウンドトリップまで確認しました。

落とし穴4: 例外申請の本体テーブル

「例外申請テーブルが見当たらない」と一度あきらめていたのですが、False Positive 申請を起票し、承認の document_id を辿ったら見つかりました。
本体は sn_sec_exception_change_approval です。

request_type      : False positive   (他に Exception / Risk Acceptance)
record + table    : Vulnerable Item: VIT0011335
desired_state     : 3 (Closed)
desired_substate  : 22 (False Positive)   ← 承認時の遷移先
approval_state    : 0 (In Review)
desired_reason    : (申請理由)

「どの VI に対する」「何の種類の(誤検知申請/例外リクエスト)」「承認したら何になる」申請なのかが一覧で見えます。
申請の可視化 → 承認の確認 → 承認/却下 → state 遷移

AIに質問してみた例
Screenshot 2026-06-27 at 19.09.57.png

設計上の工夫: レジストリ方式

設定系テーブル(アサインメントルール/修復タスクルール/TTR/承認ルール/自動クローズ/除外ルール)はスキーマもキー項目もバラバラでした。。。。
これを rule_type のレジストリで吸収し、list/get/create/update/set_active の少数ツールで全種を扱えるようにしました。SLA の record_type(vi/rt/vg)も同じ発想です。テーブルが増えてもレジストリに1行足すだけで済みます。

検証とテストの方針

VR は「実機で叩かないと分からない」ことが多すぎたので、全ツールを実 PDIで検証しました。

  • 読み取り: 実データで挙動を確認(NVD ラン、TTR 違反グループ、例外申請など)
  • 書き込み: create→update→get→delete のラウンドトリップを流し、テスト用レコードは必ず削除して残留ゼロを確認
  • クエリ安全性: 未来日付は gs.daysAgo(-N)(allowlist 済み)で注入、source/state 等はサニタイズ

ユニットテストは Vitest でモック化。
USEM 系モジュールは func 100% / stmt ほぼ 100% / branch 85〜95%、リポジトリ全体で 457 テスト が green です。

まとめ

VR/USEM を API から触るときに効く実機知見:

  1. 「Remediation Task」は sn_vul_remediation_task と task 継承の sn_vul_vulnerability の2系統。継承は super_class を辿って確認する
  2. state は直接 PATCH できない。作成/更新後は業務ルールが値を再計算する
  3. 例外承認は sysapprovalカラム ではなく source_table/document_id/approval_source カラムで紐づく
  4. 例外申請の本体は sn_sec_exception_change_approval(request_type / desired_substate を持つ)
0
0
0

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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?