Skip to main content

Prod to dev — preserve custom DLP

Create a small Runtime configuration in prod, back it up, and restore it into dev using only airs-cli commands. No capture helpers, shell variables, or scripts are needed. The example preserves custom DLP; see the separate Basic-fallback migration if you intentionally want to replace unavailable custom DLP with Basic protection.

Before you start​

Use CLI 5.7.1 or newer (SDK 0.30.0 or newer), which supports named-tenant DLP credentials. Both AIRS tenants must already exist and have Management OAuth credentials and Enterprise DLP provisioning/permissions. tenant create registers a tenant locally; it does not provision a cloud tenant.

Use dedicated test tenants with empty Runtime profile and topic inventories for this example. The label prod is an example name, not an instruction to modify a business production environment. These commands create real resources. Do not repeat the setup against a tenant where this migration has already completed.

Run commands one at a time from a private working directory. Backup files contain configuration, are created privately, and are not overwritten. No Bash-specific setup is required. Avoid --debug when handling credentials or private configuration.

airs-cli --version
airs-cli runtime profiles restore --help

The restore help must include --on-conflict with verify and --on-missing-dlp. Credentials come only from the selected tenant file; PANW_* variables, PRISMA_AIRS_CONFIG_PATH, and .env files are ignored (airs-cli doctor lists any still set). Do not export secrets to work around an authentication failure. See tenant authentication recovery.

Throughout this guide, replace quoted placeholders such as "<DEV_TSG>" with the actual value printed by an earlier airs-cli command. They are not environment variables.

1. Register and inspect dev and prod​

Enter each tenant's TSG ID, OAuth client ID, and hidden client secret when prompted. If already registered, skip creation and inspect the existing entries instead.

airs-cli tenant create dev
airs-cli tenant create prod
airs-cli tenant list
airs-cli tenant read dev
airs-cli tenant read prod

Check that dev and prod have different TSG IDs and the intended credentials/config paths. Record the dev TSG ID for --expect-tsg later. Credential reads are redacted.

Check both inventories before creating anything:

airs-cli tenant switch dev
airs-cli tenant list
airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json
airs-cli tenant switch prod
airs-cli tenant list
airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json

Each profile/topic inventory should be []. Stop if it is not empty; this guide does not delete existing configuration. Successful lists also exercise authentication in each tenant. Leave prod selected for the next three sections.

2. Create the custom DLP dependency in prod​

Create a synthetic regex pattern. AIRS-E2E-123456 is an example matching string.

airs-cli runtime dlp patterns create \
--name dlp-test-pattern --type custom --technique regex \
--description 'Synthetic Runtime migration acceptance pattern' \
--confidence-levels high --regex 'AIRS-E2E-[0-9]{6}' --output json

Copy the returned pattern id into the next command:

airs-cli runtime dlp patterns get "<PROD_PATTERN_ID>" --output json

Verify the name, regex, and detection technique. Substitute that same pattern ID in the inline request below. This is JSON passed directly to airs-cli, not a shell script or a request file. The explicit rule_item tree avoids the legacy --pattern-id shorthand, which emits a different leaf shape.

airs-cli runtime dlp profiles create --body '{
"name": "dlp-test",
"profile_type": "advanced",
"description": "Synthetic Runtime migration acceptance DLP profile",
"detection_rules": [{
"rule_type": "expression_tree",
"expression_tree": {
"operator_type": "or",
"sub_expressions": [{
"rule_item": {
"detection_technique": "regex",
"id": "<PROD_PATTERN_ID>",
"name": "dlp-test-pattern",
"match_type": "include",
"confidence_level": "high",
"occurrence_operator_type": "any",
"occurrence_count": 1
}
}]
}
}]
}' --output json

Copy the DLP profile id from the response and read it back:

airs-cli runtime dlp profiles get "<PROD_DLP_PROFILE_ID>" --output json

Confirm dlp-test is advanced and active. Its detectionRules must contain a ruleItem referencing the prod pattern, with regex/high/include/any matching. Note its version. GET output uses camelCase; create request fields use snake_case. Do not replay the GET response as a create body.

3. Create two custom topics in prod​

airs-cli runtime topics create \
--name migration-financial-advice \
--description 'Requests for personalized financial investment advice' \
--examples 'Which stocks should I buy with my retirement savings?' \
'Tell me how to invest my personal savings for maximum profit.'

airs-cli runtime topics create \
--name migration-legal-advice \
--description 'Requests for personalized legal advice or legal representation' \
--examples 'Should I sue my landlord over my rental dispute?' \
'Tell me the legal strategy I should use in my court case.'

airs-cli runtime topics list --all --max 0 --output json

Confirm both topic names, descriptions, and examples. Topic create/apply acknowledgements were human-readable in the acceptance run even when JSON was requested; use the list and GET commands for structured read-back.

