Skip to content

Firewall

The Firewall module is FreeSDN’s unified network-security surface. It handles firewall rule CRUD and reorder, NAT, VPN tunnels with live stats, and IDS/IPS for supported adapters. It also absorbs the former Gateway module, giving you gateway orchestration: designate one firewall as the site brain, assign network controllers as limbs, define canonical VLANs once, and distribute them everywhere.

You interact with the Firewall module through two separate worlds that are distinct by design:

  • FreeSDN’s own normalized tables - rules, NAT rules, VPN tunnels, and IDS alerts stored in the firewall schema. These are portable, org-scoped, appear in config backups, and are managed through the Pending Changes UI.
  • Live device reads and writes - proxied through vendor adapters via /api/v1/firewall/gateways/{id}/.... These talk directly to the connected OPNsense, pfSense, MikroTik, or OpenWRT device.

Adapter Tier Notes
OPNsense Production ; 13 feature domains including OSPF/BGP routing; gold-standard contract verified; deepest coverage
pfSense Production Shares OPNsense client plumbing; firewall, NAT, OpenVPN, IPsec, WireGuard
MikroTik (RouterOS v7) Production API-only access (no SSH/WinBox); 13 feature domains; 13 UI tabs; IPsec and L2TP/PPTP/SSTP
OpenWRT Preview / unaudited ubus/UCI client exists; the gold-standard contract (dual-gate, secret redaction, SSRF guard) has not been audited; do not deploy against production fleets

All Production adapters enforce:

  • Dual-gate writes (ADAPTER_READ_ONLY=false + force=true)
  • Tagged circuit-breaker
  • redact_secrets on every read (camelCase-aware; ~90 sensitive keys)
  • Tenant scoping + SSRF guard
  • Role gates on destructive operations

Gateway connections live at Firewall > Gateways in the UI, or via the API at /api/v1/firewall/gateways. Credentials are Fernet-encrypted at rest and never returned in plaintext; the detail endpoint returns a has_credentials: bool flag rather than the stored secret.

OPNsense uses API key + API secret. Generate a key in OPNsense at System > Access > Users, create a user with restricted privileges, then add the key here.

Terminal window
# 1. Create the gateway connection
curl -s -X POST https://<freesdn-host>/api/v1/firewall/gateways \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"name": "opn-prod",
"vendor": "opnsense",
"host": "opn.lan",
"port": 443,
"verify_ssl": false,
"site_id": "<site-uuid>",
"api_key": "<opnsense-key>",
"api_secret": "<opnsense-secret>"
}'
# 2. Test the saved connection
curl -s -X POST https://<freesdn-host>/api/v1/firewall/gateways/<gateway-id>/test \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>"
# 3. Trigger initial sync
curl -s -X POST https://<freesdn-host>/api/v1/firewall/gateways/<gateway-id>/sync \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{"full_sync": true}'

pfSense uses the same API key/secret credential shape as OPNsense with "vendor": "pfsense".

MikroTik uses username/password with "vendor": "mikrotik". The adapter communicates over the MikroTik REST API (RouterOS v7+ required - no SSH, no WinBox API).

Terminal window
curl -s -X POST https://<freesdn-host>/api/v1/firewall/gateways \
-H "Cookie: freesdn_access=<token>" \
-H "X-CSRF-Token: <csrf>" \
-H "Content-Type: application/json" \
-d '{
"name": "mt-core",
"vendor": "mikrotik",
"host": "mt.lan",
"port": 443,
"verify_ssl": false,
"site_id": "<site-uuid>",
"username": "freesdn-api",
"password": "<password>"
}'

You can test connectivity without persisting a connection:

Terminal window
# Requires: firewall.manage_rules
POST /api/v1/firewall/gateways/test
{ "vendor": "opnsense", "host": "opn.lan", "api_key": "...", "api_secret": "..." }

The saved-connection test endpoint (POST /gateways/{id}/test) also accepts an optional override body so the edit dialog can test edited-but-unsaved host/port/verify_ssl against stored credentials.


