Initial commit

This commit is contained in:
brandon committed 2026-04-18 10:12:10 -05:00
1 parent 37a2659067
commit 2e3c012074
7 files changed
+646 -2

No files matched your search

+52 -2
View File
@@ -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>
```
+82
View File
@@ -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
+64
View File
@@ -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 |
+74
View File
@@ -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 |
+94
View File
@@ -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 |
+266
View File
@@ -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()
+14
View File
@@ -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`.