4. Create three Runtime security profiles in prod​

Create a profile with custom DLP, a profile with Basic DLP, and a profile with DLP disabled. The third command explicitly configures latency so the CLI builds a policy with DLP disabled rather than leaving the entire policy to server defaults.

airs-cli runtime profiles create --name migration-custom-dlp \
--dlp-action block --dlp-profiles dlp-test

airs-cli runtime profiles create --name migration-basic-dlp \
--dlp-action block --dlp-profiles 'sensitive content'

airs-cli runtime profiles create --name migration-topics-only \
--inline-timeout-action block --max-inline-latency 5

airs-cli runtime topics apply \
--profile migration-topics-only --name migration-financial-advice --intent block

airs-cli runtime topics apply \
--profile migration-topics-only --name migration-legal-advice --intent block

airs-cli runtime profiles get migration-custom-dlp --output json
airs-cli runtime profiles get migration-basic-dlp --output json
airs-cli runtime profiles get migration-topics-only --output json
airs-cli runtime profiles list --all --max 0 --output json

Inspect the stored policies before backing up. The name-based DLP flags select members by name; they do not supply an explicit ID/version. Confirm the service stored the intended custom dependency and compare any returned ID/version with the DLP GET above. Stop if the reference is missing or points to a different dependency.

ProfileRequired stored configuration
migration-custom-dlpDLP action block, member dlp-test
migration-basic-dlpDLP action block, built-in member sensitive content
migration-topics-onlyDLP action empty, member null/empty; both custom topics in a block group

For the topic-only profile, guardrail-level action: allow permits unrelated topics; the nested topic group must say block. Also review other service/default protections: the profile flags do not reproduce every unrelated field from the historical fixture.

5. Back up prod Runtime configuration​

Confirm prod is still selected, then write a new backup in the current directory:

airs-cli tenant list
airs-cli runtime profiles backup --all --output-file ./prod-runtime-backup.json --output json

Captured backup response, with the path normalized and tenant ID redacted:

[
{
"file": "./prod-runtime-backup.json",
"sourceTsgId": "<PROD_TSG>",
"profiles": 3,
"topics": 2
}
]

Check the source TSG and counts. An existing output file causes EEXIST; choose a new filename and use that filename in the restore commands. Do not discard a successful backup.

The backup contains latest Runtime profiles and referenced custom topics. It does not contain restorable Enterprise DLP patterns/profiles, credentials, API keys, applications, or telemetry. Prepare the custom DLP dependency separately in dev next.

6. Switch to dev and prepare its DLP dependency​

airs-cli tenant switch dev
airs-cli tenant list
airs-cli runtime dlp patterns create \
--name dlp-test-pattern --type custom --technique regex \
--description 'Synthetic Runtime migration acceptance pattern' \
--confidence-levels high --regex 'AIRS-E2E-[0-9]{6}' --output json
airs-cli runtime dlp patterns get "<DEV_PATTERN_ID>" --output json

Copy the dev pattern ID from this create response. Do not use the prod pattern ID.

airs-cli runtime dlp profiles create --body '{
"name": "dlp-test",
"profile_type": "advanced",
"description": "Synthetic Runtime migration acceptance DLP profile",
"detection_rules": [{
"rule_type": "expression_tree",
"expression_tree": {
"operator_type": "or",
"sub_expressions": [{
"rule_item": {
"detection_technique": "regex",
"id": "<DEV_PATTERN_ID>",
"name": "dlp-test-pattern",
"match_type": "include",
"confidence_level": "high",
"occurrence_operator_type": "any",
"occurrence_count": 1
}
}]
}
}]
}' --output json
airs-cli runtime dlp profiles get "<DEV_DLP_PROFILE_ID>" --output json

Compare the dev read-back with prod: same synthetic regex and matching rules, advanced profile type, and a rule leaf using dev's pattern ID. DLP numeric profile IDs are tenant-scoped and can happen to be equal; a matching number alone proves nothing.

This step creates equivalent dependencies explicitly; Runtime restore does not clone Enterprise DLP. If dlp-test already exists, inspect it rather than creating a duplicate. The CLI currently has no supported Enterprise DLP profile DELETE operation.

7. Preview and restore into dev​

Replace "<DEV_TSG>" with dev's actual numeric TSG ID from airs-cli tenant list. Check that the destination still has no Runtime profiles or topics:

airs-cli tenant list
airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json
airs-cli runtime profiles restore ./prod-runtime-backup.json \
--dlp-map 'dlp-test=dlp-test' --on-missing-dlp error \
--expect-tsg "<DEV_TSG>" --dry-run --output json

The preview must show the intended source/destination TSG IDs, three profile creates, two topic creates, one DLP mapping, and no Basic fallbacks. Mapping chooses a destination dependency; it does not check that the DLP rules are equivalent. That is why step 6 includes a read-back comparison.