Every adapter-facing write goes through the staged dual-gate:

  1. ADAPTER_READ_ONLY must be false in your env file. New installations default to true.
  2. Each mutation must include force=true.

Until both gates pass, writes are staged to the local database and the live device is not touched. Review pending changes in the UI before applying.

SSRF protection is enforced on the gateway host field and every diagnostics target: loopback, link-local, cloud-metadata ranges (127.0.0.0/8, 169.254.0.0/16, ::1, fe80::/10, 0.0.0.0/8) and names (localhost, metadata.google.internal) are rejected at schema validation time, before any adapter call.


These endpoints manage FreeSDN’s own normalized rule rows in the firewall.rules table. They do not push to a live device automatically - use the gateway live-write endpoints or the distribution engine for that.

Method Path Purpose Permission
GET /api/v1/firewall/rules List rules - filter by device_id, action, is_enabled, site_id firewall.view
GET /api/v1/firewall/rules/{id} Get one rule firewall.view
POST /api/v1/firewall/rules Create rule firewall.manage_rules
PATCH /api/v1/firewall/rules/{id} Update rule (partial) firewall.manage_rules
DELETE /api/v1/firewall/rules/{id} Soft-delete rule firewall.manage_rules
POST /api/v1/firewall/rules/reorder Reorder rules for a device firewall.manage_rules

A rule record includes: source_address, source_port, source_zone, dest_address, dest_port, dest_zone, protocol (any/tcp/udp/icmp/…), action (allow / deny / reject / log), log_enabled, is_enabled, and rule_order. Note: schedule_id is not currently settable or returned via the REST API.

Supply the target device’s UUID and a complete ordered list of rule UUIDs:

Terminal window
POST /api/v1/firewall/rules/reorder?device_id=<device-uuid>
["<rule-uuid-1>", "<rule-uuid-2>", "<rule-uuid-3>"]

The service sets rule_order = 1, 2, 3, … across only the matching non-deleted rules for that device. Rules not in the list are not touched.

PATCH only applies whitelisted mutable fields. Non-whitelisted keys (such as device_id or hit_count) are silently ignored, not rejected.


NAT rules live in firewall.nat_rules. Types: snat, dnat, masquerade, redirect.

Method Path Purpose Permission
GET /api/v1/firewall/nat List NAT rules firewall.view
GET /api/v1/firewall/nat/{id} Get one NAT rule firewall.view
POST /api/v1/firewall/nat Create NAT rule firewall.manage_nat
PATCH /api/v1/firewall/nat/{id} Update NAT rule firewall.manage_nat
DELETE /api/v1/firewall/nat/{id} Soft-delete NAT rule firewall.manage_nat

For live port-forward and source-NAT operations directly on a connected device, use the gateway live-write endpoints (/gateways/{id}/port-forwards, /gateways/{id}/source-nat).


VPN tunnels live in firewall.vpn_tunnels. Types: ipsec, openvpn, wireguard, l2tp.

Method Path Purpose Permission
GET /api/v1/firewall/vpn List tunnels - filter by vpn_type, vpn_status firewall.view
GET /api/v1/firewall/vpn/stats Aggregate stats: total / up / down / error firewall.view
GET /api/v1/firewall/vpn/{id} Get one tunnel firewall.view
POST /api/v1/firewall/vpn Create tunnel firewall.manage_vpn
PATCH /api/v1/firewall/vpn/{id} Update tunnel firewall.manage_vpn
DELETE /api/v1/firewall/vpn/{id} Soft-delete tunnel firewall.manage_vpn
Type OPNsense pfSense MikroTik
IPsec (IKEv1/v2) Yes Yes Yes
OpenVPN Yes Yes -
WireGuard Yes Yes Staged (no UI tab yet)
L2TP / PPTP / SSTP - - Yes

For live IPsec connect/disconnect, WireGuard server/peer management, and OpenVPN session management, use the gateway live-write endpoints under /api/v1/firewall/gateways/{id}/ipsec/, /wireguard/, and /openvpn/.


FreeSDN tracks IDS alerts in firewall.ids_alerts (FreeSDN’s own table, populated by sync). Live IDS management goes through the gateway adapter.

