2
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?

PythonからServiceNowにアクセスする際、MFAを乗り越える方法

2
Last updated at Posted at 2025-12-30

はじめに

ServiceNowのインシデント情報をREST APIで取得したいものの、環境によってはログイン時にMFA(TOTP)が必須になっていて、単純なBasic認証だけでは弾かれることがあります。

本記事では、Basic認証のパスワード部分に パスワード + TOTP(6桁) を連結する方式で、Pythonからインシデント一覧を取得するサンプルを紹介します。
(※この方式が使えるかどうかは、組織のSSO/MFA設定・認証方式に依存します)

 
以下のような場合に活用できます。

  • ServiceNowのREST API(Table API)をPythonで叩きたい
  • MFA(TOTP)が必須の環境で、スクリプトからの呼び出しに困っている
  • 「パスワード+ワンタイムコード」を同時入力するタイプの認証を自動化したい

前提・注意事項(重要)

  • TOTPシークレット(共有鍵)は漏洩厳禁です。流出するとMFAを生成できてしまいます。
  • 会社/組織のルールによっては、MFAの自動化そのものが禁止の場合があります。公開・運用前に必ず確認してください。
  • 本記事は「技術的にこうすれば動くケースがある」という紹介であり、セキュリティ上の責任は各自でご対処願います。

やりたいこと

  1. PythonでTOTP(6桁)を生成
  2. パスワード + TOTP(6桁) を作る
  3. ServiceNowのTable API(incident)をBasic認証で呼び出す
  4. インシデント番号・件名・作成日時を表示する

使うもの

  • Python 3.x
  • ライブラリ
    • requests
    • pyotp

インストール:

pip install requests pyotp

環境変数の用意(取扱注意)

記事では伏せていますが、実運用では以下のように環境変数で渡します。サンプルのコードで直接書いて試すことはできますが、業務で使う場合は別ファイルで機密情報として扱ってください。

export SN_INSTANCE_URL="https://<your-instance>.service-now.com"
export SN_USERNAME="<your-username>"
export SN_PASSWORD="<your-password>"
export SN_TOTP_SECRET="<your-totp-secret-without-spaces>"

TOTPシークレットについて

Authenticatorアプリ等で表示されるシークレットにスペースが含まれている場合は、pyotpに渡す前にスペースを除去した文字列を使います。

ServiceNowの場合、MFA初回登録の際にQRコードの下段に


実装例(インシデント一覧を取得)

ポイントはここです:

  • pyotp.TOTP(TOTP_SECRET).now()現在時刻のワンタイムコードを作る
  • PASSWORD と結合して combined_password を作る
  • Basic認証のパスワードとして (USERNAME, combined_password) を渡す
import os
import requests
import pyotp

# ====== 設定(Qiita掲載向け:環境変数から取得) ======
INSTANCE_URL = os.getenv("SN_INSTANCE_URL", "https://<your-instance>.service-now.com")
USERNAME = os.getenv("SN_USERNAME", "<your-username>")
PASSWORD = os.getenv("SN_PASSWORD", "<your-password>")
TOTP_SECRET = os.getenv("SN_TOTP_SECRET", "<your-totp-secret-without-spaces>")


def build_combined_password() -> str:
    """PASSWORD + TOTP(6桁) を結合したパスワードを生成"""
    totp = pyotp.TOTP(TOTP_SECRET)
    mfa_code = totp.now()

    # MFAコードはログに出すと危険なので、基本は出さない
    # print(f"[DEBUG] MFA code: {mfa_code}")

    return f"{PASSWORD}{mfa_code}"


def fetch_incidents(limit: int = 10) -> None:
    """インシデントを一覧取得して表示"""
    combined_password = build_combined_password()
    api_url = f"{INSTANCE_URL}/api/now/table/incident"

    params = {
        "sysparm_limit": limit,
        "sysparm_fields": "number,short_description,sys_created_on",
    }

    # Basic Auth(ユーザー名 / パスワード+MFAコード)
    auth = (USERNAME, combined_password)

    headers = {"Accept": "application/json"}

    response = requests.get(
        api_url,
        auth=auth,
        headers=headers,
        params=params,
        timeout=30,
    )

    if response.status_code == 200:
        data = response.json()
        records = data.get("result", [])
        print(f"[+] 取得件数: {len(records)}")
        print("-" * 60)
        for r in records:
            print(f"{r.get('number')}{r.get('short_description')} ({r.get('sys_created_on')})")
    else:
        print("[!] Error:", response.status_code)
        print(response.text)


if __name__ == "__main__":
    fetch_incidents(limit=10)

実行結果例(イメージ)

[+] 取得件数: 10
------------------------------------------------------------
INC0012345 — VPNに接続できない (2025-01-01 10:00:00)
INC0012346 — メール送信が遅い (2025-01-01 10:05:00)
...

仕組みの補足(認証フローのイメージ)

「ログイン画面でパスワードとワンタイムコードを同じ入力欄に入れる」運用のAPI版、という理解です。


ハマりどころ

1) 時刻ズレでTOTPが合わない

TOTPは時刻依存なので、実行環境の時計がズレると失敗します。
まずはNTP等で時刻同期を確認します。

2) TOTPシークレットの形式

シークレットにスペースが入っている/改行が混ざる等で失敗することがあります。
スペース除去、余計な文字が入っていないかを確認します。

3) 組織設定により、この方式がそもそも通らない

環境によっては、Basic認証ではなくOAuth/SSO専用、あるいはMFAが別チャネル扱いで「パスワード連結」では通らない場合もあります。


セキュリティ上の注意(再掲)

  • TOTP_SECRETをGitに入れない
  • MFAコードをログに出さない
  • 可能なら Secret Manager / Vault / CIのシークレット機能を使う
  • 運用ルール・監査要件に従う

まとめ

  • pyotpでTOTP(ワンタイムコード)を生成し、パスワード + TOTPとしてBasic認証に渡すことで、MFAQ環境でもAPI取得ができるケースがあります
  • 記事化する際は、秘密情報を直書きしないログに出さないが重要です

難しい外部連携をするより、自分のコードでレコード情報を一括でエクスポートできるため、業務効率の向上に貢献できると思います。

以上です

2
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
2
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?