REST APIを使用した認証情報のローテーション

概要

本ページでは、KeeperPAMのローテーションオプション「PAMスクリプトのみ実行」を使用して、REST APIを通じたパスワードローテーションを設定するための一般的な手順について取り扱います。この設定は、PAMユーザーレコードのローテーション設定において、メインのローテーション方法をスキップし、ボルトに添付されたスクリプト (ポストローテーションスクリプト) のみを直接実行させるものです。

本ページの最後にはPythonスクリプトのサンプルが含まれます。

要件

  • KSMアプリケーション: Keeperシークレットマネージャー (KSM) のアプリケーションが設定済みであること

  • 共有フォルダ: 関連するレコードを格納するための共有フォルダが作成されていること

  • PAM構成: PAM構成が設定済みで、対応するゲートウェイが稼働中であること

  • REST APIトークン: 任意のAPIと連携するために必要なアクセストークンを取得していること

手順 1: REST APIトークンの取得

  • 対象のアプリケーションまたはサービスで、APIトークンを生成します

  • Keeperボルトにレコードを作成し、このトークンを保存します

    • レコードタイプは「ログイン」を使用 (任意のタイプでも可)

    • APIトークンは「パスワード」欄に保存

    • 組織のURLは「ウェブサイトアドレス」欄に入力

    • レコード名は 「API Access Details」 に設定 (スクリプト内で参照します)

手順 2: ローテーション対象ユーザーのPAMユーザーレコード作成

  • 新たにPAMユーザーレコードを作成し、対象ユーザーの情報を保存します

    • ユーザー名にはログインIDを入力

    • パスワード欄には現在のパスワードを設定 (エンドポイント仕様による)

手順 3: PAMスクリプトの追加

  • 以下のPythonスクリプトをレコードに添付します (スクリプト内には各行の解説付き)

  • スクリプト内で使用する「認証情報レコード」として、手順 1で作成した「API Access Details」レコードを指定

  • PAMユーザーレコードにカスタムテキストフィールド「NOOP」を追加し、値をTrueに設定 (NOOP=スクリプトのみ実行)

手順 4: パスワードローテーション設定

  • ローテーションタイプ: 「オンデマンド」を選択 (例として)

  • パスワードの複雑さ: 特に要件がなければデフォルトのまま

  • ローテーション設定: 先に作成したPAM構成を指定

  • 管理者認証情報レコード: 空欄のままでOK

手順 5: Python実行環境の準備

  • Keeperゲートウェイが動作している環境で、Python環境と依存パッケージがインストールされていることを確認

  • 仮想環境を使用する場合は、スクリプト冒頭にshebang行を追加

  • 注意: shebang行にスペースがあると動作しないため、スペースなしのシンボリックリンクを作成してください。以下はLinuxでのシンボリックリンク作成の例です。

    sudo ln -s "/Users/john/PAM Rotation Example/.venv/bin/python3" /usr/local/bin/pam_rotation_venv_python3

Pythonスクリプトについて

このPythonスクリプトは、ベストプラクティスに従って作成されており、以下の処理を行います。

  • 必要なモジュールのインポート

  • 変数の初期化

  • 任意のREST APIを呼び出してパスワード変更を実行するローテーション関数の定義

#!/usr/local/bin/pam_rotation_venv_python3

# 注意: Pythonインタープリタへのパスにスペースが含まれている場合、このスクリプトは実行できません。
#       これはLinuxにおけるshebang行の既知の制限であり、スペースを含まないパスに
#       Pythonインタープリタへのシンボリックリンクを作成する必要があります。
#       例: sudo ln -s "/usr/local/bin/my python3.7" /usr/local/bin/pam_rotation_venv_python3

# 注意: このスクリプトは、REST APIを使用したパスワードローテーションのデモです。
#       実際のAPIを呼び出すものではありません。ご自身のAPIに合わせてスクリプトを修正してください。

import asyncio
import sys
import base64
import json

# デバッグ用にPythonのバージョンを表示
print(f"# Python version: {sys.version}")

# デバッグ用にインストール済みパッケージを表示(必要に応じてコメントを外してください)
# import pkg_resources
# print("# \n# Installed packages for debugging:")
# installed_packages = pkg_resources.working_set
# installed_packages_list = sorted(["%s==%s" % (i.key, i.version) for i in installed_packages])
# for m in installed_packages_list:
#     print(f"  {m}")

# requestsライブラリをインポート
try:
    import requests
except ImportError:
    # 'requests'パッケージがインストールされていない場合のエラーメッセージ
    print("# Error: The 'requests' package is not installed. Run 'pip install requests' to install it.")
    exit(1)

# 変数の初期化
api_access_token_title = 'Record with Access Token'
api_access_token_record = None
params = None

# 標準入力から渡されたパラメータを読み取り、デコード
for base64_params in sys.stdin:
    params = json.loads(base64.b64decode(base64_params).decode())

    # デバッグ用に利用可能なパラメータを表示(必要に応じてコメントを外してください)
    # print(f"# \n# Available params for the script:")
    # for key, value in params.items():
    #     print(f"#     {key}={value}")

    # PAMスクリプトの「ローテーションクレデンシャル」レコードとして渡された
    # JSON文字列形式のレコード情報をデコードして読み込む
    records = json.loads(base64.b64decode(params.get('records')).decode())

    # タイトルからアクセストークンを含むレコードを探す
    api_access_token_record = next(
        (record for record in records if record['title'] == api_access_token_title), None)
    break

if api_access_token_record is None:
    # アクセストークンを含むレコードが見つからない場合のエラー
    print(f"# Error: No Record with the access token found. Title: {api_access_token_title}")
    exit(1)

# レコードから詳細情報を抽出
rest_api_service_url = api_access_token_record.get('url')
service_access_token = api_access_token_record.get('password')

# old_password = params.get('oldPassword')  # 以前のパスワードを使用したい場合はこちらを使用
new_password = params.get('newPassword')
user_email = params.get('user')             # パスワードをローテーションする対象ユーザーのメールアドレス

def rotate(user_email, new_password):
    """
    指定されたユーザーのパスワードをローテーションします。

    引数:
    - user_email (str): パスワードをローテーションする対象ユーザーのメールアドレス
    - new_password (str): 新しいパスワード

    戻り値:
    - dict: APIからのレスポンス
    """

    # リクエストのヘッダー
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {service_access_token}"
    }

    # リクエストのペイロードを準備
    request_payload = {
        "userEmail": user_email,
        "newPassword": new_password,
    }

    # APIにPOSTリクエストを送信
    response = requests.post(url=rest_api_service_url, headers=headers, data=json.dumps(request_payload))

    # リクエストが成功したかを確認
    if response.status_code == 201:
        return response.json()
    else:
        response.raise_for_status()

if __name__ == '__main__':
    """パスワードローテーションを実行するメイン関数"""

    response = rotate(user_email, new_password)

    # デバッグ用にAPIのレスポンスを表示
    print(f"# \n# Response from the API:")
    print(f"# {response}")

最終更新