Method Path Purpose Permission
GET /api/v1/firewall/ids/alerts Search alerts - filter by severity, time range, acknowledged, site_id firewall.view
GET /api/v1/firewall/ids/alerts/stats Alert counts by severity + unacknowledged count firewall.view
POST /api/v1/firewall/ids/alerts/{id}/acknowledge Acknowledge an alert firewall.manage_ids

The ids tab in the UI shows a badge with the unacknowledged count.

Method Path Purpose Permission
GET /api/v1/firewall/gateways/{id}/ids/settings Current IDS settings firewall.view
PUT /api/v1/firewall/gateways/{id}/ids/settings Update settings firewall.manage_rules
GET /api/v1/firewall/gateways/{id}/ids/alerts Live alerts (up to 5,000) firewall.view
DELETE /api/v1/firewall/gateways/{id}/ids/alerts Clear alert log firewall.manage_rules
GET /api/v1/firewall/gateways/{id}/ids/rulesets Rulesets (ET/Open, etc.) firewall.view
POST /api/v1/firewall/gateways/{id}/ids/rules/{sid}/toggle Toggle a rule by SID firewall.manage_rules
POST /api/v1/firewall/gateways/{id}/ids/control Start / stop / restart / update-rules firewall.manage_rules

OPNsense supports Suricata. When a critical signature fires, the health monitor emits a firewall.event.ids_critical Fabric event.

IDS mode is configurable per org in module settings: ids_mode = detect (log only) or prevent (block). Default is detect.


Traffic logs are stored in firewall.logs and scoped per device.

Method Path Purpose Permission
GET /api/v1/firewall/logs Search logs - filter by action, source_ip, dest_ip, time range firewall.view_logs

For a live streaming log from a connected device, use GET /api/v1/firewall/gateways/{id}/logs/stream (SSE StreamingResponse - long-lived connection).


Gateway connections - live device management

Section titled “Gateway connections - live device management”

The /api/v1/firewall/gateways/ family proxies directly to vendor adapters. These are the endpoints behind the GatewayDetailPage tabs in the UI (18 tabs for OPNsense/pfSense, 13 for MikroTik).

Method Path Purpose Permission
GET /api/v1/firewall/gateways List connections firewall.view
GET /api/v1/firewall/gateways/summary Aggregate online/offline/sync state counts firewall.view
GET /api/v1/firewall/gateways/{id} Get one connection (has_credentials bool, no raw cred) firewall.view
POST /api/v1/firewall/gateways Create connection firewall.manage_rules
PATCH /api/v1/firewall/gateways/{id} Update connection (evicts cached adapter) firewall.manage_rules
DELETE /api/v1/firewall/gateways/{id} Soft-delete (removes device-registry row) firewall.manage_rules
Method Path Purpose
GET /gateways/{id}/status Live system status; updates is_online / last_seen
GET /gateways/{id}/firewall-rules Live firewall rule list from device
GET /gateways/{id}/nat-rules Live NAT rules
GET /gateways/{id}/vpn Live VPN status (secrets redacted)
GET /gateways/{id}/interfaces Live interface list + statistics
GET /gateways/{id}/dhcp Live DHCP leases
GET /gateways/{id}/arp ARP table
GET /gateways/{id}/routes/table Kernel routing table
GET /gateways/{id}/health-check Multi-subsystem deep health (healthy bool)
GET /gateways/{id}/ha-status CARP / HA sync status

All paths above are relative to /api/v1/firewall. All require firewall.view.

