メインコンテンツへスキップ
見出し画像

ServiceNowのAPI呼び出しは誰がいつ叩いたか分かる?syslog_transactionを実機で追う


    外部システムからServiceNowのAPIを呼んだはずなのに、連携先から「反応がない」と言われることがあります。そのとき最初に切り分けるべきは、リクエストが本当にインスタンスまで届いていたかどうかです。ServiceNowでは受信したAPI呼び出しの記録がsyslog_transactionというテーブルに残ります。標準で用意されたScripted REST APIを実際にGETで叩き、認証がある場合とない場合で記録がどう変わるかをZurich PDIで確認しました。設定画面だけを眺めていても、この記録の有無までは分かりません。実際に叩いて、記録が増える瞬間を自分の目で確認しました。

    検証環境:Zurich PDI / OOTB / 2026-08-10 確認

    結論:認証で弾かれると、この環境では記録さえ残らなかった

    先に全体像です。

    • 認証ありでAPIを2回叩くと、syslog_transactionにその2回がそのまま記録されました。response_time・sys_created_by・user_agentまで残ります。

    • 認証なしで叩くと401は返りますが、同じ条件で探してもsyslog_transactionに該当行は見つかりませんでした。System Logのsyslogテーブルにも痕跡はありません。

    • つまり「連携先が叩いたのに反応がない」と言われたとき、syslog_transactionに行が無いことは「届いていない」と「認証で弾かれた」の両方であり得ます。この2つを同じ結果として扱う必要があります。


    画像

    色の意味はそのまま経路の意味です。紺が起点のリクエスト、緑が認証を通過して処理が進んだ経路、水色が記録先のsyslog_transaction、赤が認証で拒否されて記録が残らなかった経路になります。次の章から、この図の中身を1つずつ実機で確かめます。

    対象にしたAPIはOOTBのEncode/Decode Base64

    自作のAPIだと再現性が下がるため、ServiceNowが最初から用意しているScripted REST APIを対象にしました。Omni-Experience Standard Feature Setというアプリケーションに含まれる、Encode/Decode Base64というサービスです。sys_ws_definitionにservice_id=encode_decode_base64、namespace=sn_oe_sfsで登録されており、Base API pathは/api/sn_oe_sfs/encode_decode_base64でした。


    画像

    このサービスにぶら下がるリソースはdecodeBase64という1件だけでした。HTTP methodはGET、Relative pathは/{encodedString}で、requires_authenticationはtrueです。認証が必須のOOTB設定になっている点は、外部公開されるAPIとしてはごく一般的な作りです。実際、このPDIのsys_ws_operation全体でも認証必須が1,226件、匿名許可が33件で、認証必須が大半を占めていました。


    画像

    処理本体のoperation_scriptを開くと、渡された文字列をbase64デコードしたうえでJSON.parseに通し、その結果をそのまま返すだけの短いスクリプトでした。ここで気をつけたいのは、渡す文字列が単なる平文のbase64ではなく、base64化した後の中身がJSONとして解釈できる値でなければならない点です。今回はJSON文字列"ServiceNow REST call trace test"をbase64化して渡しました。

    なお画面には注意バナーも出ていました。「このレコードはOmni-Experience Standard Feature Setアプリケーションに属しているが、現在の作業スコープはGlobalである」という趣旨の内容です。OOTBのScripted REST APIは提供元のアプリケーションスコープに属していて、Global側から不用意に編集できない作りになっています。Protection policyもRead-onlyでした。標準機能をうっかり壊さないための2重の歯止めが、フォームを開いただけで見て取れます。

    認証を通っても、まだACLと内部ロールの壁がある

    requires_authenticationだけを見ていましたが、同じフォームにはrequires_acl_authorization(true)とrequires_snc_internal_role(true)というフラグもあり、enforce_aclには「Omni - REST Endpoint ACL」という個別のACLが設定されていました。つまり実際の入口は3段構えです。まずBasic認証などで「誰であるか」を確認し、次にACLと内部ロールで「その操作をしてよいか」を確認し、その両方を通って初めてoperation_scriptが動きます。

    今回試したのは1段目の認証だけです。正しい資格情報を持つが、必要なロールが無いユーザーで叩いた場合にどう記録されるかは確認していません。401とは違う応答(403系)になる可能性が高く、syslog_transactionへの記録のされ方も変わるかもしれませんが、ここは推測にとどめ、検証範囲外として扱います。

    実際に投げたリクエストと返ってきた結果

    対象のURLに対して、認証情報を付けてGETを投げると次のように返ってきます。

    GET /api/sn_oe_sfs/encode_decode_base64/IlNlcnZpY2VOb3cgUkVTVCBjYWxsIHRyYWNlIHRlc3Qi
    Authorization: Basic <連携用ユーザーの資格情報>
    
    HTTP/1.1 200 OK
    {"result":"ServiceNow REST call trace test"}

    base64をデコードしてJSONとして解釈し、渡した文字列がそのままresultに返ってきました。これで対象のAPIが正しく動くことは確認できたので、ここから本題の「呼び出した記録がどこに残るか」に入ります。

    認証ありで叩くと、syslog_transactionに1件残る

    上のリクエストを認証ありで2回実行したあと、syslog_transactionを対象APIのURLで絞り込みました。テスト開始前は該当する行が0件でしたが、2回実行した後は過不足なく2件になりました。呼び出した回数と記録された件数が一致しています。


    画像


    画像

    記録された中身は何を教えてくれるか

    1件のレコードを開くと、次のような値が入っていました。

    • response_time:57〜58ミリ秒。処理そのものは短時間で終わっています。

    • sys_created_by:admin。認証に使った資格情報に対応するユーザーがそのまま記録されます。

    • session:呼び出しごとに異なる値。同じユーザーでも、1回のAPI呼び出しは別々のセッションとして扱われていました。

    • user_agent:呼び出しに使ったHTTPクライアントの識別文字列がそのまま記録されます。連携先が想定どおりのツールで叩いているかを確認する手がかりになります。

    • sql_count・sql_time:この呼び出しで実行されたSQLの本数と所要時間も一緒に記録されていました。応答が遅い場合の切り分けに使えそうな項目です。

    remote_ipという列に発信元のIPアドレスも入っていましたが、実際の値はこの記事では伏せます。個人の接続元がそのまま残る点は、連携元を特定する材料になると同時に、画面を人に見せるときは注意が必要な項目だと分かりました。

    ほかにも記録されている項目

    フィールドをひととおり眺めると、origin_scope(Origin Application)という列に「Omni-Experience Standard Feature Set」という値が入っていました。これは呼び出し元のアプリケーションを示す値ではなさそうです。実際に動いたoperation_scriptが属するアプリケーションスコープを表していると考えられます。複数の業務アプリが似た名前のAPIを公開しているような環境では、どのアプリのコードが実行されたのかを見分ける手がかりになりそうです。

    parentとinteraction_idという列も存在しますが、今回の2件はどちらも空でした。単発のREST呼び出しでは使われず、複数のトランザクションが連鎖する処理や、会話単位でまとめる用途のフィールドだと推測します。この2つの実際の使われ方までは確認していません。

    statusもuserも無い、syslog_transactionに無い情報

    記録された値を見ていく中で、意外なことに気づきました。syslog_transactionのフィールド定義を確認すると、HTTPステータスコードを表すstatusのような列も、呼び出しユーザーを参照で持つuserのような列も存在しませんでした。


    画像

    固有フィールドは59件ありましたが、その中で「誰が」に一番近いのは文字列型のsys_created_byだけです。「何が返ったか」を表す列は最初から用意されていません。syslog_transactionに行があることは「リクエストが処理された」ことの証拠にはなります。ですが「200で返ったのか、それとも処理の途中でエラーになったのか」までは、このテーブル単体では判断できません。

    認証なしで叩くと401は返るが、記録は残らない

    同じURLに対して、今度は認証情報を付けずにGETを投げました。

    GET /api/sn_oe_sfs/encode_decode_base64/IlNlcnZpY2VOb3cgUkVTVCBjYWxsIHRyYWNlIHRlc3Qi
    
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Basic realm="Service-now"
    {"error":{"message":"User is not authenticated","detail":"Required to provide Auth information"},"status":"failure"}

    401が返り、WWW-Authenticateヘッダも付いています。ここまではよくあるAPIの動きです。問題はこの後でした。同じ条件でsyslog_transactionを検索しても、この呼び出しに対応する行が見つかりません。呼び出し前後の時間帯を条件を緩めて広く検索しても、該当する行は出てきませんでした。念のためSystem Logのsyslogテーブルも同じ時間帯で調べましたが、こちらも該当するメッセージは0件です。

    なぜ記録されないのかは推測になりますが、syslog_transactionへの書き込みはoperation_scriptの実行を含むトランザクション処理の一部として行われ、認証チェックはその手前の層で完結しているのではないかと考えています。認証で弾かれた時点でトランザクション処理そのものに入っていなければ、記録する主体が動く前に処理が終わっている計算になります。あくまで挙動から逆算した推測であり、ServiceNow側の実装を確認したわけではありません。

    この結果から言えることは限定的です。この認証方式・このPDIの範囲では、Basic認証なしで拒否されたリクエストはsyslog_transactionにもsyslogにも痕跡が残りませんでした。読み取り専用のAPIで調べられる範囲はここまでで、ロードバランサやWAFなどネットワーク層のログはPDIの外側にあるため確認していません。これ以上の追跡は、今回の検証範囲を超えます。

    連携先から「叩いたのに反応がない」と言われたときの切り分け手順

    ここまでの結果を、実際に問い合わせを受けたときの手順に落とし込みます。順番が重要です。

    1. まずsyslog_transactionを対象URLで絞り込みます。 行が見つかれば、その時刻にインスタンスまで到達し処理されたことになります。認証の成否に関わらず、届いた事実そのものはここで確認できます。

    2. 行が1件も無ければ、原因を1つに決めつけません。 認証で弾かれた可能性と、そもそも届いていない可能性の両方が残ります。この環境ではここから先を区別する材料が見つかりませんでした。

    3. 行が見つかった場合はresponse_timeとsys_created_byを見ます。 想定した連携用ユーザーで実行され、処理時間が極端に長くなければ、認証・実行の両方が正常に進んでいると判断できます。

    4. それでも連携先が結果を受け取れていないなら、スクリプト側の応答内容を疑います。 syslog_transactionは「処理されたこと」までは教えてくれますが、「何を返したか」は別に確認する必要があります。


    画像

    この順番を守る理由は単純です。syslog_transactionを先に見れば、数十秒で「届いたかどうか」だけは切り分けられます。今回の検証でも、認証ありの2回はどちらも57〜58ミリ秒という短時間で処理が終わっており、行が見つかった時点で「認証・実行のどちらにも問題は無い」とすぐ判断できました。逆に定義(sys_ws_definitionやsys_ws_operation)から先に確認してしまうと、設定を1つずつ読み解く作業が先に立ち、肝心の「今回の呼び出しはどうだったのか」に辿り着くまで時間がかかります。困りごとを聞いたら、まず記録の有無を確認し、それから定義に読み進める順番を崩さないようにしています。

    実務では何に使えるか:連携の一次切り分けに使う

    本番で「連携が動いていない」という連絡を受けたとき、いきなり開発チームやネットワーク担当を巻き込む前に、syslog_transactionをURLで絞り込む作業だけなら数分で終わります。行が見つかれば、少なくともインスタンス側の受け口までは正常です。問題の所在を「ネットワークや認証」と「アプリ側の処理」のどちらかに絞れるだけでも、次に連絡する相手が変わります。

    user_agentも地味に役立ちます。連携先が「決められたツールで叩いている」と申告していても、実際に記録されたuser_agentが別のツールを示していれば、テスト環境と本番環境を取り違えているような初歩的な行き違いに早く気づけます。数字を集計するための項目ではなく、目の前の1件を確認するための項目として使うのが実務での使い方です。

    もう1つ、認証・ACL・内部ロールという3段構えの入口を持つAPIでは、「連携先のユーザーに正しいロールを付けたか」も確認項目に加える必要があります。パスワードやトークンが合っていても、ロールが不足していれば別の理由で弾かれます。syslog_transactionに行が無いという同じ症状でも、原因の候補が1つ増えることになるので、連携用ユーザーを新しく発行するときはロールの割り当てまで込みで手順書に残しておくと、後から見返す担当者が迷いません。

    実機で気づいたこと

    一番の発見は、認証エラーが記録に残らなかったことです。ログを見れば何でも追えると思い込んでいましたが、認証の手前で弾かれたリクエストは、読み取り専用のAPIで見える範囲には何も残っていません。障害調査で「ログに無い」を「発生していない」と即断しないほうがよいと、身をもって分かりました。件数を集計するだけの調査では見落としがちな、「無いこと」自体が持つ意味の重さを実感しています。

    スクリプトを読むまでは、単純な文字列をbase64化するだけで動くAPIだと思っていました。実際にはJSON.parseを経由する作りだったので、渡す文字列はbase64にする前の時点でJSONとして正しい値である必要があります。動かなかったときにまずbase64の変換ミスを疑いがちですが、この作りを知っていれば元の値がJSONとして妥当かを先に確認できます。

    もう1つ、調査の途中で自分自身が仕掛けた罠にはまりました。syslog_transactionをurlLIKEで絞り込む確認クエリを投げたところ、そのクエリ文字列自体に対象APIの名前を含んでいたため、確認クエリ自身が検索結果に紛れ込んだのです。urlSTARTSWITHに条件を変えて解決しましたが、ログを検索する行為そのものがログに記録される環境では、絞り込み条件の書き方ひとつで数字が変わります。

    認証の入口は1段だけだと思い込んでいましたが、実際には認証・ACL・内部ロールの3段だったことも、フォームを開いて初めて気づきました。requires_authenticationだけをチェックしていれば安全だと考えがちですが、実際にはenforce_aclで個別のACLまで指定されています。外部公開するAPIを自分で作るときも、この3段のうちどこまでを意識して設計したかを、あとから見返せるようにしておく必要があると感じました。

    よくある質問

    Q1. 認証なし(401)の呼び出しは本当にどこにも記録されないのですか

    今回確認できた範囲では、syslog_transactionとsyslogのどちらにも見つかりませんでした。ネットワーク層やロードバランサ、WAFのログはPDIのAPIから見える範囲の外なので確認していません。少なくともインスタンス内の読み取り専用APIで追えるテーブルには残らないという事実だけは確認できています。

    Q2. sys_created_byを「呼び出したユーザー」として信頼してよいですか

    Basic認証で認証に成功した場合は、その資格情報に対応するユーザーがそのまま入りました。OAuthなど他の認証方式でも同じ挙動になるかは確認していません。連携用に専用ユーザーを分けておくと、この列だけで呼び出し元をすぐ判別できるようになります。逆に、複数の連携先が同じ共有アカウントを使っている場合は、sys_created_byだけでは呼び出し元を1つに絞り込めません。remote_ipやuser_agentもあわせて見る必要が出てきます。

    Q3. response_timeが遅いときは、原因をどこで見分けますか

    同じレコードのsql_countとsql_timeを見ると、DB処理にどれだけ時間を使ったかが分かります。sql_timeがresponse_timeの大半を占めていればデータ処理側、差が大きければ別の処理に時間がかかっている可能性を疑えます。今回のテストでは応答が57〜58ミリ秒と短く、この切り分けが必要になる場面ではありませんでした。

    Q4. GET以外のメソッドでも同じように痕跡を追えますか

    今回はPDIのデータを変更しない方針だったため、読み取り専用のGETだけを確認しました。POSTなど書き込み系のメソッドでも同じsyslog_transactionに記録される作りだと考えられますが、実際に試したわけではないので断定はできません。書き込みを伴う検証をする場合は、本番相当のデータに影響しない検証用インスタンスで行うことをおすすめします。

    Q5. 正しい認証情報なのに403のような別のエラーが返ってきたらどう考えますか

    今回の対象APIはrequires_acl_authorizationとrequires_snc_internal_roleも有効になっており、認証を通過した後にACLと内部ロールのチェックが控えています。401(認証エラー)と403のような認可エラーは別の層で起きるため、まずどちらのステータスコードが返っているかを連携先に確認します。認可エラー側の記録のされ方は今回確認していないので、この記事の範囲では「認証は通っている可能性が高い」という手がかりにとどめ、断定はしません。

    関連記事

    公式ドキュメントでは、次のあたりが今回の内容に関係します。

    用語

    • PDI:Personal Developer Instance(無料の検証用インスタンス)

    • OOTB:Out of the Box(初期設定のまま)

    • Scripted REST API:開発者が定義する独自のRESTエンドポイント(Service+Resource)

    • syslog_transaction:ServiceNowが処理したトランザクションの記録テーブル。画面上の表示名はTransaction Log

    • Basic認証:ユーザー名とパスワードをそのままヘッダに載せる認証方式

    自分の環境で確認するときのURL

    先頭に自分のインスタンスを付けると、同じ画面が開けます。

    対象サービス      : sys_ws_definition_list.do?sysparm_query=service_idLIKEbase64
    対象リソース      : sys_ws_operation_list.do?sysparm_query=nameLIKEdecodeBase64
    Transaction Log一覧 : syslog_transaction_list.do?sysparm_query=type=REST^ORDERBYDESCsys_created_on
    フィールド一覧    : sys_dictionary_list.do?sysparm_query=name=syslog_transaction^elementISNOTEMPTY

    検証範囲とおことわり

    確認したこと:

    • 対象のScripted REST API(Encode/Decode Base64/decodeBase64)の定義とスクリプト内容、および認証・ACL・内部ロールという3段の権限設定

    • 認証あり・認証なしそれぞれの実際の呼び出し結果(ステータスコード・レスポンスボディ・ヘッダ)

    • syslog_transactionの呼び出し前後の件数変化と、認証成功時に記録される具体的なフィールド値

    • 認証失敗(401)時にsyslog_transactionとsyslogのいずれにも痕跡が見つからなかったこと

    • syslog_transactionのフィールド定義にstatusとuserの列が無いこと

    確認していない範囲(断定しません):

    • 認証は通るがACL・内部ロールで弾かれた場合の応答内容と記録のされ方

    • OAuthなど他の認証方式での挙動

    • ロードバランサ・WAF・ネットワーク層のログ

    • レート制限にかかった場合の記録先や、401以外のエラー(500系・タイムアウトなど)が発生した場合の記録のされ方

    • 本番相当の高トラフィック環境でのログ保持期間

    件数はすべて確認した時点のものです。PDIは操作していない間も動き続けているため、今見ると数字は変わっている可能性があります。

     
     
    ServiceNowのPDI(Personal Developer Instance)を実機で観察して、Noteに記事を書いています 実装・運用・教育の現場視点で淡々と記録中です リクエストがあればその記事も書きます 個人の観察日記です

    あなたへのおすすめ