REST APIで認証情報をローテーション

Keeper Secrets ManagerでREST APIを使用するクラウドベースのアカウントを自動的にローテーション

概要

本ページでは、「NOOP モード」を使用してクラウドベースのアプリケーションまたはAPIエンドポイントとPAMゲートウェイでパスワードローテーションを設定する方法を解説します。Keeperの記録に設定されたフラグで、ゲートウェイにプライマリローテーション方法をスキップして、ポストローテーションスクリプトを直接実行するように指示します。

本ガイドには、前提条件、手順、Pythonスクリプトの例を含めました。

前提条件

  1. KSMアプリケーション: Keeper Secrets Manager (KSM) アプリケーションがセットアップされていることを確かにします。

  2. 共有フォルダ: 共有フォルダが設定されていて、そこにすべての記録が保存されている必要があります。

  3. PAM設定: PAMがセットアップされていること、およびゲートウェイが実行中であり、この設定に接続されていることを確かにします。

  4. REST APIトークン: APIとのやりとりにAPIトークンが必要となります。

手順 1: REST APIトークンまたはアクセストークンを取得

  1. 対象のアプリケーションやサービスの手順に従ってAPIトークンを生成します。

  2. この APIトークンをKeeperの記録に保存します。記録タイプは任意のタイプを選択できますが、この例では「ログイン」タイプを使用します。

    • APIトークンを「パスワード」フィールドに保存します。

    • 組織のURL をウェブサイトのアドレス」フィールドに保存します。

  3. この記録に「API Access Details」という名前を付けます。この名前は、後でスクリプトで記録を取得するために使用されます。

手順 2: ローテーション記録を設定

新しいPAMユーザー記録を作成して、パスワードをローテーションの対象ユーザーの詳細を保存します。

  • ユーザーのログインIDと一致するようにユーザー名を設定します。

  • パスワードをユーザーに設定されている現在のパスワードに設定します (RESTエンドポイントによります)。

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

  1. パスワードのローテーションを実行する下のPythonスクリプトを添付します。スクリプトの各行にはコメントが含まれています。

  2. 「ローテーションクレデンシャル」の記録 (手順 1で作成したAPIトークンとURLを含む記録) を追加します。

  3. ノーオペレーション (NOOP) アトミック実行を有効にします。

    • ユーザーの詳細が保存されている現在のPAMユーザー記録に、NOOPというラベルの新しいカスタムフィールドを作成し、その値をTrueに設定します。

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

  1. ローテーションタイプ: この例では「オンデマンド」に設定します。

  2. パスワードの複雑さ: 特別な要件がない限り、デフォルトのままにしておきます。

  3. ローテーション設定: 前に設定した PAM設定にします。

  4. 管理資格情報記録: 空のままにしておく必要があります。

Step 5: Python環境の設定

以下は、Keeper Gateway が実行されている環境での手順となります。

  1. Python環境に必要な依存関係を満たすようすべてインストールされていることを確かにしてください。

  2. 仮想環境を使用する場合は、スクリプトの先頭にシバン行を追加します。

シバン行にスペースが含まれていないようにしてください。スペースが存在する場合は、スペースを含まないシンボリックリンクを作成してください。

以下は、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のシバン行の既知の制限であり、スペースを含まないパスに 
#     Pythonインタープリタへのシンボリックリンクを作成する必要があります。
#     例: sudo ln -s "/usr/local/bin/my python3.11" /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}")

# リクエストライブラリをインポート
try:
    import requests
except ImportError:
    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

# stdinから入力パラメータを読み取り、デコードします
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 Scriptの箇所で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')

# 記録から詳細を抽出
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):
    """
    Rotate the password for a given user.

    Args:
    - user_email (str): The email of the user for whom the password should be rotated.
    - new_password (str): The new password.

    Returns:
    - dict: The response from the API call.
    """

    # Headers for the request
    headers = {
        "Content-Type": "application/json",
        "Authorization": f"Bearer {service_access_token}"
    }

    # Prepare the request payload
    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__':
    """Main function to execute the password rotation."""

    response = rotate(user_email, new_password)

    # デバッグ用に応答を表示
    print(f"# \n# Response from the API:")
    print(f"# {response}")

最終更新