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.

AdapterTierNotes
OPNsenseProduction; 13 feature domains including OSPF/BGP routing; gold-standard contract verified; deepest coverage
pfSenseProductionShares OPNsense client plumbing; firewall, NAT, OpenVPN, IPsec, WireGuard
MikroTik (RouterOS v7)ProductionAPI-only access (no SSH/WinBox); 13 feature domains; 13 UI tabs; IPsec and L2TP/PPTP/SSTP
OpenWRTPreview / unauditedubus/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.

MethodPathPurposePermission
GET/api/v1/firewall/rulesList rules - filter by device_id, action, is_enabled, site_idfirewall.view
GET/api/v1/firewall/rules/{id}Get one rulefirewall.view
POST/api/v1/firewall/rulesCreate rulefirewall.manage_rules
PATCH/api/v1/firewall/rules/{id}Update rule (partial)firewall.manage_rules
DELETE/api/v1/firewall/rules/{id}Soft-delete rulefirewall.manage_rules
POST/api/v1/firewall/rules/reorderReorder rules for a devicefirewall.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.

MethodPathPurposePermission
GET/api/v1/firewall/natList NAT rulesfirewall.view
GET/api/v1/firewall/nat/{id}Get one NAT rulefirewall.view
POST/api/v1/firewall/natCreate NAT rulefirewall.manage_nat
PATCH/api/v1/firewall/nat/{id}Update NAT rulefirewall.manage_nat
DELETE/api/v1/firewall/nat/{id}Soft-delete NAT rulefirewall.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.

MethodPathPurposePermission
GET/api/v1/firewall/vpnList tunnels - filter by vpn_type, vpn_statusfirewall.view
GET/api/v1/firewall/vpn/statsAggregate stats: total / up / down / errorfirewall.view
GET/api/v1/firewall/vpn/{id}Get one tunnelfirewall.view
POST/api/v1/firewall/vpnCreate tunnelfirewall.manage_vpn
PATCH/api/v1/firewall/vpn/{id}Update tunnelfirewall.manage_vpn
DELETE/api/v1/firewall/vpn/{id}Soft-delete tunnelfirewall.manage_vpn
TypeOPNsensepfSenseMikroTik
IPsec (IKEv1/v2)YesYesYes
OpenVPNYesYes-
WireGuardYesYesStaged (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.

MethodPathPurposePermission
GET/api/v1/firewall/ids/alertsSearch alerts - filter by severity, time range, acknowledged, site_idfirewall.view
GET/api/v1/firewall/ids/alerts/statsAlert counts by severity + unacknowledged countfirewall.view
POST/api/v1/firewall/ids/alerts/{id}/acknowledgeAcknowledge an alertfirewall.manage_ids

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

MethodPathPurposePermission
GET/api/v1/firewall/gateways/{id}/ids/settingsCurrent IDS settingsfirewall.view
PUT/api/v1/firewall/gateways/{id}/ids/settingsUpdate settingsfirewall.manage_rules
GET/api/v1/firewall/gateways/{id}/ids/alertsLive alerts (up to 5,000)firewall.view
DELETE/api/v1/firewall/gateways/{id}/ids/alertsClear alert logfirewall.manage_rules
GET/api/v1/firewall/gateways/{id}/ids/rulesetsRulesets (ET/Open, etc.)firewall.view
POST/api/v1/firewall/gateways/{id}/ids/rules/{sid}/toggleToggle a rule by SIDfirewall.manage_rules
POST/api/v1/firewall/gateways/{id}/ids/controlStart / stop / restart / update-rulesfirewall.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.

MethodPathPurposePermission
GET/api/v1/firewall/logsSearch logs - filter by action, source_ip, dest_ip, time rangefirewall.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).

MethodPathPurposePermission
GET/api/v1/firewall/gatewaysList connectionsfirewall.view
GET/api/v1/firewall/gateways/summaryAggregate online/offline/sync state countsfirewall.view
GET/api/v1/firewall/gateways/{id}Get one connection (has_credentials bool, no raw cred)firewall.view
POST/api/v1/firewall/gatewaysCreate connectionfirewall.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
MethodPathPurpose
GET/gateways/{id}/statusLive system status; updates is_online / last_seen
GET/gateways/{id}/firewall-rulesLive firewall rule list from device
GET/gateways/{id}/nat-rulesLive NAT rules
GET/gateways/{id}/vpnLive VPN status (secrets redacted)
GET/gateways/{id}/interfacesLive interface list + statistics
GET/gateways/{id}/dhcpLive DHCP leases
GET/gateways/{id}/arpARP table
GET/gateways/{id}/routes/tableKernel routing table
GET/gateways/{id}/health-checkMulti-subsystem deep health (healthy bool)
GET/gateways/{id}/ha-statusCARP / HA sync status

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