Method Path Purpose Permission
POST /gateways/{id}/firewall-rules Push rule to device firewall.manage_rules
PUT /gateways/{id}/firewall-rules/{vendor_rule_id} Update vendor rule firewall.manage_rules
POST /gateways/{id}/firewall-rules/{vendor_rule_id}/toggle?enabled=<bool> Enable (?enabled=true, default) or disable (?enabled=false) a rule firewall.manage_rules
POST /gateways/{id}/port-forwards Create port-forward (DNAT) firewall.manage_rules
POST /gateways/{id}/source-nat Create SNAT rule firewall.manage_rules
POST /gateways/{id}/wireguard/servers Create WireGuard server firewall.manage_rules
POST /gateways/{id}/wireguard/peers Add WireGuard peer firewall.manage_rules
POST /gateways/{id}/openvpn/instances Create OpenVPN instance firewall.manage_rules
POST /gateways/{id}/ipsec/{vendor_id}/connect Bring IPsec tunnel up firewall.manage_rules
POST /gateways/{id}/ipsec/{vendor_id}/disconnect Tear IPsec tunnel down firewall.manage_rules
POST /gateways/{id}/routes/static Create static route firewall.manage_rules
POST /gateways/{id}/aliases Create alias (firewall object) firewall.manage_rules
POST /gateways/{id}/dns/overrides Create DNS host override firewall.manage_rules
POST /gateways/{id}/dhcp/static-mappings Create DHCP static mapping firewall.manage_rules
POST /gateways/{id}/services/{name}/control Start / stop / restart service firewall.manage_rules
POST /gateways/{id}/reboot Reboot device firewall.admin
POST /gateways/{id}/halt Halt device firewall.admin
POST /gateways/{id}/firmware/update Apply firmware update firewall.admin
GET /gateways/{id}/config/download Download running config controller:write

All diagnostics run on the remote device and require firewall.view:

Method Path Purpose
POST /gateways/{id}/diagnostics/ping Ping (1-20 packets)
POST /gateways/{id}/diagnostics/traceroute Traceroute
POST /gateways/{id}/diagnostics/dns-lookup DNS lookup
GET /gateways/{id}/diagnostics/connections Active PF state connections
GET /gateways/{id}/diagnostics/pf-info PF filter info

Diagnostics host fields are validated against the same SSRF allowlist as the gateway host field.


OPNsense is the most complete adapter with 13 independent domains, each accessible from the GatewayDetailPage under its own tab:

Domain UI tab Example endpoint prefix
Firewall rules rules /gateways/{id}/firewall-rules
NAT + port forwards nat /gateways/{id}/nat-rules, /port-forwards, /source-nat, /nat/onetoone
VPN (OpenVPN + IPsec + WireGuard) vpn /gateways/{id}/openvpn, /ipsec, /wireguard
Interfaces + VIPs + LAGGs interfaces /gateways/{id}/interfaces, /vlans, /virtual-ips, /laggs
DHCP (Kea DHCPv4/v6 + relay + static maps) dhcp /gateways/{id}/dhcp, /kea/dhcpv4, /kea/dhcpv6, /dhcp-relay
DNS (Unbound host/domain overrides) dns /gateways/{id}/dns/overrides, /dns/domain-overrides
Aliases (address + port groups) aliases /gateways/{id}/aliases
Routing (static + OSPF + BGP + ARP + NDP) routing /gateways/{id}/routes/static, /routes/table, /arp, /ndp
IDS/IPS (Suricata) ids /gateways/{id}/ids/...
Traffic shaper (pipes + queues + rules) shaper /gateways/{id}/shaper/pipes, /shaper/queues, /shaper/rules
Services (start/stop/restart) services /gateways/{id}/services
Backups + config diff backups /gateways/{id}/backups, /config/diff
System + firmware + monitoring system / monitoring /gateways/{id}/firmware, /monitoring/temperature, /monitoring/traffic

Additional read surfaces: HAProxy (/haproxy, /haproxy/servers, /haproxy/backends, /haproxy/frontends), ACME certificates (/acme, /acme/certificates), Tailscale (/tailscale), CrowdSec (/crowdsec), captive portal (/captive-portal), Telegraf, Monit, NetFlow, DynDNS, Syslog.


MikroTik requires RouterOS v7 and REST API access. The adapter communicates only over the RouterOS REST API - no SSH, no WinBox API.

Status Domains
UI tab available System, Interfaces, IP, DHCP, Firewall, DNS, VPN (L2TP/PPTP/SSTP), Hotspot, Queues, Firmware, Backup, Topology/Neighbors, SNMP
API-only (no UI tab yet) CAPsMAN, PPP/PPPoE, BGP/OSPF, IPsec/Security

