Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 12 additions & 5 deletions docs/cyberark-pam-import.md
Original file line number Diff line number Diff line change
Expand Up @@ -62,8 +62,13 @@ Keeper Vault/
| PaloAltoNetworks, CiscoIOS, CiscoASA, JuniperJunos, F5BigIP, CheckPointGAIA | pamMachine | ssh | 22 |
| CyberArk (internal) | pamMachine | ssh | 22 |
| BusinessWebsite | login | — | — |
| (empty platformId) | pamMachine | ssh | 22 |
| (unknown platformId) | pamMachine | ssh | 22 |
| Custom/renamed platform resolved by CyberArk metadata or keyword matching | inferred PAM type | inferred | inferred |
| Empty/unknown platform with no metadata or keyword match | login | — | — |

For an unresolved platform, fields not already represented by the login's title,
login, password, URL, or CyberArk notes are preserved as text custom fields.
Nested account metadata is flattened using dotted field names. Raw secret-bearing
payload keys are excluded from custom fields.

### Field Mapping

Expand Down Expand Up @@ -167,6 +172,9 @@ pam project cyberark-import pvwa.company.com --dry-run --output import.json --in
# Filter specific safes
pam project cyberark-import pvwa.company.com --safes "Production,Staging" --exclude-safes "Archive*"

# Import into Nested Share Folders (folders, records, rotation, PAM config)
pam project cyberark-import pvwa.company.com --name "CyberArk Migration" --gateway "My Gateway" --nsf

# Extend existing project
pam project cyberark-import pvwa.company.com --config <pam-config-uid>

Expand Down Expand Up @@ -196,7 +204,8 @@ pam project cyberark-cleanup --name "CyberArk Migration" --dry-run
| `--name`, `-n` | Project name |
| `--config`, `-c` | Extend existing PAM config UID |
| `--gateway`, `-g` | Gateway name or UID |
| `--folder-mode` | flat, exact, ksm (default) |
| `--folder-mode` | flat, exact, ksm, safe (default: safe) |
| `--nsf` | Create project folders/records/PAM config in Nested Share Folders |
| `--safes` | Include only these safes (comma/glob) |
| `--exclude-safes` | Exclude safes (comma/glob) |
| `--list-safes` | List safes and exit |
Expand Down Expand Up @@ -270,5 +279,3 @@ Before building the import JSON, the importer warns about:
- Rate limit handling: automatic retry on HTTP 429 with exponential backoff
- Pagination cap: MAX_FETCH_RECORDS (50,000) prevents OOM attacks
---


25 changes: 18 additions & 7 deletions keepercommander/commands/pam/vault_target.py
Original file line number Diff line number Diff line change
Expand Up @@ -594,8 +594,13 @@ def update_pam_record(params, record, command='pam', force_nsf=False):
params.sync_data = True


def execute_record_add_in_folder(params, args, folder_uid, command='pam'):
"""Add a record in *folder_uid*, using NSF-native creation when needed."""
def execute_record_add_in_folder(params, args, folder_uid, command='pam',
sync_after=True):
"""Add a record in *folder_uid*, using NSF-native creation when needed.

When *sync_after* is False, NSF callers can defer sync_down to a batch
boundary (avoids one sync per record during large PAM imports).
"""
from ..record_edit import RecordAddCommand
from ..nested_share_folder.record_commands import NestedShareRecordAddCommand

Expand All @@ -605,7 +610,7 @@ def execute_record_add_in_folder(params, args, folder_uid, command='pam'):
nsf_args.pop('folder', None)
nsf_args['folder_uid'] = folder_uid
uid = NestedShareRecordAddCommand().execute(params, **nsf_args)
if uid:
if uid and sync_after:
from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys
sync_down_preserving_nsf_keys(params)
return uid
Expand All @@ -614,8 +619,13 @@ def execute_record_add_in_folder(params, args, folder_uid, command='pam'):
return RecordAddCommand().execute(params, **record_args)


def execute_record_v3_add_in_folder(params, args, folder_uid, command='pam'):
"""Add a v3 typed record in *folder_uid*, using NSF-native creation when needed."""
def execute_record_v3_add_in_folder(params, args, folder_uid, command='pam',
sync_after=True):
"""Add a v3 typed record in *folder_uid*, using NSF-native creation when needed.

When *sync_after* is False, NSF callers can defer sync_down to a batch
boundary (avoids one sync per record during large PAM imports).
"""
import json

from ..recordv3 import RecordAddCommand
Expand All @@ -638,8 +648,9 @@ def execute_record_v3_add_in_folder(params, args, folder_uid, command='pam'):
if not result.get('success'):
raise CommandError(command, normalize_nsf_user_message(result.get('message')) or
'Failed to create record in Nested Share Folder')
from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys
sync_down_preserving_nsf_keys(params)
if sync_after:
from ..pam_import.nsf_helpers import sync_down_preserving_nsf_keys
sync_down_preserving_nsf_keys(params)
return result['record_uid']

record_args['folder'] = folder_uid
Expand Down
18 changes: 12 additions & 6 deletions keepercommander/commands/pam_import/base.py
Original file line number Diff line number Diff line change
Expand Up @@ -1070,7 +1070,8 @@ def create_record(self, params, folder_uid):
fields.append(f"file=@{x.file}")

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid

Expand Down Expand Up @@ -1165,7 +1166,8 @@ def create_record(self, params, folder_uid):
fields.append(f"file=@{x.file}")

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid
return uid
Expand Down Expand Up @@ -1435,7 +1437,8 @@ def create_record(self, params, folder_uid):
# switch to f.* once RT definition(s) update w/ pamSettings field

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid

Expand Down Expand Up @@ -1628,7 +1631,8 @@ def create_record(self, params, folder_uid):
# switch to f.* once RT definition(s) update w/ pamSettings field

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid

Expand Down Expand Up @@ -1776,7 +1780,8 @@ def create_record(self, params, folder_uid):
# switch to f.* once RT definition(s) update w/ pamSettings field

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid

Expand Down Expand Up @@ -1881,7 +1886,8 @@ def create_record(self, params, folder_uid):
# switch to f.* once RT definition(s) update w/ pamRemoteBrowserSettings field

if fields: args["fields"] = fields
uid = execute_record_add_in_folder(params, args, folder_uid, command='pam-project-import')
uid = execute_record_add_in_folder(
params, args, folder_uid, command='pam-project-import', sync_after=False)
if uid and isinstance(uid, str):
self.uid = uid

Expand Down
Loading