Importing PAM Resources

How to bulk import KeeperPAM resources

Overview

Keeper supports importing of PAM resources in bulk through the Keeper Commander CLI. This allows you to import a large number of resources, along with a PAM Configuration, Gateway and project folders.

We have created a simple and advanced import method. The simple method described in this page converts a basic CSV list of Windows hosts into a JSON import file that Keeper Commander can ingest. Use this method when onboarding large numbers of PAM Machines.

In this page, we will demonstrate importing a large number of domain-joined Windows servers and local admin accounts.


Overview of the Workflow

  1. Prepare a CSV that contains the target servers and credentials.

  2. Create or edit a JSON template that describes the project, policies and directory binding.

  3. Run the helper script to merge the CSV data with the template and produce pam_import.json.

  4. Import the file with the pam project import command.


Prerequisites

Requirement
Notes

Keeper Commander v17.1.2 or newer

Verify with keeper version

Python 3.8+

Required to execute the conversion script

KeeperPAM License

Enabled in the Keeper Admin Console

Admin role with Manage PAM permission

Enabled in the Keeper Admin Console


1 – Prepare the CSV

We will convert a basic 3-column CSV file into a JSON import file using a Python script. The script expects a comma‑separated file named servers_to_import.csv by default. Each row must contain exactly three fields, as seen by the example below:

hostname,username,password
srv‑01,Administrator,LocalAdminPassword123
srv‑02,Administrator,LocalAdminPassword123
srv‑03,Administrator,LocalAdminPassword123
srv‑04,Administrator,LocalAdminPassword123
srv‑05,Administrator,LocalAdminPassword123

Tip: The first line is treated as a header if it matches the column names above. Replace the Administrator and LocalAdminPassword123 with the local admin username/password for each server.


2 – Create the JSON Template

Download the below JSON Template file and save it as import_template.json.

Click to view
{
    "project": "XXX:Project1",
    "shared_folder_users": {
        "manage_users": true,
        "manage_records": true,
        "can_edit": true,
        "can_share": true
    },
    "shared_folder_resources": {
        "manage_users": true,
        "manage_records": true,
        "can_edit": true,
        "can_share": true
    },
    "pam_configuration": {
        "environment": "local",
        "connections": "on",
        "rotation": "on",
        "graphical_session_recording": "on"
    },
    "pam_data": {
        "resources": [
            {
                "_comment1": "Every key that starts with '_' is a comment and can be ignored or deleted",
                "_comment2": "Every value that starts with uppercase 'XXX:' must be replaced with actual value (removed if not required)",
                "_comment3": "Every value that starts with lowercase 'xxx:' is just a placeholder - can be replaced with anything but must be present",
                "type": "pamDirectory",
                "title": "XXX:Project1 AD",
                "directory_type": "XXX:active_directory|ldap",
                "host": "XXX:demo.local",
                "port": "XXX:636",
                "use_ssl": true,
                "domain_name": "XXX:demo.local",
                "pam_settings": {
                    "options": {
                        "rotation": "on",
                        "connections": "on",
                        "tunneling": "on",
                        "graphical_session_recording": "on"
                    },
                    "connection": {
                        "protocol": "rdp",
                        "port": "XXX:3389",
                        "security": "XXX:any",
                        "ignore_server_cert": true,
                        "_comment_administrative_credentials": "Must match the unique title of one of the users below",
                        "administrative_credentials": "XXX:DomainAdmin"
                    }
                },
                "users": [
                    {
                        "type": "pamUser",
                        "_comment_title": "Must match administrative_credentials above if this is the admin user",
                        "title": "XXX:DomainAdmin",
                        "_comment_login_password": "Must provide valid credentials but delete sensitive data/json after import",
                        "login": "XXX:administrator@demo.local",
                        "password": "XXX:P4ssw0rd_123",
                        "rotation_settings": {
                            "rotation": "general",
                            "enabled": "on",
                            "schedule": {
                                "type": "on-demand"
                            }
                        }
                    }
                ]
            },
            {
                "_comment4": "While pamDirectory section above is static, the pamMachine section below is dynamicly generated",
                "_comment5": "One pamMachine with one pamUser will be generated per each line from the CSV file",
                "_comment6": "Only one pamMachine is needed and it will be used as a template for all CSV rows",
                "_comment7": "Please do NOT edit lines with xxx: in them - these are placeholders",
                "_comment8": "Any other line that don't contain xxx: can be altered/added/deleted in the template",
                "_comment9": "CSV Format: server_name,username,password",
                "type": "pamMachine",
                "_comment_title_and_host": "server value from CSV",
                "title": "xxx:server1",
                "host": "xxx:server1",
                "port": "5986",
                "ssl_verification": true,
                "operating_system": "Windows",
                "pam_settings": {
                    "options": {
                        "rotation": "on",
                        "connections": "on",
                        "tunneling": "on",
                        "graphical_session_recording": "on"
                    },
                    "connection": {
                        "protocol": "rdp",
                        "port": "3389",
                        "security": "any",
                        "ignore_server_cert": true,
                        "_comment_administrative_credentials": "Format: pamDirectory#title.pamDirectory#administrative_credentials - exact match needed",
                        "administrative_credentials": "XXX:Project1 AD.DomainAdmin"
                    }
                },
                "users": [
                    {
                        "type": "pamUser",
                        "_comment_title": "username value from CSV or server-username if --prefix-names option is used",
                        "title": "xxx:admin",
                        "_comment_login": "username value from CSV",
                        "login": "xxx:Administrator",
                        "_comment_password": "password value from CSV",
                        "password": "xxx:P4ssw0rd_123",
                        "rotation_settings": {
                            "rotation": "general",
                            "enabled": "on",
                            "schedule": {
                                "type": "on-demand"
                            }
                        }
                    }
                ]
            }
        ]
    }
}
  • Replace every value beginning with capital XXX: with a value

  • Leave placeholders beginning with xxx: untouched—these are overwritten by the script

