Migrate security rules from any supported source firewall into Palo Alto PAN-OS, Panorama, or VMware NSX DFW — rule-by-rule and device-by-device — through a discover, select, translate, check, deploy, validate, and rollback pipeline.
Firewall Rule Migration moves security rules from any firewall Versus can read into one of three write targets — Palo Alto PAN-OS (standalone), Palo Alto Panorama (device-group), or VMware NSX Distributed Firewall (DFW). It works rule-by-rule (every source rule is discovered, translated, and reviewed as its own unit) and device-by-device (each source firewall is discovered independently, and multiple sources can consolidate into a single target policy).
The migration is a Migration Plan that lives alongside the other application migrations in Versus (A10→AVI, F5 ASM→Cloudflare, rSeries). It reuses the normalized firewall rule model that Versus already builds when it ingests a firewall, so discovery is a read of existing inventory rather than a re-parse of vendor configuration.
Versus keeps every firewall's policy in a normalized rule model — a vendor-neutral intermediate representation (IR) populated by each vendor's importer:
FirewallRuleSet — a named container (a PAN rulebase, an NSX DFW section, etc.), with a rule_type of security, nat, or pbf.FirewallRule — one rule, with action, enabled, sequence, src_zones / dst_zones, src_addresses / dst_addresses, services, applications, log_setting, tags, and hit counters.FirewallObject — an address, address-group, service, service-group, application, or tag referenced by rules.NatRule — NAT rules kept separately from security rules.Because every source vendor's importer normalizes into this same shape, the migration pipeline is vendor-agnostic on the source side: onboarding a new source firewall simply means having an importer that populates the IR. Discovery reads those rows; it does not re-connect to the source device to re-parse config.
A migration is driven by a FirewallMigrationPlan, which references one or more source devices and a single target device, records the chosen target platform and scope, and holds the plan's state as it moves through the pipeline. The plan does not duplicate rule bodies — the authoritative rules stay in the IR, and the plan holds selection, translation, deploy log, and target references.
| Target platform | Plan value | Write driver | Scope field | Commit model |
|---|---|---|---|---|
| Palo Alto PAN-OS (standalone) | panos | PanosDriver | target_vsys (e.g. vsys1) | local commit |
| Palo Alto Panorama | panorama | PanoramaDriver | target_device_group | commit-all to the device-group |
| VMware NSX DFW | nsx | NsxDriver | nsx_domain + nsx_security_policy | declarative — realized on PATCH, no separate commit |
PAN-OS and Panorama reuse the existing Versus firewall drivers. NSX DFW was read-only in Versus before this feature — the migration adds an NsxDriver that implements the write path against the NSX-T Policy API.
A plan advances through a fixed set of stages, each an API action on the plan. Every stage is re-runnable, advances the plan's status, and returns the updated state. The lifecycle is:
draft → discovered → selected → translated → checked → deployed → completed
↘ rolled_back
↘ failed
For each source device on the plan, discover reads its FirewallRule rows from the IR (ordered by rule-set, then sequence) and denormalizes each into a candidate carrying a stable rule key, its action, zones, addresses, services, applications, and enabled flag. The response reports per-device rule counts so you can see what each source contributes.
A rule key is the string "<device_id>:<rule_set_id>:<rule_id>". It is the join key that ties discovery, selection, translation, deploy log, and target references together for one rule.
You choose which candidates to migrate by posting their rule keys (or "all"). Selection is stored on the plan; nothing is written to any device.
For each selected rule, Versus builds a target-native rule plus a checklist, migration notes, and any conflicts — this is pure logic with no device calls. The referenced address and service objects are translated in the same pass and deduplicated so a subnet used by several source rules becomes one target object.
Translation is faithful and explicit: anything that cannot be reproduced 1:1 is recorded as a note or conflict rather than silently dropped.
Action mapping:
| Source action | PAN-OS action | NSX action |
|---|---|---|
allow | allow | ALLOW |
deny | deny | DROP |
drop | drop | DROP |
reset | reset-both | REJECT |
snat / dnat | flagged as a NAT rule | flagged as a NAT rule |
snat / dnat rules are security-policy placeholders only — they carry a conflict telling you to migrate them via the NAT rulebase, because NAT is not a security-rule (and, on NSX, not a DFW) concept.
Zones. PAN-OS requires from / to zones; when a source rule has no zone context, translation defaults both to any, marks the map zones checklist item blocked, and adds a note to review before deploy. NSX has no zones at all — source zones are translated into NSX applied-to scope / groups, with a note to review the mapping.
Objects. Addresses and address-groups become PAN address / address-group objects, or NSX Groups (IP-sets); services become PAN services or NSX Services. Applications map to PAN App-IDs (verify each resolves to a built-in App-ID) or to NSX L7 context profiles where an equivalent exists.
Disabled and logging. A disabled source rule is translated and deployed disabled (disabled: true) so target ordering and audit are preserved. Logging maps to a PAN log-setting reference or NSX logged: true.
A plan-level summary rolls the per-rule results into total, ready, with_conflicts, and with_notes counts for the wizard.
check_objects deduplicates against the target device: for each translated rule it marks rule_exists when the target already has a rule of the same name, and it carries forward the rule's conflicts. This is the "already present, offer to skip" step so a re-run doesn't create duplicates.
Deploy writes the translated rules through the target driver — PanosDriver, PanoramaDriver, or NsxDriver, selected from the plan's target_platform and constructed from the target device and its stored credential. Each rule is provisioned and logged individually into an append-only deploy_log, with the driver's transaction reference captured in target_refs for rollback.
If the target is unreachable or a driver can't be constructed, deploy falls back to a dry run: each rule is logged as simulated (what would be created) instead of failing, so a plan can be walked end-to-end in a lab or demo without a live target. You can also request this explicitly with dry_run: true. A plan whose rules all deploy (or simulate) cleanly moves to deployed; otherwise it is marked failed.
For each target, the commit behavior differs:
PATCH — the Policy API is declarative, so there is no separate commit.validate confirms the deploy result — when every logged rule reached deployed or simulated, the plan advances to completed. The NSX driver additionally supports checking a rule's realized state on the Policy API.
rollback reverses the writes recorded for the plan, calling the target driver's rollback for each provisioned rule (on NSX, a DELETE of the rule under its security policy), then records the removal in the deploy log and sets the plan to rolled_back. Pre-existing objects the plan did not create are never removed.
The plan and its pipeline are exposed as a REST resource under the Versus API. All endpoints require an authenticated bearer token — see Running Workflows via the API for how to obtain one.
| Method | Path | Purpose |
|---|---|---|
GET / POST | /api/firewall-migration-plans/ | list / create a plan |
GET / PATCH / DELETE | /api/firewall-migration-plans/{id}/ | retrieve / update / delete |
POST | /api/firewall-migration-plans/{id}/discover/ | read source IR → candidates |
POST | /api/firewall-migration-plans/{id}/select_rules/ | set selected rule keys |
POST | /api/firewall-migration-plans/{id}/translate/ | build target rules + object map |
POST | /api/firewall-migration-plans/{id}/check_objects/ | dedupe against the target |
POST | /api/firewall-migration-plans/{id}/deploy/ | write via the target driver |
POST | /api/firewall-migration-plans/{id}/validate/ | confirm the deploy result |
POST | /api/firewall-migration-plans/{id}/rollback/ | reverse the plan's writes |
Create a plan by naming its source and target and the target platform:
POST /api/firewall-migration-plans/
Authorization: Bearer …
Content-Type: application/json
{
"name": "DC-edge ASA → PAN-OS",
"source_devices": [12, 13],
"target_device": 40,
"target_platform": "panos",
"target_vsys": "vsys1"
}
Discover the source rules:
POST /api/firewall-migration-plans/7/discover/
200 OK
{
"discovered": 214,
"per_device": [
{ "device_id": 12, "device_name": "asa-edge-1", "vendor": "cisco_asa", "rule_count": 141 },
{ "device_id": 13, "device_name": "asa-edge-2", "vendor": "cisco_asa", "rule_count": 73 }
],
"candidates": [ … ]
}
Select rules (a list of keys, or "all"), then translate:
POST /api/firewall-migration-plans/7/select_rules/
{ "selected": ["12:88:9041", "12:88:9042", "13:91:9210"] }
POST /api/firewall-migration-plans/7/translate/
200 OK
{
"translated": 3,
"objects": 11,
"summary": { "total": 3, "ready": 2, "with_conflicts": 1, "with_notes": 3 },
"translation": { "12:88:9041": { "source": {…}, "target": {…}, "checklist": […], "migration_notes": […], "conflicts": [] } },
"object_translation": { "target_objects": [ … ], "notes": [ … ] }
}
Each translation entry carries the source summary, the target rule (PAN from/to/source/destination/service/application/action, or the NSX source_groups/destination_groups/services/action/direction), the per-rule checklist, migration_notes, and any conflicts.
Deploy, then validate:
POST /api/firewall-migration-plans/7/deploy/
{ "dry_run": false }
200 OK
{ "deployed": 3, "total": 3, "simulated": false, "log": [ … ] }
POST /api/firewall-migration-plans/7/validate/
{ "validated": 3, "total": 3, "status": "completed" }
If anything went wrong, POST /api/firewall-migration-plans/7/rollback/ reverses the writes and sets the plan to rolled_back.
Because discovery is device-by-device and keyed by device, several source firewalls can migrate into a single target scope — one PAN vsys, one Panorama device-group, or one NSX security policy. When you select rules from more than one source, translation merges them and deduplicates shared objects by value, so a 10.0.0.0/24 used by three source firewalls becomes one target object rather than three near-duplicates. This avoids the object explosion that usually accompanies a firewall consolidation.
NsxDriver implements the same driver contract as the PAN drivers, against the NSX-T Policy API (/policy/api/v1). It maps a translated rule to an NSX Rule resource, references groups and services by their policy paths (or ANY), and:
PATCH under …/domains/{domain}/security-policies/{policy}/rules/{id},DELETE of the rule.Rule, group, and service IDs are derived deterministically from the rule name, so re-running a deploy upserts the same rule rather than creating duplicates. Target credentials are read from the device's stored credential in the Versus Vault — they are never embedded in the plan.
Firewall Rule Migration is one of the platform's application migrations, and it builds on the same foundations as the rest of Versus: the normalized firewall inventory that discovery populates, the driver layer that also powers firewall automation and audit, credentials held in the vault, and the outbound-only collector plane that reaches your devices. It is a management-plane operation — Versus reads the source policy from inventory and writes the target policy through the appropriate driver, with a review gate and a rollback path on every plan.