Files
proxmox/scripts/unifi/create-firewall-rules.sh
defiQUG b3a8fe4496
Some checks failed
Deploy to Phoenix / deploy (push) Has been cancelled
chore: sync all changes to Gitea
- Config, docs, scripts, and backup manifests
- Submodule refs unchanged (m = modified content in submodules)

Made-with: Cursor
2026-03-02 11:37:34 -08:00

219 lines
5.4 KiB
Bash
Executable File

#!/usr/bin/env bash
set -euo pipefail
# Create firewall rules via UniFi Network API
# This script creates ACL rules for network segmentation and security
set -e
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
cd "$PROJECT_ROOT"
# Load UNIFI_* from repo .env, unifi-api/.env, or ~/.env
if [ -f "$PROJECT_ROOT/.env" ]; then
set -a && source "$PROJECT_ROOT/.env" 2>/dev/null && set +a
fi
if [ -f "$PROJECT_ROOT/unifi-api/.env" ]; then
set -a && source "$PROJECT_ROOT/unifi-api/.env" 2>/dev/null && set +a
fi
if [ -f ~/.env ]; then
source <(grep "^UNIFI_" ~/.env 2>/dev/null | sed 's/^/export /') 2>/dev/null || true
fi
UDM_URL="${UNIFI_UDM_URL:-https://192.168.0.1}"
API_KEY="${UNIFI_API_KEY}"
SITE_ID="88f7af54-98f8-306a-a1c7-c9349722b1f6"
if [ -z "$API_KEY" ]; then
echo "❌ UNIFI_API_KEY not set in environment"
exit 1
fi
echo "Creating Firewall Rules via API"
echo "=================================="
echo ""
echo "UDM URL: $UDM_URL"
echo "Site ID: $SITE_ID"
echo ""
# Get network IDs
echo "Fetching network IDs..."
NETWORKS_JSON=$(curl -k -s -X GET "$UDM_URL/proxy/network/integration/v1/sites/$SITE_ID/networks" \
-H "X-API-KEY: $API_KEY" \
-H 'Accept: application/json')
# Extract network IDs using Python
NETWORK_IDS=$(python3 << 'PYEOF'
import sys, json
data = json.load(sys.stdin)
networks = data.get('data', [])
vlan_map = {}
for net in networks:
vlan_id = net.get('vlanId')
if vlan_id and vlan_id > 1:
vlan_map[vlan_id] = net.get('id')
# Key VLANs we need
key_vlans = {
11: 'MGMT-LAN',
110: 'BESU-VAL',
111: 'BESU-SEN',
112: 'BESU-RPC',
120: 'BLOCKSCOUT',
121: 'CACTI',
130: 'CCIP-OPS',
132: 'CCIP-COMMIT',
133: 'CCIP-EXEC',
134: 'CCIP-RMN',
140: 'FABRIC',
141: 'FIREFLY',
150: 'INDY',
160: 'SANKOFA-SVC',
200: 'PHX-SOV-SMOM',
201: 'PHX-SOV-ICCC',
202: 'PHX-SOV-DBIS',
203: 'PHX-SOV-AR'
}
# Export as shell variables
for vlan, name in key_vlans.items():
if vlan in vlan_map:
print(f"NETWORK_ID_VLAN{vlan}={vlan_map[vlan]}")
print(f"NETWORK_NAME_VLAN{vlan}={name}")
PYEOF
)
# Source the network IDs
eval "$NETWORK_IDS"
echo "✅ Network IDs loaded"
echo ""
# Function to create ACL rule
create_acl_rule() {
local name=$1
local description=$2
local action=$3
local index=$4
local source_networks=$5
local dest_networks=$6
local protocol=$7
echo "Creating rule: $name"
# Build source filter
if [ -n "$source_networks" ]; then
SOURCE_FILTER=$(python3 << PYEOF
import json
networks = "$source_networks".split()
network_ids = []
for net in networks:
var_name = f"NETWORK_ID_VLAN{net}"
import os
net_id = os.environ.get(var_name)
if net_id:
network_ids.append(net_id)
print(json.dumps({
"type": "NETWORK",
"networkIds": network_ids
}))
PYEOF
)
else
SOURCE_FILTER="null"
fi
# Build destination filter
if [ -n "$dest_networks" ]; then
DEST_FILTER=$(python3 << PYEOF
import json
networks = "$dest_networks".split()
network_ids = []
for net in networks:
var_name = f"NETWORK_ID_VLAN{net}"
import os
net_id = os.environ.get(var_name)
if net_id:
network_ids.append(net_id)
print(json.dumps({
"type": "NETWORK",
"networkIds": network_ids
}))
PYEOF
)
else
DEST_FILTER="null"
fi
# Build protocol filter
if [ -n "$protocol" ]; then
PROTOCOL_FILTER="[\"$protocol\"]"
else
PROTOCOL_FILTER="null"
fi
# Create rule JSON
RULE_JSON=$(python3 << PYEOF
import json, sys
source = json.loads('$SOURCE_FILTER') if '$SOURCE_FILTER' != 'null' else None
dest = json.loads('$DEST_FILTER') if '$DEST_FILTER' != 'null' else None
protocol = json.loads('$PROTOCOL_FILTER') if '$PROTOCOL_FILTER' != 'null' else None
rule = {
"type": "IPV4",
"enabled": True,
"name": "$name",
"description": "$description",
"action": "$action",
"index": $index,
"sourceFilter": source,
"destinationFilter": dest,
"protocolFilter": protocol,
"enforcingDeviceFilter": None
}
print(json.dumps(rule))
PYEOF
)
# Create the rule
RESPONSE=$(curl -k -s -w "\n%{http_code}" -X POST "$UDM_URL/proxy/network/integration/v1/sites/$SITE_ID/acl-rules" \
-H "X-API-KEY: $API_KEY" \
-H 'Content-Type: application/json' \
-H 'Accept: application/json' \
-d "$RULE_JSON")
HTTP_CODE=$(echo "$RESPONSE" | tail -n1)
RESPONSE_BODY=$(echo "$RESPONSE" | sed '$d')
if [ "$HTTP_CODE" = "201" ] || [ "$HTTP_CODE" = "200" ]; then
echo " ✅ Rule created successfully"
return 0
else
echo " ❌ Failed to create rule (HTTP $HTTP_CODE)"
echo " Response: $RESPONSE_BODY"
return 1
fi
}
# Create firewall rules
echo "Creating firewall rules..."
echo ""
# Rule 1: Block sovereign tenant inter-VLAN traffic (VLANs 200-203)
create_acl_rule \
"Block Sovereign Tenant East-West Traffic" \
"Deny traffic between sovereign tenant VLANs (200-203) for isolation" \
"BLOCK" \
100 \
"200 201 202 203" \
"200 201 202 203" \
""
echo ""
echo "✅ Firewall rule creation complete!"
echo ""
echo "Note: Additional rules (management access, monitoring) can be added"
echo " after verifying the API request format works correctly."