Christian Manivong d6a0b21dc6
CI / test (3.10) (push) Failing after 8s
CI / test (3.11) (push) Failing after 7s
CI / test (3.12) (push) Failing after 8s
CI / test (3.9) (push) Failing after 7s
refactor(warnings): report raw signal only, no severity/presentation
get_device_warnings() now returns only {code, meta} — severity, title,
message, and action are resolved centrally by netork's
WARNING_CATALOG (netork/core/device_warnings.py), not by the driver.
Keeps this driver independent of netork and avoids per-vendor drift in
how the same warning code is presented.
2026-07-20 09:54:14 +02:00
2026-05-29 09:22:10 +02:00
2026-05-29 09:22:10 +02:00
2026-05-29 09:22:10 +02:00
2026-05-29 09:22:10 +02:00
2026-05-29 09:22:10 +02:00

napalm-opnsense

NAPALM community driver for OPNsense firewalls (read-only, via REST API).

Tested devices

Model OPNsense Version Tested
OPNsense (virtual/bare metal) 24.7 ✅

Additional OPNsense versions should work — contributions welcome.

Requirements

Dependency Minimum version
Python 3.9
NAPALM 4.0
requests 2.28

Installation

pip install napalm-opnsense

Or from source:

git clone https://github.com/napalm-automation-community/napalm-opnsense
cd napalm-opnsense
pip install -e .

Quick start

from napalm import get_network_driver

driver = get_network_driver("opnsense")
with driver(
    "192.168.1.1",
    "my_api_key",
    "my_api_secret",
    optional_args={"verify": False},
) as device:
    facts = device.get_facts()
    print(facts)

Authentication

OPNsense uses API key/secret pairs instead of username/password. Generate a key pair in the OPNsense GUI under System → Access → Users → edit user → API keys.

Pass the credentials via optional_args:

optional_args={
    "api_key": "your-api-key",
    "api_secret": "your-api-secret",
    "verify": False,  # set to a CA bundle path or True in production
}

Alternatively, pass the key/secret as the positional username/password arguments.

Implemented getters

Getter Status OPNsense API Endpoint
get_facts ✅ GET /api/core/system/status
get_interfaces ✅ GET /api/interfaces/overview/export
get_interfaces_ip ✅ GET /api/interfaces/addresses/export
get_interfaces_counters ✅ GET /api/diagnostics/interface/get_interface_statistics
get_arp_table ✅ GET /api/diagnostics/interface/get_arp
get_ipv6_neighbors_table ✅ GET /api/diagnostics/interface/get_ndp
get_route_to ✅ GET /api/diagnostics/interface/get_routes
get_environment ✅ GET /api/diagnostics/system/system_resources + system_temperature
get_lldp_neighbors ✅ ¹ GET /api/lldpd/service/neighbor
get_lldp_neighbors_detail ✅ ¹ GET /api/lldpd/service/neighbor
get_ntp_servers ✅ GET /api/ntpd/service/status
get_config ✅ GET /api/core/backup/download/this (XML)
is_alive ✅ TCP socket check
get_bgp_neighbors ✅ ² GET /api/quagga/bgp/get + GET /api/quagga/diagnostics/bgpneighbors
get_vlans ✅ GET /api/interfaces/vlan_settings/search_item
get_mac_address_table ❌ Not applicable (firewall, no L2 switching)

¹ Requires the os-lldpd plugin. Returns empty dict if the plugin is not installed. ² Requires the os-frr (FRR/Quagga) plugin. Returns empty dict if the plugin is not installed or FRR is not running.

Config management

OPNsense does not expose a single generic "push config" endpoint. Config is managed per-module via separate API controllers. This driver implements config management for static routes via /api/routes/routes/.

Why routes? Routes are the most common network-automation target on a firewall, and the OPNsense routes API provides full CRUD operations.

Supported methods

Method OPNsense API
load_merge_candidate(config=...) stages routes in memory
compare_config() diffs against GET /api/routes/routes/searchroute
commit_config() snapshots backup → POST /api/routes/routes/addroute × n → reconfigure
discard_config() clears staged candidate
rollback() POST /api/core/backup/revert_backup/{id} — restores the config.xml snapshot taken before the last commit

Config format

The load_merge_candidate config parameter must be a JSON array of route objects, each with network and gateway keys. gateway must be the name of an existing OPNsense gateway (as configured under System → Gateways → Configuration), not an IP address.

[
  {
    "network": "10.0.0.0/8",
    "gateway": "WAN_GW",
    "descr": "Corporate internal",
    "disabled": "0"
  },
  {
    "network": "0.0.0.0/0",
    "gateway": "WAN_GW",
    "descr": "Default route"
  }
]

Example

import json

driver = get_network_driver("opnsense")
d = driver("192.168.1.1", "user", "pass", optional_args={"api_key": "k", "api_secret": "s"})
d.open()

routes = json.dumps([{"network": "10.0.0.0/8", "gateway": "WAN_GW"}])
d.load_merge_candidate(config=routes)

print(d.compare_config())   # unified diff
d.commit_config()           # applies routes and calls reconfigure
d.rollback()                # removes the routes just added
d.close()

Limitations

  • load_replace_candidate is not supported (no XML upload endpoint in the JSON API).
  • Non-route config (firewall rules, DHCP, DNS, interfaces, …) must be managed via OPNsense module-specific controllers — outside the scope of this driver.
  • rollback() reverts the entire config.xml to the pre-commit state (not just the routes). OPNsense's backup API has no partial-restore capability.
  • Rollback uses the backup snapshot taken at commit_config() time. If no commit was made in the current session, the most recent available backup is used as a fallback.

Optional arguments

Argument Default Description
api_key username OPNsense API key
api_secret password OPNsense API secret
base_url https://<hostname> Override the base URL
verify True TLS certificate verification (path or bool)

Development

pip install -e ".[dev]"
pytest tests/

CI

This project includes a GitHub Actions workflow that:

  • Runs unit tests across Python 3.9–3.12
  • Builds sdist and wheel
  • Uploads build artifacts

See .github/workflows/ci.yml.

License

Apache 2.0 — see LICENSE.

S
Description
No description provided
Readme
203 KiB
Languages
Python 100%