Copying a distributed firewall from one NSX Global Manager to another is how a second site, or a rebuilt manager, inherits a policy nobody wants to retype. It is also how a live rule appears on the wrong groups if the copy is treated as finished the moment the API returns 200.
The Challenge
A DFW policy is not a document. It is a graph. Groups, services, context profiles, and the rules that point at them. An export that drops the graph, or a restore that recreates every referenced object because the path did not match, will either fail late or succeed at creating a parallel firewall. Neither is a migration.
The other trap is the UI export. Encrypted UI exports are not a format this tool accepts. If the source of truth is a file someone downloaded from the product UI and cannot read, we do not guess at it.
What the Tool Does
Three commands, and TLS verification is always on. Export reads the Global Manager and writes a bundle. Plan reads that bundle plus an optional exact-path mapping and writes a plan. Apply reads the plan. Without --commit, apply does not write.
The plan strips fields the target must own: realization ids, publish status, owner, origin site, remote path. Policies are staged disabled. There is no automatic activation. Mapped objects are reused, not changed. Network objects that are only dependencies are recorded so a person can map them. They are not recreated.
Apply writes through a journal that is flushed and synced as it goes, and it refuses to send a security policy that is not still marked disabled. When the API calls return, the tool prints the sentence the operator has to believe: the writes were accepted, the policies are still disabled, go verify realization and group membership on both sites. API acceptance is not realization proof. That line is in the tool because we watched someone treat a 200 as done.
The Story We Tell the Change Board
The interesting version is not “we migrated the firewall.” It is “we put a disabled copy on the other Global Manager, mapped the objects that already existed, and did not turn a rule on until membership was checked on both sites.” That is a smaller claim, and it is the one the script can keep.
Exclusive file creation is part of the claim. Export, plan, and journal files are created with a flag that fails if the name already exists. A second run does not quietly overwrite last night’s bundle. If you need a new export, you pick a new name.
The Results
The target Global Manager received a disabled copy of the policy. Mapped objects were reused. Dependency objects were recorded, not recreated. The journal was the record of what was sent. Nobody treated the API response as proof the rule was realized. Activation stayed a separate decision, after membership was checked on both sites.
Lessons Learned
A DFW policy is a graph. An export that drops the graph, or a restore that recreates every referenced object because the path did not match, builds a parallel firewall. Encrypted UI exports are not a format this tool accepts. Exclusive file creation matters: a second run must not overwrite last night’s bundle.
Getting Started
Run it beside this. Export and plan write files. Apply does not write unless you pass --commit.
python3 nsx_dfw_migrate.py export --host https://gm-a.essential.coach --out gm-a.json
python3 nsx_dfw_migrate.py plan --host https://gm-b.essential.coach --bundle gm-a.json --out gm-b.plan
python3 nsx_dfw_migrate.py apply --host https://gm-b.essential.coach --plan gm-b.plan
python3 nsx_dfw_migrate.py apply --host https://gm-b.essential.coach --plan gm-b.plan --commit
Clone nsx-dfw-gm-migrate. Run --help, then export, then plan. Apply does not write unless you pass --commit. TLS verification is on. After apply, the policies are still disabled. Check realization and group membership on both sites before anyone enables a rule.
Conclusion
The claim the change board can keep is the smaller one. A disabled copy is on the other Global Manager. The rules are not on until membership has been read.
References
VCF does not own this object. Upgrading NSX Global Manager Nodes in a Federated Environment states that if NSX Federation is configured between two VCF instances, SDDC Manager does not manage the lifecycle of the NSX Global Manager nodes. Those nodes are upgraded by hand, standby and active, before the VCF instances and the Local Managers. A firewall move between those managers is the same kind of work. It is outside the VCF upgrade buttons. The NSX build that belongs with VCF 9.1.1 is the NSX line in the VCF 9.1.1 Bill of Materials.
The exporter, the plan, and the apply that refuses to stage an enabled policy are in the repository. Run plan before --commit.
Repository: github.com/noahfarshad/nsx-dfw-gm-migrate
Related Stories:
- NSX Federation Made the Same Segment Appear Twice — the other job VCF does not lifecycle for you
- The VCF Workload Domain That Said It Was Already Upgraded — another case where the API is the record and the screen is not