MethodPathPurposePermission
POST/gateways/{id}/firewall-rulesPush rule to devicefirewall.manage_rules
PUT/gateways/{id}/firewall-rules/{vendor_rule_id}Update vendor rulefirewall.manage_rules
POST/gateways/{id}/firewall-rules/{vendor_rule_id}/toggle?enabled=<bool>Enable (?enabled=true, default) or disable (?enabled=false) a rulefirewall.manage_rules
POST/gateways/{id}/port-forwardsCreate port-forward (DNAT)firewall.manage_rules
POST/gateways/{id}/source-natCreate SNAT rulefirewall.manage_rules
POST/gateways/{id}/wireguard/serversCreate WireGuard serverfirewall.manage_rules
POST/gateways/{id}/wireguard/peersAdd WireGuard peerfirewall.manage_rules
POST/gateways/{id}/openvpn/instancesCreate OpenVPN instancefirewall.manage_rules
POST/gateways/{id}/ipsec/{vendor_id}/connectBring IPsec tunnel upfirewall.manage_rules
POST/gateways/{id}/ipsec/{vendor_id}/disconnectTear IPsec tunnel downfirewall.manage_rules
POST/gateways/{id}/routes/staticCreate static routefirewall.manage_rules
POST/gateways/{id}/aliasesCreate alias (firewall object)firewall.manage_rules
POST/gateways/{id}/dns/overridesCreate DNS host overridefirewall.manage_rules
POST/gateways/{id}/dhcp/static-mappingsCreate DHCP static mappingfirewall.manage_rules
POST/gateways/{id}/services/{name}/controlStart / stop / restart servicefirewall.manage_rules
POST/gateways/{id}/rebootReboot devicefirewall.admin
POST/gateways/{id}/haltHalt devicefirewall.admin
POST/gateways/{id}/firmware/updateApply firmware updatefirewall.admin
GET/gateways/{id}/config/downloadDownload running configcontroller:write

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

MethodPathPurpose
POST/gateways/{id}/diagnostics/pingPing (1-20 packets)
POST/gateways/{id}/diagnostics/tracerouteTraceroute
POST/gateways/{id}/diagnostics/dns-lookupDNS lookup
GET/gateways/{id}/diagnostics/connectionsActive PF state connections
GET/gateways/{id}/diagnostics/pf-infoPF 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:

DomainUI tabExample endpoint prefix
Firewall rulesrules/gateways/{id}/firewall-rules
NAT + port forwardsnat/gateways/{id}/nat-rules, /port-forwards, /source-nat, /nat/onetoone
VPN (OpenVPN + IPsec + WireGuard)vpn/gateways/{id}/openvpn, /ipsec, /wireguard
Interfaces + VIPs + LAGGsinterfaces/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 diffbackups/gateways/{id}/backups, /config/diff
System + firmware + monitoringsystem / 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.

StatusDomains
UI tab availableSystem, 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.

LayerDescription
Layer 0Controller-direct; always works; single-controller config push
Layer 1Multi-controller VLAN visibility; alignment score; per-cell copy
Layer 2Gateway orchestration; brain/limb roles; read-only brain; canonical VLAN distribution
Layer 3Full 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.

MethodPathPurposePermission
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 mapgateway.manage_topology
DELETE/api/v1/firewall/topology/{site_id}Remove role mapgateway.manage_topology
POST/api/v1/firewall/topology/{site_id}/validateValidate (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.

MethodPathPurposePermission
GET/api/v1/firewall/vlansList canonical VLANsgateway.view
GET/api/v1/firewall/vlans/{id}VLAN detail (+ DHCP scope + reservations)gateway.view
POST/api/v1/firewall/vlansCreate canonical VLANgateway.manage_vlans
PATCH/api/v1/firewall/vlans/{id}Update VLANgateway.manage_vlans
DELETE/api/v1/firewall/vlans/{id}Delete VLANgateway.manage_vlans

Canonical DHCP scopes and reservations for a VLAN:

MethodPathPermission
GET/api/v1/firewall/dhcp/scopesgateway.view
POST/api/v1/firewall/dhcp/scopesgateway.manage_dhcp
POST/api/v1/firewall/dhcp/reservationsgateway.manage_dhcp
DELETE/api/v1/firewall/dhcp/reservations/{id}gateway.manage_dhcp

Canonical DNS overrides:

MethodPathPermission
GET/api/v1/firewall/dns/recordsgateway.view
POST/api/v1/firewall/dns/recordsgateway.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.

MethodPathPurposePermission
GET/api/v1/firewall/templatesList templatesgateway.view
POST/api/v1/firewall/templatesCreate templategateway.manage_vlans
PATCH/api/v1/firewall/templates/{id}Update templategateway.manage_vlans
DELETE/api/v1/firewall/templates/{id}Delete templategateway.manage_vlans
POST/api/v1/firewall/templates/{id}/apply/{site_id}Instantiate template at sitegateway.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
MethodPathPurposePermission
GET/api/v1/firewall/distributionList distribution recordsgateway.view
GET/api/v1/firewall/distribution/{id}Detail (plan + per-step results)gateway.view
POST/api/v1/firewall/distribution/triggerTrigger distribution (vlan_id + site_id)gateway.distribute
POST/api/v1/firewall/distribution/{id}/retryRetry a failed distributiongateway.distribute
POST/api/v1/firewall/distribution/{id}/rollbackSaga rollbackgateway.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.

MethodPathPurposePermission
GET/api/v1/firewall/drift/eventsList drift events (paginated)gateway.drift
GET/api/v1/firewall/drift/summaryCounts by severity + pending/resolvedgateway.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}/resolveResolve: reapply, accept, or ignoregateway.drift
GET/api/v1/firewall/drift/suppressionsList suppression rulesgateway.drift
POST/api/v1/firewall/drift/suppressionsCreate suppression rulegateway.drift
DELETE/api/v1/firewall/drift/suppressions/{id}Deactivate suppression rulegateway.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:

StepNameWhat happens
1DiscoverAuto-discover devices at the site
2Assign rolesSubmit { gateway_id: "brain" | "limb" } for each discovered device
3ScanFull config pull from brain and all limbs
4ReconcileSubmit decisions per resource: adopt, skip, merge, or ignore
5DistributePush adopted resources to canonical state + devices
6VerifyConfirm 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.

MethodPathPurposePermission
POST/api/v1/firewall/import/startStart import sessiongateway.import
GET/api/v1/firewall/import/{id}Session state (current step + per-step payloads)gateway.import
POST/api/v1/firewall/import/{id}/stepAdvance wizard stepgateway.import
POST/api/v1/firewall/import/{id}/cancelCancel sessiongateway.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:

MethodPathPurposePermission
POST/api/v1/firewall/reconciliation/{site_id}/importImport VLAN interfaces from brain → create/update canonical (flags orphans)gateway.import
GET/api/v1/firewall/reconciliation/{site_id}/alignmentCompare canonical vs actual device stategateway.view
POST/api/v1/firewall/reconciliation/{site_id}/distributePush L2 VLAN config to limb devicesgateway.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.

SettingTypeDefaultDescription
default_policyallow | denydenyDefault packet policy for new rules
log_blockedbooltrueLog blocked connections to firewall.logs (primary PostgreSQL)
ids_enabledbooltrueEnable IDS globally
ids_modedetect | preventdetectDetect (log) or prevent (block)
log_retention_daysint 7-36530Firewall log retention
sync_interval_minutesint 1-14405Gateway sync frequency
drift_check_interval_minutesint 5-144015Drift check frequency
distribution_lock_ttl_secondsint 60-3600300Max time a distribution lock is held
auto_remediate_driftboolfalseAutomatically push fixes for detected drift
import_retention_daysint 1-36590Import session retention

Permission codePurposeNotes
firewall.viewView rules, NAT, VPN, IDS alerts, logs, gateway statusGate for almost all GET routes
firewall.manage_rulesCreate/edit/delete rules; also gates gateway CRUD and most live writesRequired for all write operations on gateway connections
firewall.manage_natNAT rule CRUD (FreeSDN tables)
firewall.manage_vpnVPN tunnel CRUD (FreeSDN tables)
firewall.manage_idsAcknowledge IDS alerts (FreeSDN tables)
firewall.view_logsView traffic logs
firewall.manage_gatewaysDeclared in manifest; not used by any route - grant firewall.manage_rules instead
firewall.adminReboot / halt device; apply firmware updateNot declared in the module manifest; must be in the global role catalog
controller:writeDownload running configCore-level permission; not in the module manifest
gateway.viewView orchestration topology, canonical resources, drift
gateway.manage_topologyEdit brain/limb role maps
gateway.manage_vlansCanonical VLAN + template CRUD
gateway.manage_dhcpDHCP scope and reservation CRUD
gateway.manage_dnsDNS override CRUD
gateway.distributeTrigger distribution, retry, rollback
gateway.importRun brownfield import wizard and reconciliation import
gateway.driftView, resolve, and suppress drift events
gateway.diagnosticsRun 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.

IDTierDescriptionPermission
firewall.search_alertsNativeRecent IDS/IPS + security alerts (1-200 results, org-scoped)firewall.view_logs
EventTrigger
gateway.sync.completedGateway sync finishes successfully
gateway.brain.offlineBrain device stops responding
firewall.event.ids_criticalCritical IDS signature fires
firewall.event.wan_downWAN gateway goes down
firewall.event.wan_upWAN gateway comes back up
firewall.event.gateway_unreachableGateway stops responding
firewall.event.gateway_onlineGateway 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.


TaskScheduleQueuePurpose
gateway.sync_all_gatewaysEvery 5 minsyncSync all enabled gateway connections (rate-limited 2/min)
gateway.check_all_sites_driftEvery 15 minsyncDrift check all sites with orchestration
gateway.cleanup_distribution_locksEvery 10 mindefaultClean up expired distribution locks
firewall.poll_healthEvery 2 minmetricsHealth 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.