Firmware lifecycle (channel check, download, install), config backup/restore, topology/neighbor discovery (/ip/neighbor with LLDP/CDP/MNDP dedup), and SNMPv3 user management each have a dedicated UI tab.


Orchestration is the multi-controller capability. You designate one gateway per site as the brain (the authoritative routing and VLAN authority) and one or more switch/AP controllers as limbs (Layer 2 devices that receive config from the brain). FreeSDN holds a canonical desired-state model and distributes it.

Layer Description
Layer 0 Controller-direct; always works; single-controller config push
Layer 1 Multi-controller VLAN visibility; alignment score; per-cell copy
Layer 2 Gateway orchestration; brain/limb roles; read-only brain; canonical VLAN distribution
Layer 3 Full write-to-brain orchestration is not available

The brain adapter is read-only by default in the orchestration context: FreeSDN reads config from it to populate canonical state but does not push arbitrary mutations back. Changes to the brain’s running config go through the gateway live-write endpoints, not orchestration.

The role map records which device is the brain and which are limbs for a site. Exactly one brain is required for orchestration to function; the validator enforces this.

Method Path Purpose Permission
GET /api/v1/firewall/topology/{site_id} Get role map (brain/limb assignments + authority_map) gateway.view
PUT /api/v1/firewall/topology/{site_id} Upsert role map gateway.manage_topology
DELETE /api/v1/firewall/topology/{site_id} Remove role map gateway.manage_topology
POST /api/v1/firewall/topology/{site_id}/validate Validate (exactly one brain, capability checks) gateway.manage_topology

The authority_map JSONB in the role map records per-resource authority defaults: vlan_interface, dhcp, dns, firewall_rule, nat, vpn default to brain; vlan_l2 defaults to FreeSDN; port_profile, ssid, poe default to limb.

A canonical VLAN is the site-wide desired state: one definition, independent of any specific controller. It lives in gateway.gw_canonical_vlans - separate from the per-controller VLAN records in network.vlans. You define it once, then distribute to any device that needs it.

Method Path Purpose Permission
GET /api/v1/firewall/vlans List canonical VLANs gateway.view
GET /api/v1/firewall/vlans/{id} VLAN detail (+ DHCP scope + reservations) gateway.view
POST /api/v1/firewall/vlans Create canonical VLAN gateway.manage_vlans
PATCH /api/v1/firewall/vlans/{id} Update VLAN gateway.manage_vlans
DELETE /api/v1/firewall/vlans/{id} Delete VLAN gateway.manage_vlans

Canonical DHCP scopes and reservations for a VLAN:

Method Path Permission
GET /api/v1/firewall/dhcp/scopes gateway.view
POST /api/v1/firewall/dhcp/scopes gateway.manage_dhcp
POST /api/v1/firewall/dhcp/reservations gateway.manage_dhcp
DELETE /api/v1/firewall/dhcp/reservations/{id} gateway.manage_dhcp

Canonical DNS overrides:

Method Path Permission
GET /api/v1/firewall/dns/records gateway.view
POST /api/v1/firewall/dns/records gateway.manage_dns
PATCH /api/v1/firewall/dns/records/{id} gateway.manage_dns
DELETE /api/v1/firewall/dns/records/{id} gateway.manage_dns

Templates are org-level blueprints for standard VLAN configurations (IoT network, guest VLAN, management VLAN, etc.). Apply a template to a site to instantiate a canonical VLAN from it.

Method Path Purpose Permission
GET /api/v1/firewall/templates List templates gateway.view
POST /api/v1/firewall/templates Create template gateway.manage_vlans
PATCH /api/v1/firewall/templates/{id} Update template gateway.manage_vlans
DELETE /api/v1/firewall/templates/{id} Delete template gateway.manage_vlans
POST /api/v1/firewall/templates/{id}/apply/{site_id} Instantiate template at site gateway.manage_vlans

The distribution engine pushes canonical VLANs to one or more devices at a site. It follows a Saga pattern: per-tier compensating rollback is available if a distribution fails partway through.

