> For the complete documentation index, see [llms.txt](https://docs.keeper.io/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.keeper.io/keeperpam/jp/privileged-access-manager/password-rotation/rotation-use-cases/saas-account/cisco-meraki.md).

# Cisco Meraki

## 概要 <a href="#overview" id="overview"></a>

本ページでは、Cisco Merakiダッシュボードユーザーの認証情報をポストローテーションスクリプトでローテーションする手順を取り扱います。

組み込みのSaaSローテーションを利用する場合は、[SaaSプラグイン](/keeperpam/jp/privileged-access-manager/password-rotation/rotation-use-cases/saas-plugins.md)をご参照ください。

## 要件 <a href="#prerequisites" id="prerequisites"></a>

以下がすでに完了していることを前提としています。

* Keeperシークレットマネージャーアプリケーションが設定されていること
* 関連レコードを格納する共有フォルダが作成されていること
* PAM構成が設定済みで、ゲートウェイが稼働中であること
* Python環境に `requests` ライブラリがインストールされていること (`pip install requests`)

## 1. Cisco Meraki認証レコードの作成 <a href="#id-1-create-the-cisco-meraki-authentication-record" id="id-1-create-the-cisco-meraki-authentication-record"></a>

Meraki APIキーとネットワークIDを保存するPAMユーザーレコードを作成します。レコードタイトルは `Cisco Authentication Record` とします。

* **パスワード** フィールドにMeraki APIキーを保存
* カスタムフィールド `network_id` にネットワークIDを設定 (例: `13.0.0.1`)

## 2. 対象ユーザーのレコード作成 <a href="#id-2-create-the-target-user-record" id="id-2-create-the-target-user-record"></a>

ローテーション対象のMerakiユーザー用に2つ目のPAMユーザーレコードを作成します。

* **ログイン** に対象ユーザーのメールアドレスを設定
* **パスワード** に現在のパスワードを設定

## 3. ローテーション設定の構成 <a href="#id-3-configure-rotation-settings" id="id-3-configure-rotation-settings"></a>

**\[ローテーション設定]** で **\[セットアップ]** を開き、以下を設定します。

* **\[ローテーションプロファイル]:** **\[PAMスクリプトのみを実行する]**
* **\[PAMリソース]:** ゲートウェイに対応するPAM構成
* **\[アップデート]** で保存

## 4. ポストローテーションスクリプトのアップロード <a href="#id-4-upload-the-post-rotation-script" id="id-4-upload-the-post-rotation-script"></a>

**\[PAMスクリプト]** で **\[PAMスクリプトを追加]** をクリックし、以下のスクリプトを添付します。

* **\[ローテーションクレデンシャル]** に、手順1の `Cisco Authentication Record` を指定

### Pythonスクリプト <a href="#python-script" id="python-script"></a>

以下は、Cisco Merakiユーザーの認証情報をローテーションするPAMスクリプトです。

{% code overflow="wrap" %}

```python
'''
Cisco Merakiユーザーアカウントのパスワードローテーションスクリプト

このスクリプトで、指定されたCisco Merakiユーザーのパスワードをローテーションします。

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

import sys
import base64
import json
import urllib3
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
'''
Optionally display installed packages for debugging. Uncomment if needed.
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:
    print("# Error: The 'requests' package is not installed. Run 'pip install requests' to install it.")
    exit(1)

def fetch_meraki_user_by_email(api_key, network_id, email):
    """
    Fetches User details by email.
    
    Args:
    - api_key (str): The Meraki API key.
    - network_id (str): The network ID to search within.
    - email (str): The email of the user to fetch.
    
    Returns:
    - User details if found, otherwise None.
    """
    if not network_id:
        print("Invalid network ID.")
        return None

    # Merakiダッシュボードユーザーを取得するためのURL
    users_url = f"https://api.meraki.com/api/v1/networks/{network_id}/merakiAuthUsers"
    headers = {
        'X-Cisco-Meraki-API-Key': api_key,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    try:
        # ユーザーを取得するためのGETリクエストを送信します。
        response = requests.get(users_url, headers=headers)
        response.raise_for_status()
        # Parse response JSON
        users = response.json()

        if users:
            for user in users:
                if user['email'] == email:
                    print("\nUser found for the email-", email)
                    return user
        return None

    except requests.exceptions.RequestException as e:
        print(f"Error fetching Meraki dashboard users: {e}")
        return None

def update_meraki_user_password(api_key, network_id, user_id, new_password):
    """
    Updates the password for a Meraki dashboard user.
    
    Args:
    - api_key (str): The Meraki API key.
    - network_id (str): The network ID the user belongs to.
    - user_id (str): The ID of the user to update.
    - new_password (str): The new password to set.
    
    Returns:
    - bool: True if successful, otherwise False.
    """
    if not network_id:
        print("Invalid network ID.")
        return False

    # 特定のユーザーのパスワードを更新するためのURL
    user_url = f"https://api.meraki.com/api/v1/networks/{network_id}/merakiAuthUsers/{user_id}"
    headers = {
        'X-Cisco-Meraki-API-Key': api_key,
        'Content-Type': 'application/json',
        'Accept': 'application/json'
    }

    payload = {'password': new_password}

    # ユーザーのパスワードを更新するためのPUTリクエストを送信します。
    response = requests.put(user_url, headers=headers, json=payload)
    
    return response

def rotate(meraki_network_id, meraki_api_key, meraki_user_email, new_password):
    """
    Rotate the password for a given Cisco user.
    Args:
    - meraki_network_id (str): Network ID of the network where the user is located.
    - meraki_api_key (str): API access key for authorization.
    - meraki_user_email (str): Email of the user whose password needs to be rotated.
    - new_password (str): The new password to be set for the Cisco user.
    Returns:
    - None
    """
    
    # 関数fetch_meraki_user_by_emailを呼び出して、ユーザーのメールアドレスを使用してユーザーの詳細を取得します。
    user = fetch_meraki_user_by_email(meraki_api_key, meraki_network_id, meraki_user_email)

    # ユーザーが存在しない場合、メッセージを表示してプログラムを終了します。
    if not user:
        print(f"No user found with the email: {meraki_user_email}")
        exit(1)
    
    try:
        meraki_user_id = user['id']

        # 指定されたユーザーIDを使用してパスワードを更新します。
        response = update_meraki_user_password(meraki_api_key, meraki_network_id, meraki_user_id, new_password)
        if response.status_code == 200:
            print(f"Password updated successfully for user with email {meraki_user_email}")
        else:
            print(f"Failed to update password. Status code: {response.status_code}, Error: {response.text}")

    except requests.exceptions.HTTPError as http_err:
        print(f"HTTP error occurred while updating the password for the given user email: {http_err}")
    except Exception as err:
        print(f"An error occurred: {err}")

def main():
    """
    Main function to rotate the password for a Cisco meraki user.

    Reads and decodes input parameters from stdin, including the authentication record details
    and the new password. Then, updates the password of the specified Cisco meraki user.
    """
    record_title = 'Cisco Authentication Record' #This should be same as the title of the record containing meraki api key and network ID details. 
    api_access_token_record = None
    params = None
    
    # 標準入力（stdin）から入力パラメータを読み取り、デコードします。
    for base64_params in sys.stdin:
        params = json.loads(base64.b64decode(base64_params).decode())

        # PAMスクリプトセクションから渡されたJSON文字列をデコードし、「Rotation Credential」レコードとして読み込みます。
        records = json.loads(base64.b64decode(params.get('records')).decode())
        # 指定されたタイトルと一致するレコードを検索します。
        api_access_token_record = next((record for record in records if record['title'].lower() == record_title.lower()), None)
        break

    if api_access_token_record is None:
        print(f"# Error: No Record with the access token found. Title: {record_title}")
        exit(1)
    
    # レコードから詳細情報を抽出します。
    
    # ユーザーが存在するネットワークのネットワークIDです。
    meraki_network_id = api_access_token_record.get('network_id')
    
    # Cisco Meraki API認証のためのAPIキーです。
    meraki_api_key = api_access_token_record.get('password')

    # パスワードをローテーションする必要があるCisco Merakiユーザーのメールアドレスです。
    meraki_user_email = params.get('user')

    # Cisco Merakiユーザーに設定する新しいパスワードです。
    new_password = params.get('newPassword')
    
    # 必要なすべてのフィールドが存在するか確認します。
    if not all([meraki_network_id, meraki_api_key, meraki_user_email]):
        print("# Error: One or more required fields are missing in the access token record.")
        exit(1)

    # 指定されたCisco Merakiユーザーのパスワードをローテーションします。
    rotate(meraki_network_id, meraki_api_key, meraki_user_email, new_password)

if __name__ == "__main__":
    main()
```

{% endcode %}

GitHubでも入手できます。

{% embed url="<https://github.com/Keeper-Security/Zero-Trust-KeeperPAM-Scripts/blob/main/cisco-meraki/update_meraki_user.py>" %}

## 5. Python実行環境の準備 <a href="#id-5-python-environment-setup" id="id-5-python-environment-setup"></a>

**\[追加認証情報]** で手順1の `Cisco Authentication Record` を選択します。

* **\[コマンドプレフィックス付きで実行]** を有効にし、Python実行ファイルのフルパスを指定
* Docker経由のゲートウェイでは通常 `/usr/local/bin/python3`

## 6. 構成の保存とローテーションの実行 <a href="#id-6-save-and-run-rotation" id="id-6-save-and-run-rotation"></a>

PAMユーザーレコードで **\[保存]** をクリックします。設定後、**\[PAMスクリプトのみを実行]** でオンデマンドローテーションを実行できます。

![](/files/FjxOC0E04Kk5PR0hA3b1)


---

# Agent Instructions
This documentation is published with GitBook. GitBook is the documentation platform designed so that both humans and AI agents can read, navigate, and reason over technical content effectively. Learn more at gitbook.com.

## Querying This Documentation
If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.keeper.io/keeperpam/jp/privileged-access-manager/password-rotation/rotation-use-cases/saas-account/cisco-meraki.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
