Initial commit
This commit is contained in:
1 parent
37a2659067
commit
2e3c012074
7 files changed
+646
-2
No files matched your search
@@ -1,3 +1,53 @@
|
||||
# nsx_blueprints
|
||||
# NSX Security Blueprints
|
||||
|
||||
Repo of NSX Security Blueprints for applications
|
||||
Python-based automation scripts for deploying NSX tags, security groups, and security policies for enterprise applications.
|
||||
|
||||
## Supported NSX Versions
|
||||
- NSX 4.x
|
||||
- NSX 9.x
|
||||
|
||||
## Structure
|
||||
|
||||
```
|
||||
nsx_blueprints/
|
||||
├── shared/ # Shared utilities, NSX API client, constants
|
||||
├── infra/ # Infrastructure policy (DNS, NTP, AD) — Infrastructure DFW category
|
||||
├── epic/ # EPIC EHR application blueprint
|
||||
├── horizon_view/ # Omnissa Horizon View (VDI) blueprint
|
||||
└── _template/ # Generic blueprint template for new applications
|
||||
```
|
||||
|
||||
## Blueprints
|
||||
|
||||
| Blueprint | DFW Category | Description |
|
||||
|---|---|---|
|
||||
| [Infrastructure](infra/) | Infrastructure | Shared services — DNS, NTP, Active Directory security groups and policy |
|
||||
| [EPIC](epic/) | Application | EPIC Electronic Health Records — tags, security groups, and DFW policy |
|
||||
| [Horizon View](horizon_view/) | Application | Omnissa Horizon View VDI — tags, security groups, and DFW policy |
|
||||
| [Template](\_template/) | Application | Generic starting point for new application blueprints |
|
||||
|
||||
## Conventions
|
||||
|
||||
### Tag Naming
|
||||
`<AppName>|<Tier>` — e.g. `EPIC|Web`, `EPIC|App`, `EPIC|DB`
|
||||
|
||||
### Security Group Naming
|
||||
`SG-<AppName>-<Tier>` — e.g. `SG-EPIC-Web`, `SG-EPIC-DB`
|
||||
|
||||
### Policy / Rule Naming
|
||||
- Policy: `Policy-<AppName>`
|
||||
- Rules: descriptive action-first names, e.g. `Allow-HTTPS-Web`, `Deny-All`
|
||||
|
||||
## Prerequisites
|
||||
- Python 3.10+
|
||||
- `requests` library
|
||||
- NSX Manager credentials with appropriate RBAC permissions
|
||||
|
||||
## Usage
|
||||
|
||||
Each blueprint directory contains its own `README.md` with application-specific setup and run instructions.
|
||||
|
||||
```bash
|
||||
pip install -r requirements.txt
|
||||
python epic/deploy.py --nsx-manager <IP> --username <user> --password <pass>
|
||||
```
|
||||
@@ -0,0 +1,82 @@
|
||||
# [AppName] — NSX Security Blueprint Template
|
||||
|
||||
Generic template for creating NSX tags, security groups, and a Distributed Firewall (DFW) policy for a new application. Copy this directory and replace `[AppName]` throughout.
|
||||
|
||||
## Application Overview
|
||||
|
||||
_Describe the application, its role in the environment, and the tiers that need to be segmented._
|
||||
|
||||
## Tiers & Tags
|
||||
|
||||
| Tag | Scope | Purpose |
|
||||
|---|---|---|
|
||||
| `[AppName]\|Web` | `AppName` | Web / presentation tier |
|
||||
| `[AppName]\|App` | `AppName` | Application tier |
|
||||
| `[AppName]\|DB` | `AppName` | Database tier |
|
||||
|
||||
_Add or remove tiers as needed._
|
||||
|
||||
## Security Groups
|
||||
|
||||
| Group | Membership Criteria | Purpose |
|
||||
|---|---|---|
|
||||
| `SG-[AppName]-Web` | Tag: `[AppName]\|Web` | Web-tier VMs |
|
||||
| `SG-[AppName]-App` | Tag: `[AppName]\|App` | Application-tier VMs |
|
||||
| `SG-[AppName]-DB` | Tag: `[AppName]\|DB` | Database-tier VMs |
|
||||
| `SG-[AppName]-All` | All groups above | All app workloads — used in lockdown rule |
|
||||
|
||||
## DFW Policy: `Policy-[AppName]`
|
||||
|
||||
| # | Rule Name | Source | Destination | Service | Action | Applied To |
|
||||
|---|---|---|---|---|---|---|
|
||||
| 1 | Allow-HTTPS-Web | Any | SG-[AppName]-Web | HTTPS (443) | Allow | DFW |
|
||||
| 2 | Allow-MSSQL-DB | SG-[AppName]-App | SG-[AppName]-DB | MSSQL (1433) | Allow | DFW |
|
||||
| 3 | Allow-SSH-DB | SG-[AppName]-Mgmt | SG-[AppName]-DB | SSH (22) | Allow | DFW |
|
||||
| 4 | Lockdown-[AppName] | Any | SG-[AppName]-All | Any | Deny | SG-[AppName]-All |
|
||||
|
||||
> **Lockdown rule** (last rule): set **Applied To** to `SG-[AppName]-All` so the deny is scoped to this application's workloads only and does not affect other traffic on the DFW.
|
||||
|
||||
## Infrastructure Policy
|
||||
|
||||
An infrastructure-category policy (`Policy-Infra-[AppName]`) should be used for cross-cutting concerns such as:
|
||||
- DNS / NTP access from app workloads
|
||||
- AD/LDAP access
|
||||
- Monitoring and backup agent traffic
|
||||
- Syslog forwarding
|
||||
|
||||
_This policy lives under the **Infrastructure** DFW category and is documented separately._
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
_template/
|
||||
├── README.md
|
||||
├── deploy.py # Main entry point — orchestrates tags, groups, policy
|
||||
├── tags.py # Tag creation logic
|
||||
├── security_groups.py # Security group creation logic
|
||||
└── policy.py # DFW policy and rule creation logic
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python <appname>/deploy.py \
|
||||
--nsx-manager <IP_OR_FQDN> \
|
||||
--username <admin_user> \
|
||||
--password <password>
|
||||
```
|
||||
|
||||
### Optional flags
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--dry-run` | False | Print planned changes without applying them |
|
||||
| `--verify-ssl` | True | Disable with `--no-verify-ssl` for lab environments |
|
||||
|
||||
## Customization Checklist
|
||||
|
||||
- [ ] Replace all `[AppName]` placeholders
|
||||
- [ ] Add/remove tiers to match actual application architecture
|
||||
- [ ] Adjust services/ports in the policy table
|
||||
- [ ] Define which group gets SSH admin access (Rule 3 source)
|
||||
- [ ] Review lockdown rule — confirm Applied To is correct
|
||||
- [ ] Add infrastructure policy rules as needed
|
||||
@@ -0,0 +1,64 @@
|
||||
# EPIC EHR — NSX Security Blueprint
|
||||
|
||||
Automates NSX tags, security groups, and Distributed Firewall (DFW) policy for an EPIC Electronic Health Records deployment.
|
||||
|
||||
## Application Overview
|
||||
|
||||
EPIC is a multi-tier healthcare EHR platform. This blueprint segments the EPIC workloads into distinct security zones using NSX micro-segmentation.
|
||||
|
||||
## Tiers & Tags
|
||||
|
||||
| Tag | Scope | Purpose |
|
||||
|---|---|---|
|
||||
| `EPIC\|Web` | `AppName` | EPIC web/presentation tier |
|
||||
| `EPIC\|App` | `AppName` | EPIC application tier |
|
||||
| `EPIC\|DB` | `AppName` | EPIC database tier |
|
||||
| `EPIC\|Mgmt` | `AppName` | EPIC management/Hyperspace servers |
|
||||
|
||||
## Security Groups
|
||||
|
||||
| Group | Membership Criteria | Purpose |
|
||||
|---|---|---|
|
||||
| `SG-EPIC-Web` | Tag: `EPIC\|Web` | Web-tier VMs |
|
||||
| `SG-EPIC-App` | Tag: `EPIC\|App` | Application-tier VMs |
|
||||
| `SG-EPIC-DB` | Tag: `EPIC\|DB` | Database-tier VMs |
|
||||
| `SG-EPIC-Mgmt` | Tag: `EPIC\|Mgmt` | Management/Hyperspace VMs |
|
||||
| `SG-EPIC-All` | Tag: `EPIC\|*` (all above) | All EPIC workloads — used in lockdown rules |
|
||||
|
||||
## DFW Policy: `Policy-EPIC`
|
||||
|
||||
| # | Rule Name | Source | Destination | Service | Action |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Allow-HTTPS-Web | Any | SG-EPIC-Web | HTTPS (443) | Allow |
|
||||
| 2 | Allow-App-to-DB | SG-EPIC-App | SG-EPIC-DB | MSSQL (1433) | Allow |
|
||||
| 3 | Allow-SSH-DB | SG-EPIC-Mgmt | SG-EPIC-DB | SSH (22) | Allow |
|
||||
| 4 | Allow-Web-to-App | SG-EPIC-Web | SG-EPIC-App | HTTP/HTTPS | Allow |
|
||||
| 5 | Lockdown-EPIC | Any | SG-EPIC-All | Any | Deny |
|
||||
|
||||
> Rule 5 (Lockdown) has **Applied To** set to `SG-EPIC-All` to scope the deny to EPIC workloads only.
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
epic/
|
||||
├── README.md
|
||||
├── deploy.py # Main entry point — orchestrates tags, groups, policy
|
||||
├── tags.py # Tag creation logic
|
||||
├── security_groups.py # Security group creation logic
|
||||
└── policy.py # DFW policy and rule creation logic
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python epic/deploy.py \
|
||||
--nsx-manager <IP_OR_FQDN> \
|
||||
--username <admin_user> \
|
||||
--password <password>
|
||||
```
|
||||
|
||||
### Optional flags
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--dry-run` | False | Print planned changes without applying them |
|
||||
| `--verify-ssl` | True | Disable with `--no-verify-ssl` for lab environments |
|
||||
@@ -0,0 +1,74 @@
|
||||
# Omnissa Horizon View — NSX Security Blueprint
|
||||
|
||||
Automates NSX tags, security groups, and Distributed Firewall (DFW) policy for an Omnissa Horizon View (formerly VMware Horizon) VDI deployment.
|
||||
|
||||
## Application Overview
|
||||
|
||||
Omnissa Horizon View provides virtual desktop and published application delivery. This blueprint segments the Horizon infrastructure and desktop pools using NSX micro-segmentation.
|
||||
|
||||
## Tiers & Tags
|
||||
|
||||
| Tag | Scope | Purpose |
|
||||
|---|---|---|
|
||||
| `Horizon\|ConnectionServer` | `AppName` | Horizon Connection Servers |
|
||||
| `Horizon\|EnrollmentServer` | `AppName` | Enrollment/True SSO servers |
|
||||
| `Horizon\|UAG` | `AppName` | Unified Access Gateways (external access) |
|
||||
| `Horizon\|Composer` | `AppName` | Horizon Composer / Instant Clone domain join servers |
|
||||
| `Horizon\|VDI` | `AppName` | Virtual desktop pool VMs |
|
||||
| `Horizon\|RDSH` | `AppName` | Published application / RDSH session hosts |
|
||||
| `Horizon\|Mgmt` | `AppName` | Horizon management / admin jump hosts |
|
||||
|
||||
## Security Groups
|
||||
|
||||
| Group | Membership Criteria | Purpose |
|
||||
|---|---|---|
|
||||
| `SG-Horizon-ConnectionServer` | Tag: `Horizon\|ConnectionServer` | Connection Server VMs |
|
||||
| `SG-Horizon-EnrollmentServer` | Tag: `Horizon\|EnrollmentServer` | Enrollment Server VMs |
|
||||
| `SG-Horizon-UAG` | Tag: `Horizon\|UAG` | Unified Access Gateway VMs |
|
||||
| `SG-Horizon-Composer` | Tag: `Horizon\|Composer` | Composer / IC join VMs |
|
||||
| `SG-Horizon-VDI` | Tag: `Horizon\|VDI` | Virtual desktop VMs |
|
||||
| `SG-Horizon-RDSH` | Tag: `Horizon\|RDSH` | RDSH session host VMs |
|
||||
| `SG-Horizon-Mgmt` | Tag: `Horizon\|Mgmt` | Management / admin VMs |
|
||||
| `SG-Horizon-All` | All groups above | All Horizon workloads — used in lockdown rules |
|
||||
|
||||
## DFW Policy: `Policy-Horizon`
|
||||
|
||||
| # | Rule Name | Source | Destination | Service | Action |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Allow-HTTPS-UAG | Any | SG-Horizon-UAG | HTTPS (443) | Allow |
|
||||
| 2 | Allow-Blast-UAG | Any | SG-Horizon-UAG | Blast (8443, 443) | Allow |
|
||||
| 3 | Allow-UAG-to-CS | SG-Horizon-UAG | SG-Horizon-ConnectionServer | HTTPS (443) | Allow |
|
||||
| 4 | Allow-Client-to-CS | Any | SG-Horizon-ConnectionServer | HTTPS (443), Blast (8443) | Allow |
|
||||
| 5 | Allow-CS-to-VDI | SG-Horizon-ConnectionServer | SG-Horizon-VDI | Blast (22443), PCoIP (4172) | Allow |
|
||||
| 6 | Allow-CS-to-RDSH | SG-Horizon-ConnectionServer | SG-Horizon-RDSH | Blast (22443), RDP (3389) | Allow |
|
||||
| 7 | Allow-SSH-Mgmt | SG-Horizon-Mgmt | SG-Horizon-All | SSH (22) | Allow |
|
||||
| 8 | Allow-Enrollment-CS | SG-Horizon-ConnectionServer | SG-Horizon-EnrollmentServer | HTTPS (443) | Allow |
|
||||
| 9 | Lockdown-Horizon | Any | SG-Horizon-All | Any | Deny |
|
||||
|
||||
> Rule 9 (Lockdown) has **Applied To** set to `SG-Horizon-All` to scope the deny to Horizon workloads only.
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
horizon_view/
|
||||
├── README.md
|
||||
├── deploy.py # Main entry point — orchestrates tags, groups, policy
|
||||
├── tags.py # Tag creation logic
|
||||
├── security_groups.py # Security group creation logic
|
||||
└── policy.py # DFW policy and rule creation logic
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
python horizon_view/deploy.py \
|
||||
--nsx-manager <IP_OR_FQDN> \
|
||||
--username <admin_user> \
|
||||
--password <password>
|
||||
```
|
||||
|
||||
### Optional flags
|
||||
| Flag | Default | Description |
|
||||
|---|---|---|
|
||||
| `--dry-run` | False | Print planned changes without applying them |
|
||||
| `--verify-ssl` | True | Disable with `--no-verify-ssl` for lab environments |
|
||||
@@ -0,0 +1,94 @@
|
||||
# Infrastructure — NSX Security Blueprint
|
||||
|
||||
Automates NSX security groups and DFW policies for shared infrastructure services used across all application blueprints. Lives under the NSX **Infrastructure** DFW category.
|
||||
|
||||
## Scope
|
||||
|
||||
Infrastructure groups and policies cover cross-cutting services that every application needs to reach — DNS, NTP, Active Directory, monitoring, backup, syslog, etc. By placing these rules in the **Infrastructure** category they evaluate before application-level policies and remain centrally managed.
|
||||
|
||||
## Tag Convention
|
||||
|
||||
| Scope | Value | Purpose |
|
||||
|---|---|---|
|
||||
| `Infra` | `DNS Server` | Authoritative / recursive DNS servers |
|
||||
| `Infra` | `NTP Server` | NTP time sources |
|
||||
| `Infra` | `Domain Controller` | Active Directory Domain Controllers |
|
||||
|
||||
Apply these tags to VMs in NSX (or via vCenter tag sync) so that new servers are automatically picked up by the dynamic group membership criteria.
|
||||
|
||||
## Security Groups
|
||||
|
||||
Managed by `security_groups.py`. Each group uses a **union** of three member sources so the groups can be built up incrementally:
|
||||
|
||||
| Group | Dynamic (Tag) | Static IPs | Explicit VMs |
|
||||
|---|---|---|---|
|
||||
| `SG-Infra-DNS-Servers` | `Infra:DNS Server` | ✓ | ✓ |
|
||||
| `SG-Infra-NTP-Servers` | `Infra:NTP Server` | ✓ | ✓ |
|
||||
| `SG-Infra-Domain-Controllers` | `Infra:Domain Controller` | ✓ | ✓ |
|
||||
|
||||
> The `GROUP_PREFIX` (`SG-Infra-`) is configurable at the top of each script.
|
||||
|
||||
## DFW Policy: `Policy-Infra`
|
||||
|
||||
_Defined in `policy.py` — coming soon._
|
||||
|
||||
Planned rules (Infrastructure category, evaluated before application policies):
|
||||
|
||||
| # | Rule Name | Source | Destination | Service | Action |
|
||||
|---|---|---|---|---|---|
|
||||
| 1 | Allow-DNS-UDP | Any | SG-Infra-DNS-Servers | DNS/UDP (53) | Allow |
|
||||
| 2 | Allow-DNS-TCP | Any | SG-Infra-DNS-Servers | DNS/TCP (53) | Allow |
|
||||
| 3 | Allow-NTP | Any | SG-Infra-NTP-Servers | NTP/UDP (123) | Allow |
|
||||
| 4 | Allow-LDAP | Any | SG-Infra-Domain-Controllers | LDAP (389), LDAPS (636) | Allow |
|
||||
| 5 | Allow-Kerberos | Any | SG-Infra-Domain-Controllers | Kerberos (88/UDP+TCP) | Allow |
|
||||
| 6 | Allow-SMB-DC | Any | SG-Infra-Domain-Controllers | SMB (445) | Allow |
|
||||
|
||||
## Files
|
||||
|
||||
```
|
||||
infra/
|
||||
├── README.md
|
||||
├── security_groups.py # Creates/updates infrastructure security groups
|
||||
└── policy.py # DFW policy and rules (coming soon)
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
### Prerequisites
|
||||
```bash
|
||||
pip install requests
|
||||
```
|
||||
|
||||
### Populate member data
|
||||
Open `security_groups.py` and edit the `GROUPS` dictionary:
|
||||
- `ip_addresses` — static IPs or CIDRs for servers not yet tagged
|
||||
- `vm_ext_ids` — vCenter MoRef IDs (e.g. `"vm-1042"`) for explicit VM membership
|
||||
- `tag_value` — already set; drives dynamic membership via NSX tag conditions
|
||||
|
||||
### Dry run (no changes)
|
||||
```bash
|
||||
python infra/security_groups.py \
|
||||
--nsx-manager <IP_OR_FQDN> \
|
||||
--username admin \
|
||||
--password <password> \
|
||||
--dry-run
|
||||
```
|
||||
|
||||
### Apply
|
||||
```bash
|
||||
python infra/security_groups.py \
|
||||
--nsx-manager <IP_OR_FQDN> \
|
||||
--username admin \
|
||||
--password <password>
|
||||
```
|
||||
|
||||
### Lab / self-signed cert environments
|
||||
Add `--no-verify-ssl` to either command above.
|
||||
|
||||
## Customization
|
||||
|
||||
| Variable | Location | Default | Purpose |
|
||||
|---|---|---|---|
|
||||
| `GROUP_PREFIX` | top of `security_groups.py` | `SG-Infra-` | Prefix on all group names and IDs |
|
||||
| `TAG_SCOPE` | top of `security_groups.py` | `Infra` | NSX tag scope for infrastructure tags |
|
||||
| `DOMAIN` | top of `security_groups.py` | `default` | NSX Policy domain |
|
||||
@@ -0,0 +1,266 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
NSX Infrastructure Security Groups
|
||||
Creates or updates NSX security groups for shared infrastructure servers.
|
||||
|
||||
Edit the CONFIGURATION section below before running, then:
|
||||
python infra/security_groups.py --nsx-manager <IP> --username admin --password <pass>
|
||||
|
||||
Add --dry-run to preview the API payloads without making any changes.
|
||||
"""
|
||||
|
||||
import argparse
|
||||
import json
|
||||
import sys
|
||||
import urllib3
|
||||
import requests
|
||||
from typing import Any
|
||||
|
||||
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
|
||||
|
||||
# ── CONFIGURATION ──────────────────────────────────────────────────────────────
|
||||
|
||||
# Prefix applied to every group's display name and ID.
|
||||
# Change this to match your environment's naming standard.
|
||||
GROUP_PREFIX = "SG-Infra-"
|
||||
|
||||
# NSX tag scope used for all infrastructure server tags.
|
||||
# Tag format: scope=TAG_SCOPE, value=<server_type> e.g. scope="Infra", value="DNS Server"
|
||||
TAG_SCOPE = "Infra"
|
||||
|
||||
# NSX Policy domain. "default" is correct for most environments.
|
||||
DOMAIN = "default"
|
||||
|
||||
# Group definitions.
|
||||
#
|
||||
# Each entry key becomes part of the group ID (URL-safe, no spaces).
|
||||
# Fields:
|
||||
# display_name : suffix appended to GROUP_PREFIX → "SG-Infra-DNS-Servers"
|
||||
# tag_value : tag value (under TAG_SCOPE) that dynamically adds matching VMs
|
||||
# ip_addresses : static IPs or CIDR ranges to include (list of strings)
|
||||
# vm_ext_ids : vCenter VM External IDs / MoRefs to include (list of strings)
|
||||
# Find these in vCenter (e.g. "vm-1042") or via the NSX VM inventory API.
|
||||
#
|
||||
# Members from all three sources are OR'd together in the group expression.
|
||||
|
||||
GROUPS: dict[str, dict[str, Any]] = {
|
||||
"DNS": {
|
||||
"display_name": "DNS-Servers",
|
||||
"tag_value": "DNS Server",
|
||||
"ip_addresses": [
|
||||
# "192.168.10.53",
|
||||
# "192.168.10.54",
|
||||
],
|
||||
"vm_ext_ids": [
|
||||
# "vm-1001",
|
||||
],
|
||||
},
|
||||
"NTP": {
|
||||
"display_name": "NTP-Servers",
|
||||
"tag_value": "NTP Server",
|
||||
"ip_addresses": [
|
||||
# "192.168.10.123",
|
||||
# "192.168.10.124",
|
||||
],
|
||||
"vm_ext_ids": [
|
||||
# "vm-1002",
|
||||
],
|
||||
},
|
||||
"DC": {
|
||||
"display_name": "Domain-Controllers",
|
||||
"tag_value": "Domain Controller",
|
||||
"ip_addresses": [
|
||||
# "192.168.10.10",
|
||||
# "192.168.10.11",
|
||||
],
|
||||
"vm_ext_ids": [
|
||||
# "vm-1003",
|
||||
# "vm-1004",
|
||||
],
|
||||
},
|
||||
}
|
||||
|
||||
# ── END CONFIGURATION ──────────────────────────────────────────────────────────
|
||||
|
||||
|
||||
def group_id(key: str) -> str:
|
||||
"""Derive a stable, URL-safe NSX group ID from the config key and prefix."""
|
||||
prefix = GROUP_PREFIX.rstrip("-").replace(" ", "-")
|
||||
return f"{prefix}-{key}"
|
||||
|
||||
|
||||
def build_expressions(cfg: dict[str, Any]) -> list[dict[str, Any]]:
|
||||
"""
|
||||
Build the NSX Policy expression list for a group.
|
||||
|
||||
Each source type (IPs, tag-matched VMs, explicit VMs) is OR'd together.
|
||||
Tag matching uses a NestedExpression to enforce both scope AND value so
|
||||
that tags from other scopes with the same value are not inadvertently included.
|
||||
|
||||
Expression order matters in the NSX API — the ConjunctionOperator must sit
|
||||
between two non-operator expressions; the first expression must never be
|
||||
a ConjunctionOperator.
|
||||
"""
|
||||
expressions: list[dict[str, Any]] = []
|
||||
|
||||
def _or():
|
||||
"""Append an OR separator between expression blocks."""
|
||||
if expressions:
|
||||
expressions.append({
|
||||
"resource_type": "ConjunctionOperator",
|
||||
"conjunction_operator": "OR",
|
||||
})
|
||||
|
||||
# ── Static IP addresses / CIDRs ──────────────────────────────────────────
|
||||
ip_list = [ip for ip in cfg.get("ip_addresses", []) if ip]
|
||||
if ip_list:
|
||||
_or()
|
||||
expressions.append({
|
||||
"resource_type": "IPAddressExpression",
|
||||
"ip_addresses": ip_list,
|
||||
})
|
||||
|
||||
# ── Dynamic tag membership (scope=TAG_SCOPE AND value=tag_value) ─────────
|
||||
# NestedExpression combines two Condition objects with AND:
|
||||
# Condition 1 — matches the tag SCOPE field (scope_operator triggers this)
|
||||
# Condition 2 — matches the tag VALUE field
|
||||
tag_value = cfg.get("tag_value", "").strip()
|
||||
if tag_value:
|
||||
_or()
|
||||
expressions.append({
|
||||
"resource_type": "NestedExpression",
|
||||
"expressions": [
|
||||
{
|
||||
"resource_type": "Condition",
|
||||
"member_type": "VirtualMachine",
|
||||
"key": "Tag",
|
||||
"operator": "EQUALS",
|
||||
"value": TAG_SCOPE,
|
||||
# scope_operator tells NSX to match this Condition against
|
||||
# the tag's scope field instead of the tag's value field.
|
||||
"scope_operator": "EQUALS",
|
||||
},
|
||||
{
|
||||
"resource_type": "ConjunctionOperator",
|
||||
"conjunction_operator": "AND",
|
||||
},
|
||||
{
|
||||
"resource_type": "Condition",
|
||||
"member_type": "VirtualMachine",
|
||||
"key": "Tag",
|
||||
"operator": "EQUALS",
|
||||
"value": tag_value,
|
||||
},
|
||||
],
|
||||
})
|
||||
|
||||
# ── Explicit VMs by vCenter External ID / MoRef ──────────────────────────
|
||||
ext_ids = [v for v in cfg.get("vm_ext_ids", []) if v]
|
||||
if ext_ids:
|
||||
_or()
|
||||
expressions.append({
|
||||
"resource_type": "ExternalIDExpression",
|
||||
"member_type": "VirtualMachine",
|
||||
"external_ids": ext_ids,
|
||||
})
|
||||
|
||||
return expressions
|
||||
|
||||
|
||||
def build_group_payload(key: str, cfg: dict[str, Any]) -> dict[str, Any]:
|
||||
"""Assemble the full NSX Policy group PATCH body."""
|
||||
expressions = build_expressions(cfg)
|
||||
if not expressions:
|
||||
raise ValueError(
|
||||
f"Group '{key}' has no members defined "
|
||||
"(add ip_addresses, tag_value, or vm_ext_ids in CONFIGURATION)."
|
||||
)
|
||||
|
||||
return {
|
||||
"id": group_id(key),
|
||||
"display_name": f"{GROUP_PREFIX}{cfg['display_name']}",
|
||||
"description": (
|
||||
f"Infrastructure {cfg['display_name'].replace('-', ' ')} — "
|
||||
f"managed by nsx_blueprints/infra/security_groups.py"
|
||||
),
|
||||
"expression": expressions,
|
||||
}
|
||||
|
||||
|
||||
def patch_group(
|
||||
session: requests.Session,
|
||||
base_url: str,
|
||||
key: str,
|
||||
payload: dict[str, Any],
|
||||
dry_run: bool,
|
||||
) -> None:
|
||||
url = (
|
||||
f"{base_url}/policy/api/v1/infra/domains/{DOMAIN}/groups/{group_id(key)}"
|
||||
)
|
||||
|
||||
print(f"\n{'[DRY RUN] ' if dry_run else ''}Group: {payload['display_name']}")
|
||||
print(f" URL : PATCH {url}")
|
||||
print(f" Body: {json.dumps(payload, indent=4)}")
|
||||
|
||||
if dry_run:
|
||||
return
|
||||
|
||||
resp = session.patch(url, json=payload)
|
||||
if resp.status_code in (200, 201):
|
||||
print(f" ✓ {resp.status_code} — group created/updated successfully.")
|
||||
else:
|
||||
print(f" ✗ {resp.status_code} — {resp.text}", file=sys.stderr)
|
||||
resp.raise_for_status()
|
||||
|
||||
|
||||
def build_session(username: str, password: str, verify_ssl: bool) -> requests.Session:
|
||||
s = requests.Session()
|
||||
s.auth = (username, password)
|
||||
s.verify = verify_ssl
|
||||
s.headers.update({"Content-Type": "application/json"})
|
||||
return s
|
||||
|
||||
|
||||
def parse_args() -> argparse.Namespace:
|
||||
p = argparse.ArgumentParser(
|
||||
description="Create/update NSX infrastructure security groups."
|
||||
)
|
||||
p.add_argument("--nsx-manager", required=True, metavar="HOST",
|
||||
help="NSX Manager IP or FQDN (e.g. 192.168.1.10)")
|
||||
p.add_argument("--username", required=True,
|
||||
help="NSX Manager username")
|
||||
p.add_argument("--password", required=True,
|
||||
help="NSX Manager password")
|
||||
p.add_argument("--dry-run", action="store_true",
|
||||
help="Print payloads without calling the API")
|
||||
p.add_argument("--no-verify-ssl", action="store_true",
|
||||
help="Disable SSL certificate verification (useful in lab environments)")
|
||||
return p.parse_args()
|
||||
|
||||
|
||||
def main() -> None:
|
||||
args = parse_args()
|
||||
base_url = f"https://{args.nsx_manager.rstrip('/')}"
|
||||
session = build_session(args.username, args.password, not args.no_verify_ssl)
|
||||
|
||||
errors: list[str] = []
|
||||
for key, cfg in GROUPS.items():
|
||||
try:
|
||||
payload = build_group_payload(key, cfg)
|
||||
patch_group(session, base_url, key, payload, args.dry_run)
|
||||
except ValueError as exc:
|
||||
print(f" ⚠ Skipping '{key}': {exc}")
|
||||
except requests.HTTPError as exc:
|
||||
errors.append(f"{key}: {exc}")
|
||||
|
||||
if errors:
|
||||
print("\nErrors encountered:", file=sys.stderr)
|
||||
for err in errors:
|
||||
print(f" - {err}", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
print("\nDone." if not args.dry_run else "\nDry run complete — no changes were made.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,14 @@
|
||||
# Shared Utilities
|
||||
|
||||
Common modules used across all NSX blueprints.
|
||||
|
||||
## Planned Modules
|
||||
|
||||
| File | Purpose |
|
||||
|---|---|
|
||||
| `nsx_client.py` | Authenticated `requests` wrapper for NSX Manager REST API |
|
||||
| `constants.py` | Shared service definitions, port numbers, category names |
|
||||
| `models.py` | Dataclasses for Tag, SecurityGroup, Rule, Policy |
|
||||
| `utils.py` | Helpers: retry logic, response validation, ID resolution |
|
||||
|
||||
These modules are imported by each blueprint's `tags.py`, `security_groups.py`, and `policy.py`.
|
||||
Reference in new issue
Block a user