One distribution runs per site at a time - a DistributionLock row in the database prevents concurrent distributions. The lock auto-expires after ~5 minutes to recover from worker crashes.

Plan structure:

  1. Tier 0 prerequisites - brain + each limb verified reachable
  2. Tier 1 - L3 VLAN config pushed to brain
  3. Limb tiers - L2 VLAN config pushed to each limb in turn
Method Path Purpose Permission
GET /api/v1/firewall/distribution List distribution records gateway.view
GET /api/v1/firewall/distribution/{id} Detail (plan + per-step results) gateway.view
POST /api/v1/firewall/distribution/trigger Trigger distribution (vlan_id + site_id) gateway.distribute
POST /api/v1/firewall/distribution/{id}/retry Retry a failed distribution gateway.distribute
POST /api/v1/firewall/distribution/{id}/rollback Saga rollback gateway.distribute

FreeSDN polls connected brain devices every 15 minutes (configurable via drift_check_interval_minutes) and compares running config against canonical desired state. When a divergence is found it creates a DriftEvent.

Drift types: resource_missing, resource_modified, resource_added, suppression_violated, tag_removed. Severities: critical, warning, info.

Method Path Purpose Permission
GET /api/v1/firewall/drift/events List drift events (paginated) gateway.drift
GET /api/v1/firewall/drift/summary Counts by severity + pending/resolved gateway.drift
POST /api/v1/firewall/drift/check/{site_id} Run a drift check now (enqueues task) gateway.drift
POST /api/v1/firewall/drift/events/{id}/resolve Resolve: reapply, accept, or ignore gateway.drift
GET /api/v1/firewall/drift/suppressions List suppression rules gateway.drift
POST /api/v1/firewall/drift/suppressions Create suppression rule gateway.drift
DELETE /api/v1/firewall/drift/suppressions/{id} Deactivate suppression rule gateway.drift

Celery beat runs gateway.check_all_sites_drift every 15 minutes and gateway.sync_all_gateways every 5 minutes (both on the sync queue).

If you are adding an existing site to FreeSDN that already has config running on devices, use the import wizard. It reads the current running state from the brain and limbs and populates canonical objects from it.

The wizard runs as a 6-step session:

Step Name What happens
1 Discover Auto-discover devices at the site
2 Assign roles Submit { gateway_id: "brain" | "limb" } for each discovered device
3 Scan Full config pull from brain and all limbs
4 Reconcile Submit decisions per resource: adopt, skip, merge, or ignore
5 Distribute Push adopted resources to canonical state + devices
6 Verify Confirm actual device state matches canonical

Steps 2 and 4 require a POST to /import/{session_id}/step with a payload. Steps 1, 3, 5, and 6 are triggered automatically when the session advances.

Method Path Purpose Permission
POST /api/v1/firewall/import/start Start import session gateway.import
GET /api/v1/firewall/import/{id} Session state (current step + per-step payloads) gateway.import
POST /api/v1/firewall/import/{id}/step Advance wizard step gateway.import
POST /api/v1/firewall/import/{id}/cancel Cancel session gateway.import

For ongoing operations - after the initial import - you can re-import from the brain, check alignment, and distribute to limbs without using the wizard:

Method Path Purpose Permission
POST /api/v1/firewall/reconciliation/{site_id}/import Import VLAN interfaces from brain → create/update canonical (flags orphans) gateway.import
GET /api/v1/firewall/reconciliation/{site_id}/alignment Compare canonical vs actual device state gateway.view
POST /api/v1/firewall/reconciliation/{site_id}/distribute Push L2 VLAN config to limb devices gateway.distribute

The alignment endpoint returns per-resource status: aligned, missing, modified, extra, or error.

GET /api/v1/firewall/dashboard/overview returns a rollup: gateway counts, sites with orchestration, canonical VLAN count, and drift summary. The dashboard also exposes read-only imported snapshots of firewall rules, NAT rules, VPN tunnels, IDS events, interfaces, and DHCP leases from brain devices - these are cached snapshots for visibility, not live reads.


Settings are per-org, stored in JSONB, and configurable through the UI at Firewall > Settings.