Captured preview response (tenant IDs redacted):

[
{
"sourceTsgId": "<PROD_TSG>",
"destinationTsgId": "<DEV_TSG>",
"dryRun": true,
"profiles": [
{"name": "migration-basic-dlp", "action": "create"},
{"name": "migration-custom-dlp", "action": "create"},
{"name": "migration-topics-only", "action": "create"}
],
"topics": [
{"name": "migration-financial-advice", "action": "create"},
{"name": "migration-legal-advice", "action": "create"}
],
"dlpMappings": [{"source": "dlp-test", "destination": "dlp-test"}],
"dlpFallbacks": [],
"serverDefaults": []
}
]

Confirm the dry-run left the inventories empty, then execute and review the confirmation prompt. --force is unnecessary for this interactive workflow.

airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json
airs-cli runtime profiles restore ./prod-runtime-backup.json \
--dlp-map 'dlp-test=dlp-test' --on-missing-dlp error \
--expect-tsg "<DEV_TSG>" --output json

The completed result must have complete: true, three created profiles, two created topics, and dlpFallbacks: []. Stop on any error. Completed writes remain after a partial failure; use the verification preview below to inspect recovery instead of blindly recreating resources or choosing skip/update.

8. Validate the migrated configuration​

airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json
airs-cli runtime profiles get migration-custom-dlp --output json
airs-cli runtime profiles get migration-basic-dlp --output json
airs-cli runtime profiles get migration-topics-only --output json
airs-cli runtime dlp profiles get "<DEV_DLP_PROFILE_ID>" --output json
airs-cli runtime dlp patterns get "<DEV_PATTERN_ID>" --output json

Check the following before declaring the migration successful:

CheckExpected in dev
InventoryThree profiles and two topics
Custom DLPdlp-test, action block, binding to dev's DLP profile/version and rule tree
Basic DLPBuilt-in sensitive content, action block
Topic-only profileDLP disabled; both custom topics in the nested block group
Topic referencesDev topic IDs/revisions; descriptions and examples preserved
Protection changesNo Basic fallback; inspect any reported server-added defaults

Ask restore to compare the existing profiles with the backup without changing resources:

airs-cli runtime profiles restore ./prod-runtime-backup.json \
--dlp-map 'dlp-test=dlp-test' --on-missing-dlp error --on-conflict verify \
--expect-tsg "<DEV_TSG>" --dry-run --output json

All three profile actions should be verify, and both topic actions should be reuse. There must be no creates or updates. A mismatch fails validation. If a resource is missing, investigate rather than assuming the earlier restore completed.

Once that preview is clean, run the same verification without --dry-run:

airs-cli runtime profiles restore ./prod-runtime-backup.json \
--dlp-map 'dlp-test=dlp-test' --on-missing-dlp error --on-conflict verify \
--expect-tsg "<DEV_TSG>" --output json
airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json

Expect complete: true, three verified profiles and two reused topics. IDs/revisions should remain unchanged. Verify is not globally read-only: without --dry-run, it can create missing resources, which is why the preceding preview matters.

Optionally back up dev's restored state, inspect prod again, and leave dev selected:

airs-cli runtime profiles backup --all --output-file ./dev-runtime-backup.json --output json
airs-cli tenant switch prod
airs-cli runtime profiles list --all --max 0 --output json
airs-cli runtime topics list --all --max 0 --output json
airs-cli tenant switch dev
airs-cli tenant list

Compare prod's IDs, revisions, and configuration with the pre-migration state; migration should not change the source. Keep both backups private. If your terminal closes, tenant registrations and backup files persist: return to the backup directory, inspect airs-cli tenant list, select the intended tenant, and resume from the last verified step.

Validated results — 2026-09-09​

The operator's submitted migration evidence was independently checked offline:

StageVerified result
Backup3 profiles, 2 referenced topics
Dry-run3 profile creates, 2 topic creates, 1 DLP mapping; destination unchanged
RestoreComplete; 3 profiles and 2 topics created; 0 Basic fallbacks
Verify rerunComplete; 3 profiles verified, 2 topics reused; destination unchanged
SourceProfile/topic snapshots unchanged
Custom DLPEquivalent synthetic regex and rule tree, rebound to dev dependencies

The 45 captured commands used internal capture tooling and explicit JSON Runtime profile requests. This guide presents direct CLI commands instead; the name-based profile flags above are not a verbatim replay of those requests. Command syntax/request construction is checked locally; the archived run is not evidence of a new live execution of this edited guide. Always perform the read-back checks above, including other policy defaults.

The archive did not record the CLI version or scanner test traffic. These results validate configuration migration, not detection efficacy or application cutover. Raw evidence, tenant IDs, local paths, and audit identities are not published here.