pfSense firewall
v0.6.7Operate a pfSense firewall over its REST API: read firewall rules, NAT, aliases, virtual IPs, interface / gateway (config + status) / service / VPN status, DHCP leases, routes, ARP, CARP, pf tables, installed packages, the config-change history, and firewall / system / auth / DHCP / OpenVPN logs, plus a few gated mutators (apply filter, flush states, restart a service, reboot). Uses the community pfSense-pkg-RESTAPI package (/api/v2), which runs on the firewall and works across CE and Plus.
curl
jq
Install
emisar pack install
fetches this pack, re-validates it, and verifies its content hash against the
--hash
below — the exact bytes this page was rendered against, so a tampered copy is
rejected — before copying it into the runner's packs dir. The command reloads a
running daemon itself; no manual restart.
sudo emisar pack install pfsense --hash sha256:f84eca93f21def6cdb4986a9fba4a0a1a89098a643c1bc9c952400a0570d84c5
Setup
Every action calls the pfSense REST API at
$PFSENSE_URL
via curl, sending
$PFSENSE_API_KEY
as the X-API-Key header. Install the community pfSense-pkg-RESTAPI package on the firewall (System → Package Manager), mint a key under System → REST API → Keys, and point
PFSENSE_URL
at the firewall's GUI URL.
Environment
Set these on the runner host, then add each name to
execution.inherit_env
so the value reaches the action.
-
PFSENSE_URLdefault https://192.168.1.1Firewall GUI / API base URL — scheme, host, and port if non-default. The API is served on the same TLS + port as the webConfigurator.
-
PFSENSE_API_KEYrequiredREST API key (System → REST API → Keys). Sent as the X-API-Key header over curl stdin, so it never appears in the process arguments or the audit log. Use a least-privilege, read-only key.
-
PFSENSE_INSECURESet to "true" to skip TLS verification — needed for the default self-signed GUI certificate. Prefer pinning a CA via CURL_CA_BUNDLE.
Notes
-
Any of
PFSENSE_URL/PFSENSE_API_KEY/PFSENSE_INSECUREyou set must also be allowlisted in the runner'sexecution.inherit_env— the action env is scrubbed to PATH/LANG/LC_ALL/TERM by default, so an env present on the host but not allowlisted is silently dropped (the action falls back to its local default or fails auth). - Requires the community REST API package (pfSense-pkg-RESTAPI, /api/v2) installed on the firewall — not Netgate's Nexus controller API. The package's read_only switch (System → REST API) forces the whole API GET-only; pair it with a read-only key for a diagnostics deployment.
-
TLS is verified by default. pfSense ships a self-signed GUI cert, so set
PFSENSE_INSECURE=true, or set CURL_CA_BUNDLE to a CA file (curl reads it natively) to verify properly. -
Reads that would expose secrets (user passwords, IPsec phase pre-shared keys) are intentionally omitted, and the API's arbitrary-command endpoint (/diagnostics/command_prompt — a remote shell) is deliberately not wired: that belongs in the default-denied
shellbreak-glass pack, not here. The certificate-store reads (certificates / certificate_authorities / crls) select only non-secret fields with jq, so the certificate private key (prvPEM) is never returned — by design, not just redaction. The mutators are risk-gated; reboot is critical. -
Dynamic routing (FRR — BGP / OSPF / BFD) is NOT exposed by this REST API, so this pack cannot read it. FRR state lives behind vtysh on the firewall; reach it out-of-band (the
frrpack runs vtysh locally on an FRR host, or use SNMP).
Verify it works
Runs pfsense.version, a low-risk
read that confirms the pack can reach its target. Run it on the host once the pack
is installed; pack install runs it for
you.
sudo emisar pack verify pfsense
Install and configure a pack walks through the whole sequence on a host.
Actions 44 total
View on GitHub-
pfsense.aliases script low Low — read-only or trivially reversible
GET /api/v2/firewall/aliases
List firewall aliases (named host / network / port groups) and their members. Use to see which IPs a block/allow list currently contains.
View source on GitHub -
pfsense.apply_dhcp_server script medium Medium — changes state, easily reversible
POST /api/v2/services/dhcp_server/apply
Apply staged DHCP server changes — reloads dhcpd so pending static-mapping or pool edits take effect. This is the separate step the static-mapping writes deliberately leave to the operator; it pushes whatever is currently staged, not only the change you just made.
View source on GitHub -
pfsense.apply_filter script medium Medium — changes state, easily reversible
POST /api/v2/firewall/apply
Apply staged firewall changes — reloads the pf filter so pending rule, NAT, or alias edits take effect. Idempotent and low blast radius, but it does push whatever is currently staged into the live ruleset.
View source on GitHub -
pfsense.arp_table script low Low — read-only or trivially reversible
GET /api/v2/diagnostics/arp_table
Show the ARP table — IP ↔ MAC ↔ interface, with hostname and expiry. Use to confirm a host is on the network and which interface it is on.
View source on GitHub -
pfsense.auth_log script medium Medium — changes state, easily reversible
GET /api/v2/status/logs/auth
Show recent authentication-log entries — webConfigurator and SSH logins to the firewall, successes and failures, with user and source IP. Use to spot brute-force attempts or confirm who logged in.
View source on GitHub -
pfsense.carp_status script low Low — read-only or trivially reversible
GET /api/v2/status/carp
Show CARP high-availability status — whether this node is MASTER or BACKUP and the state of each virtual IP. Use to confirm HA roles after a failover.
View source on GitHub -
pfsense.certificate_authorities script
GET /api/v2/system/certificate_authorities
List the certificate authorities — each CA's description, refid, parent CA (caref, for intermediates), OS-trust-store flag, and serial. The CA private key is never returned: the action selects only these non-secret fields, so the `prv` PEM is dropped at the source. (The REST API exposes no structured expiry for CAs; use pfsense.certificates for cert validity windows.)
View source on GitHub -
pfsense.certificates script low Low — read-only or trivially reversible
GET /api/v2/system/certificates
List the certificate store — each certificate's description, refid, signing CA (caref), type, and validity window (valid_from / valid_until / valid_days_left) for expiry monitoring. The private key is never returned: the action selects only these non-secret fields, so the `prv` PEM is dropped at the source.
View source on GitHub -
pfsense.config_history script low Low — read-only or trivially reversible
GET /api/v2/diagnostics/config_history/revisions
List the saved configuration revisions — the change history with each revision's time, description (what changed), and the user who made it. Use to answer "what changed on the firewall and when". Returns revision metadata only, not the full configuration.
View source on GitHub -
pfsense.create_dhcp_static_mapping script medium Medium — changes state, easily reversible
POST /api/v2/services/dhcp_server/static_mapping
Reserve one DHCP address for one MAC on one interface — the "give this host a stable address" edit. Creates a single mapping; it never touches an existing one and never edits a pool. The change is STAGED: dhcpd keeps serving the old configuration until pfsense.apply_dhcp_server runs, so the operator chooses when the DHCP server reloads.
View source on GitHub -
pfsense.crls script low Low — read-only or trivially reversible
GET /api/v2/system/crls
List the certificate revocation lists — each CRL's description, refid, issuing CA (caref), method (internal / existing), lifetime, serial, and the count of revoked certificates. The raw CRL PEM and the full revoked-entry list are omitted to keep the output compact (neither is a secret).
View source on GitHub -
pfsense.delete_dhcp_static_mapping script medium Medium — changes state, easily reversible
DELETE /api/v2/services/dhcp_server/static_mapping
Remove one DHCP static mapping, named by the interface and the id that pfsense.dhcp_static_mappings returns for it. Deletes exactly that one mapping — there is no wildcard form and no "delete all" here. The client falls back to a pool address on its next lease. The change is STAGED: dhcpd keeps serving the old configuration until pfsense.apply_dhcp_server runs.
View source on GitHub -
pfsense.dhcp_leases script low Low — read-only or trivially reversible
GET /api/v2/status/dhcp_server/leases
List DHCP leases — IP, MAC, hostname, and state (active / expired / static). Works for both the ISC and Kea backends. Use to find what a device was assigned.
View source on GitHub -
pfsense.dhcp_log script medium Medium — changes state, easily reversible
GET /api/v2/status/logs/dhcp
Show recent DHCP server log entries — lease discover/offer/request/ack and declines, with client MACs and assigned addresses. Use to debug a client that is not getting an address or to see who leased what.
View source on GitHub -
pfsense.dhcp_static_mappings script low Low — read-only or trivially reversible
GET /api/v2/services/dhcp_server/static_mappings
List the DHCP static mappings on one interface — each mapping's id, MAC, reserved address, hostname, description, and whether it also gets a static ARP entry. This is the read that names the object every static-mapping write acts on: the delete takes the id this returns.
View source on GitHub -
pfsense.dns_resolver_settings script low Low — read-only or trivially reversible
GET /api/v2/services/dns_resolver/settings
Show the DNS Resolver (Unbound) configuration — whether it is enabled, the listen and TLS ports, the interfaces it binds and forwards out of, DNSSEC and forwarding mode, and the DHCP/OpenVPN registration flags. The operator's free-text `custom_options` block is never returned: it is raw Unbound config an operator can put anything in, including forwarding credentials, so the action selects only the settings above and drops it at the source.
View source on GitHub -
pfsense.firewall_log script medium Medium — changes state, easily reversible
GET /api/v2/status/logs/firewall
Show recent firewall filter-log entries — blocked/passed packets with time, interface, action, and source/destination. Use to see what is being dropped.
View source on GitHub -
pfsense.firewall_rules script low Low — read-only or trivially reversible
GET /api/v2/firewall/rules
List all configured firewall filter rules, in order, with interface, action, source, destination, and description. Use to see what is allowed or blocked.
View source on GitHub -
pfsense.flush_states script high High — service-affecting
DELETE /api/v2/firewall/states
Flush the entire firewall state table — drops every tracked connection through the firewall. Existing sessions must re-establish. Use to clear a stuck state table or force traffic to re-evaluate against new rules.
View source on GitHub -
pfsense.gateway_groups script low Low — read-only or trivially reversible
GET /api/v2/routing/gateway/groups
List the configured gateway groups — the multi-WAN failover / load-balance tiers that decide which gateway carries traffic when one is down. Use to understand failover policy; pair with gateway_status for live up/down state.
View source on GitHub -
pfsense.gateway_status script low Low — read-only or trivially reversible
GET /api/v2/status/gateways
Show gateway monitoring (dpinger) — per-gateway up/down state, RTT, std-dev, and packet loss. Use to diagnose WAN / multi-WAN failover.
View source on GitHub -
pfsense.gateways script low Low — read-only or trivially reversible
GET /api/v2/routing/gateways
List the configured gateways (the routing config, not live status) — each gateway's name, interface, gateway/monitor IP, default flag, and weight. Use pfsense.gateway_status for live dpinger up/down/RTT, and pfsense.gateway_groups for failover groups.
View source on GitHub -
pfsense.interface_config script low Low — read-only or trivially reversible
GET /api/v2/interfaces
List the configured network interfaces — assignment, description, IPv4/IPv6 addressing mode, and MTU. This is the configuration; use interface_status for live link state and counters.
View source on GitHub -
pfsense.interface_status script low Low — read-only or trivially reversible
GET /api/v2/status/interfaces
Show per-interface live status — link state, IPv4/IPv6 addresses, media, and in/out packet + byte + error counters. Use to spot a down WAN or errors.
View source on GitHub -
pfsense.ipsec_child_sas script low Low — read-only or trivially reversible
GET /api/v2/status/ipsec/child_sas
Show IPsec child SAs (phase 2) — the installed traffic-selector pairs that actually carry tunnel traffic, with state, bytes, and lifetime. Pair with ipsec_status (phase-1 IKE SAs) to tell "tunnel up" from "tunnel passing traffic".
View source on GitHub -
pfsense.ipsec_status script low Low — read-only or trivially reversible
GET /api/v2/status/ipsec/sas
Show IPsec security associations — phase-1 IKE SAs and their state (established or not), peers, and algorithms. Use to check whether a site-to-site tunnel is up.
View source on GitHub -
pfsense.nat_outbound script low Low — read-only or trivially reversible
GET /api/v2/firewall/nat/outbound/mappings
List outbound NAT mappings — how internal traffic is translated leaving the firewall. Use to debug source-NAT and masquerade behaviour.
View source on GitHub -
pfsense.nat_port_forwards script low Low — read-only or trivially reversible
GET /api/v2/firewall/nat/port_forwards
List inbound NAT port-forward rules — external port/interface to internal target. Use to audit what is exposed.
View source on GitHub -
pfsense.ntp_settings script low Low — read-only or trivially reversible
GET /api/v2/services/ntp/settings
Show the NTP service configuration — whether it is enabled, the interfaces it binds, the poll interval bounds, orphan-mode stratum, peer limit, logging and statistics flags, leap-second handling, and whether server authentication is on with which algorithm. The shared authentication key itself is never returned: the action selects only the settings above, so `serverauthkey` is dropped at the source.
View source on GitHub -
pfsense.openvpn_log script medium Medium — changes state, easily reversible
GET /api/v2/status/logs/openvpn
Show recent OpenVPN log entries — tunnel up/down, client connect/disconnect, and TLS/auth handshake errors. Use to debug VPN connectivity or a client that cannot establish a tunnel. See pfsense.openvpn_status for live session state.
View source on GitHub -
pfsense.openvpn_status script low Low — read-only or trivially reversible
GET /api/v2/status/openvpn/servers
Show OpenVPN server status — each server and its connected clients (common name, real address, bytes in/out, connected-since). Use to see who is on the VPN.
View source on GitHub -
pfsense.pf_table script low Low — read-only or trivially reversible
GET /api/v2/diagnostics/table
Show the addresses in one pf table by name (list the names with pfsense.pf_tables) — e.g. which IPs sshguard or a pfBlocker alias is currently blocking. pfBlocker feed tables can hold tens of thousands of entries, so the output is deliberately capped and returned as text; a table larger than the cap is truncated — narrow to a specific smaller table.
View source on GitHub -
pfsense.pf_tables script low Low — read-only or trivially reversible
GET /api/v2/diagnostics/tables
List the pf table NAMES defined on the firewall (bogons, sshguard, virusprot, pfBlocker aliases, …) — just the names, not their contents. Use pfsense.pf_table to read the addresses in one table (some tables hold tens of thousands of entries).
View source on GitHub -
pfsense.reboot script critical Critical — data loss or irreversible
POST /api/v2/diagnostics/reboot
Reboot the firewall. All traffic through the box stops until it finishes booting, and there is no remote undo. Use only when a reboot is genuinely required.
View source on GitHub -
pfsense.restart_service script high High — service-affecting
POST /api/v2/status/service (restart)
Restart a pfSense service by name (unbound, dhcpd, openvpn, ipsec, dpinger, …). The service is briefly unavailable while it restarts, so dependent connectivity can blip.
View source on GitHub -
pfsense.service_status script low Low — read-only or trivially reversible
GET /api/v2/status/services
List all pfSense services with their enabled flag and running state (unbound, dhcpd/kea, openvpn, ipsec, dpinger, …). Use to find a stopped service.
View source on GitHub -
pfsense.states_size script low Low — read-only or trivially reversible
GET /api/v2/firewall/states/size
Show current firewall state-table count and the configured maximum. Use to watch for state exhaustion. Cheap — does not dump the whole table.
View source on GitHub -
pfsense.static_routes script low Low — read-only or trivially reversible
GET /api/v2/routing/static_routes
List configured static routes — destination network, gateway, and description. Use to check routing for a reachability problem.
View source on GitHub -
pfsense.system_log script medium Medium — changes state, easily reversible
GET /api/v2/status/logs/system
Show recent system-log entries — the general pfSense log (boot, services, errors). Use for "what happened on the box recently?".
View source on GitHub -
pfsense.system_packages script low Low — read-only or trivially reversible
GET /api/v2/system/packages
List the installed pfSense add-on packages with their installed version and whether an update is available. Use to confirm what is loaded on the box (e.g. the FRR or REST API package) and what is out of date.
View source on GitHub -
pfsense.system_status script low Low — read-only or trivially reversible
GET /api/v2/status/system
Show firewall system health — version, uptime, CPU model/usage/load, memory, swap, mbuf and disk usage, and temperature. The first stop for "how is the box doing?".
View source on GitHub -
pfsense.version script low Low — read-only or trivially reversible
GET /api/v2/system/version
Show pfSense version, build, and kernel. Cheap connectivity + auth check, and the pack's verify action.
View source on GitHub -
pfsense.virtual_ips script low Low — read-only or trivially reversible
GET /api/v2/firewall/virtual_ips
List the configured virtual IPs (VIPs) — CARP, IP-alias, and proxy-ARP — with interface, subnet, type, and CARP vhid. Use to audit the shared HA addresses; pair with carp_status for which node currently owns each.
View source on GitHub -
pfsense.wireguard_peers script low Low — read-only or trivially reversible
GET /api/v2/vpn/wireguard/peers
List the configured WireGuard peers — each peer's description, whether it is enabled, the tunnel it belongs to, its endpoint host and port, keepalive interval, public key, and allowed IPs, for answering "is this peer configured and pointed where I think it is". The peer's optional pre-shared key is never returned: the action selects only the fields above, so `presharedkey` is dropped at the source.
View source on GitHub