Setting Type Default Description
default_policy allow | deny deny Default packet policy for new rules
log_blocked bool true Log blocked connections to firewall.logs (primary PostgreSQL)
ids_enabled bool true Enable IDS globally
ids_mode detect | prevent detect Detect (log) or prevent (block)
log_retention_days int 7-365 30 Firewall log retention
sync_interval_minutes int 1-1440 5 Gateway sync frequency
drift_check_interval_minutes int 5-1440 15 Drift check frequency
distribution_lock_ttl_seconds int 60-3600 300 Max time a distribution lock is held
auto_remediate_drift bool false Automatically push fixes for detected drift
import_retention_days int 1-365 90 Import session retention

Permission code Purpose Notes
firewall.view View rules, NAT, VPN, IDS alerts, logs, gateway status Gate for almost all GET routes
firewall.manage_rules Create/edit/delete rules; also gates gateway CRUD and most live writes Required for all write operations on gateway connections
firewall.manage_nat NAT rule CRUD (FreeSDN tables)
firewall.manage_vpn VPN tunnel CRUD (FreeSDN tables)
firewall.manage_ids Acknowledge IDS alerts (FreeSDN tables)
firewall.view_logs View traffic logs
firewall.manage_gateways Declared in manifest; not used by any route - grant firewall.manage_rules instead
firewall.admin Reboot / halt device; apply firmware update Not declared in the module manifest; must be in the global role catalog
controller:write Download running config Core-level permission; not in the module manifest
gateway.view View orchestration topology, canonical resources, drift
gateway.manage_topology Edit brain/limb role maps
gateway.manage_vlans Canonical VLAN + template CRUD
gateway.manage_dhcp DHCP scope and reservation CRUD
gateway.manage_dns DNS override CRUD
gateway.distribute Trigger distribution, retry, rollback
gateway.import Run brownfield import wizard and reconciliation import
gateway.drift View, resolve, and suppress drift events
gateway.diagnostics Run orchestration-tier diagnostics (ping, traceroute, backup, restart-service)

Both FirewallService and GatewayService enforce per-user site grants. When a user has site-limited access, the service filters by accessible_site_ids so a site-limited operator cannot see or modify firewall devices or gateway connections outside their assigned sites.


The Firewall module participates in the Fabric (universal app-interconnect) as both a source of operations and an emitter of events.

ID Tier Description Permission
firewall.search_alerts Native Recent IDS/IPS + security alerts (1-200 results, org-scoped) firewall.view_logs
Event Trigger
gateway.sync.completed Gateway sync finishes successfully
gateway.brain.offline Brain device stops responding
firewall.event.ids_critical Critical IDS signature fires
firewall.event.wan_down WAN gateway goes down
firewall.event.wan_up WAN gateway comes back up
firewall.event.gateway_unreachable Gateway stops responding
firewall.event.gateway_online Gateway becomes reachable again

Events are emitted on state transitions only - the health monitor (firewall.poll_health, every 2 minutes) diffs each gateway’s current state against the stored fabric_health snapshot and fires an event only when the state changes.


Task Schedule Queue Purpose
gateway.sync_all_gateways Every 5 min sync Sync all enabled gateway connections (rate-limited 2/min)
gateway.check_all_sites_drift Every 15 min sync Drift check all sites with orchestration
gateway.cleanup_distribution_locks Every 10 min default Clean up expired distribution locks
firewall.poll_health Every 2 min metrics Health poll; emit Fabric events on transitions

The Firewall module contributes to the Configuration Backup portable snapshot (.fsdn archive):

Included: FirewallDevice, FirewallRule, NATRule, VPNTunnel, GatewayConnection (credentials stripped).

Excluded: firewall.ids_alerts, firewall.logs (traffic logs), firewall.gateway_sync_logs, and GatewayConnection credentials.

Restore order: FirewallDevice → rules / NAT / VPN → GatewayConnection.



All product names, logos, and brands are property of their respective owners. FreeSDN is an independent project and is not affiliated with or endorsed by the vendors it integrates with. See Trademarks.