# NSX Security Group IP Sync Syncs effective IP members from Security Groups on a **source** NSX manager to static IP entries on matching groups on a **target** NSX manager. The source is the source of truth for each pair. Supports NSX **3.x, 4.x, and 9.x** via the Policy REST API. --- ## How it works ``` Source NSX Target NSX ────────────────────────── ────────────────────────── Security-Group-A Security-Group-A [VM Criteria: Name contains [VM Criteria: Name contains win-svr-web] win-svr-web] Effective IPs (computed): Static IP entries: 10.0.1.10 10.0.1.10 ← already synced 10.0.1.11 ← missing on target (nothing) (10.0.1.99 removed from source) 10.0.1.99 ← will be removed ``` The script: 1. Fetches **effective (computed) IPs** from each group on the source. 2. Fetches **static IP entries** from matching groups on the target. 3. Diffs: source IPs are the desired state. 4. Patches the target group: **adds** missing IPs, **removes** extra IPs. Only the `IPAddressExpression` entries are touched. Existing VM/Tag/Condition criteria on the target group are left unchanged. --- ## Requirements - Python 3.10+ - `pip install -r requirements.txt` --- ## Quick start ```bash # 1. Install dependencies pip install -r requirements.txt # 2. Copy and edit the config cp config.example.yaml config.yaml $EDITOR config.yaml # 3. Dry-run (WhatIf – no changes written) python main.py --config config.yaml --whatif # 4. Live sync python main.py --config config.yaml ``` --- ## Usage ``` python main.py [--config FILE] [options] ``` ### Connection flags (override config) | Flag | Description | |---|---| | `--source-host HOST` | Source NSX manager hostname or IP | | `--source-user USER` | Source username | | `--source-pass PASS` | Source password *(prefer env var)* | | `--source-domain DOMAIN` | Policy domain (default: `default`) | | `--target-host HOST` | Target NSX manager hostname or IP | | `--target-user USER` | Target username | | `--target-pass PASS` | Target password *(prefer env var)* | | `--target-domain DOMAIN` | Policy domain (default: `default`) | | `--no-verify-ssl` | Skip SSL certificate verification | ### Sync flags | Flag | Description | |---|---| | `--groups NAME [NAME ...]` | Security group names to sync | | `--whatif` | Show what would change, write nothing | | `--interactive` | Terminal UI for group selection | | `--workers N` | Concurrent API threads (default: 4) | ### Output / export flags | Flag | Description | |---|---| | `--export json\|csv\|both` | Export source/target snapshots + diff | | `--export-dir DIR` | Output directory (default: `exports/`) | | `--silent` | Suppress console output (automation) | | `--log-file FILE` | Write logs to a file | | `--debug` | Verbose API logging | --- ## Credentials via environment variables Store passwords in environment variables instead of the config file: ```bash export NSX_SOURCE_PASSWORD="your-source-password" export NSX_TARGET_PASSWORD="your-target-password" python main.py --config config.yaml ``` The config file also supports `${ENV_VAR}` interpolation: ```yaml password: "${NSX_SOURCE_PASSWORD}" ``` --- ## WhatIf / Test mode ```bash python main.py --config config.yaml --whatif ``` Prints exactly what would be added or removed per group without writing any changes to the target. Use this to validate before a live run. --- ## Export for auditing ```bash # Export JSON and CSV before syncing python main.py --config config.yaml --export both --whatif ``` Creates timestamped files in `exports/`: | File | Contents | |---|---| | `source_.json/csv` | Effective IPs per group on source | | `target_.json/csv` | Current static IPs per group on target | | `diff_.json/csv` | Per-IP action: `add`, `remove`, or `in_sync` | --- ## Automation (silent mode) ```bash python main.py --config config.yaml --silent --log-file logs/sync.log echo "Exit code: $?" ``` Exit codes: | Code | Meaning | |---|---| | `0` | Success – all groups synced (or already in sync) | | `1` | Configuration error – check args/config | | `2` | Runtime error – one or more groups failed; check logs | --- ## Interactive mode ```bash python main.py --config config.yaml --interactive ``` Pulls the full group list from the source manager and presents a paginated terminal selector. Use row numbers to toggle selection, then press `d` to confirm. --- ## Project structure ``` nsx_fed_sync_script/ ├── main.py Entry point / CLI ├── config.example.yaml Configuration template ├── requirements.txt ├── .gitignore ├── nsx_sync/ │ ├── nsx_client.py NSX Policy API client (auth, pagination, retries) │ ├── sync_engine.py Diff + apply logic (concurrent fetch & patch) │ ├── exporter.py JSON / CSV export helpers │ └── interactive.py Terminal group-selection UI ├── exports/ Runtime export files (git-ignored) └── logs/ Runtime log files (git-ignored) ``` --- ## Notes on NSX version compatibility The script exclusively uses the **NSX Policy API** (`/policy/api/v1/...`), which is available and recommended on NSX 3.x, 4.x, and later. The deprecated Manager API (`/api/v1/ns-groups/...`) is not used. For NSX 3.x environments where the Policy API may not yet be the primary interface, ensure that Security Groups are managed through the Policy plane (not the legacy Manager plane) for the effective-IP endpoint to return accurate results.