For our simple example, we'll modify the XXX fields with the below:

Top section:
"project": "Import Demo Project"

pam_data.resources:
"title": "My Domain Controller"
"directory_type": "active_directory"
"host": "lureydemo.local"
"port": "636"
"domain_name": "lureydemo.local"

pam_data.resources.pamDirectory.pam_settings.connection:
"port": "3389"
"security": "any"
"administrative_credentials": "My Domain Admin"

pam_data.resources.pamDirectory.users:
"title": "My Domain Admin"
"login": "administrator@lureydemo.local"
"password": "YourExistingDomainPassword"

pam_data.resources.pamMachine.users:
"administrative_credentials": "My Domain Controller.My Domain Admin"
(note: this is named to reference the directory title and directory admin)

3 – Generate the Import File

The CSV will be converted to a properly formatted JSON file for all of the servers.

  • Download the script pam_import_generator.py and save it to the same working folder.

  • At this point, you have 3 files in the current folder:

    • pam_import_generator.py

    • import_template.json

    • servers_to_import.csv

  • Run the pam_import_generator.py script to generate the full JSON import file:

python3 pam_import_generator.py --prefix-names

This creates a file called pam_import.json which contains all of the resources which will be imported into Keeper.


4 – Import Resources into Keeper

The file pam_import.json will now be imported into Keeper from the Commander CLI. Start your Keeper Commander session. If you haven't set up Commander, follow this setup guide.

keeper shell

Run the import with this command (assumes that the pam_import.json file is in the Commander working directory. It can also have an absolute path).

pam project import -f pam_import.json

When the import is complete, the response output in Commander will contain an access token:

"access_token": "XXXXXXXX...."

Save the value inside the quotes (XXXXX.....) for initializing the Gateway in the next step below.

Note: After the import is complete, the vault will be updated with the resources. If your vault is currently open, it's probably a good idea to click Full Sync or refresh the page.

5 – Start the Gateway

This document doesn't cover the installation of a Keeper Gateway, so let's assume that you have already done this. If you haven't created a Gateway, follow these setup instructions for your preferred method.

  • In the Gateway's configuration, update the GATEWAY_CONFIG with the access token value provided in Step 4 above. For Docker installations, this will be in the docker-compose.yaml file. For Windows installations, it will be in the C:\ProgramData\KeeperGateway\config\gateway-config.json file

  • Restart the Gateway

At this point, the Gateway is running and has been associated to all of your imported resources. By default, the import will add all PAM projects to a folder called "PAM Environments".

Import Results

Based on this example, below are some screenshots of the resources created:

  • Secrets Manager Application

  • Keeper Gateway

  • PAM Configuration

  • PAM Directory (Active Directory Service)

  • PAM User representing the Domain Admin

  • PAM Machine Resources (Windows Servers)

  • PAM Users for each PAM Machine (Local Admins)

KSM Application
PAM Configuration
PAM Gateway
PAM Resources
PAM Users
Domain Controller
PAM Machine
PAM User (Local Admin)

Advanced Import Formats

This document demonstrated the basic example of importing a series of Windows servers for the purpose of establishing connections, tunnels and automated password rotation. The configuration of the connections and resources was set up to be simple.

More advanced import options including full JSON template capabilities are documented on this GitHub README Page. This page provides all of the possible settings that can be modified as part of the import process. If you need to re-run this process, it's no big deal - just delete the Folders, PAM Configuration and Gateway from the vault and start over.

If you have any questions on the import process, contact your account team or email commander@keepersecurity.com.


Last updated

Was this helpful?