OPNsense API Client
This is a Python3 client for interacting with the official OPNsense API.
It enables easy management and automation of OPNsense firewalls.
The base-code is a Fork of this OPNsense Ansible-Collection that was refactored for use within raw Python.
This can be useful if you want to automate your Infrastructure and do not use Ansible.
An interactive CLI interface might be added later on.
Install
pip install oxl-opnsense-client
Get to know the available modules:
Contribute
The codebase of this library will be automatically synced with the upstream code of the OPNsense Ansible-Module!
Thus, new features (and feature-requests) should be made there.
Feel free to report issues/bugs, take part in discussions and add/extend tests.
Note: Only the API-enabled functionalities can be implemented.
Usage
Documentation, Ansible OPNsense-Collection Docs
from oxl_opnsense_client import Client
with Client(
firewall='192.168.10.20',
port=443, # default
credential_file='/tmp/.opnsense.txt',
# token='0pWN/C3tnXem6OoOp0zc9K5GUBoqBKCZ8jj8nc4LEjbFixjM0ELgEyXnb4BIqVgGNunuX0uLThblgp9Z',
# secret='Vod5ug1kdSu3KlrYSzIZV9Ae9YFMgugCIZdIIYpefPQVhvp6KKuT7ugUIxCeKGvN6tj9uqduOzOzUlv',
) as c:
c.test()
# True
### CHECK SUPPORTED MODULES ###
c.list_modules()
# ['acme_account', 'acme_action', 'acme_certificate', 'acme_general', 'acme_validation', 'alias', 'alias_multi', 'alias_purge', 'bind_acl', 'bind_blocklist', 'bind_domain', 'bind_general', 'bind_record', 'bind_record_multi', 'cron', 'dhcp_controlagent', 'dhcp_general', 'dhcp_reservation', 'dhcp_subnet', 'dhcrelay_destination', 'dhcrelay_relay', 'dnsmasq_boot', 'dnsmasq_domain', 'dnsmasq_general', 'dnsmasq_host', 'dnsmasq_option', 'dnsmasq_range', 'dnsmasq_tag', 'frr_bfd_general', 'frr_bfd_neighbor', 'frr_bgp_as_path', 'frr_bgp_community_list', 'frr_bgp_general', 'frr_bgp_neighbor', 'frr_bgp_peer_group', 'frr_bgp_prefix_list', 'frr_bgp_redistribution', 'frr_bgp_route_map', 'frr_diagnostic', 'frr_general', 'frr_ospf3_general', 'frr_ospf3_interface', 'frr_ospf3_network', 'frr_ospf3_prefix_list', 'frr_ospf3_redistribution', 'frr_ospf3_route_map', 'frr_ospf_general', 'frr_ospf_interface', 'frr_ospf_network', 'frr_ospf_prefix_list', 'frr_ospf_redistribution', 'frr_ospf_route_map', 'frr_rip', 'gateway', 'group', 'hasync_general', 'hasync_service', 'ids_action', 'ids_general', 'ids_policy', 'ids_policy_rule', 'ids_rule', 'ids_ruleset', 'ids_user_rule', 'interface_bridge', 'interface_gif', 'interface_gre', 'interface_lagg', 'interface_loopback', 'interface_vip', 'interface_vlan', 'interface_vxlan', 'ipsec_auth_local', 'ipsec_auth_remote', 'ipsec_cert', 'ipsec_child', 'ipsec_connection', 'ipsec_general', 'ipsec_manual_spd', 'ipsec_pool', 'ipsec_psk', 'ipsec_vti', 'list', 'monit_alert', 'monit_service', 'monit_test', 'nat_one_to_one', 'nat_source', 'neighbor', 'nginx_general', 'nginx_upstream_server', 'openvpn_client', 'openvpn_client_override', 'openvpn_server', 'openvpn_static_key', 'openvpn_status', 'package', 'postfix_address', 'postfix_domain', 'postfix_general', 'postfix_headercheck', 'postfix_recipient', 'postfix_recipientbcc', 'postfix_sender', 'postfix_senderbcc', 'postfix_sendercanonical', 'privilege', 'raw', 'reload', 'route', 'rule', 'rule_interface_group', 'rule_multi', 'rule_purge', 'savepoint', 'service', 'shaper_pipe', 'shaper_queue', 'shaper_rule', 'snapshot', 'syslog', 'system', 'unbound_acl', 'unbound_dnsbl', 'unbound_dot', 'unbound_forward', 'unbound_general', 'unbound_host', 'unbound_host_alias', 'user', 'webproxy_acl', 'webproxy_auth', 'webproxy_cache', 'webproxy_forward', 'webproxy_general', 'webproxy_icap', 'webproxy_pac_match', 'webproxy_pac_proxy', 'webproxy_pac_rule', 'webproxy_parent', 'webproxy_remote_acl', 'webproxy_traffic', 'wireguard_general', 'wireguard_peer', 'wireguard_server', 'wireguard_show']
### CHECK MODULE ARGUMENTS / SPECS ###
c.module_specs('route')
# {'specs': {'gateway': {'type': 'str', 'required': True, 'aliases': ['gw'], 'description': 'Specify a valid existing gateway matching the networks ip protocol'}, 'network': {'type': 'str', 'required': True, 'aliases': ['nw', 'net'], 'description': 'Specify a valid network matching the gateways ip protocol'}, 'description': {'type': 'str', 'required': False, 'aliases': ['desc']}, 'match_fields': {'type': 'list', 'required': False, 'elements': 'str', 'description': "Fields that are used to match configured routes with the running config - if any of those fields are changed, the module will think it's a new route", 'choices': ['network', 'gateway', 'description'], 'default': ['network', 'gateway']}, 'reload': {'type': 'bool', 'required': False, 'default': True, 'aliases': ['apply'], 'description': 'If the running config should be reloaded/applied on change - will take some time'}, 'state': {'type': 'str', 'required': False, 'choices': ['present', 'absent'], 'default': 'present'}, 'enabled': {'type': 'bool', 'required': False, 'default': True}}}
c.module_specs('wireguard_show', stdout=True)
# prints in pretty-JSON
### CREATE ENTRY ###
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303})
# {'error': None, 'result': {'changed': True, 'diff': {'after': {'uuid': None, 'rfc5424': False, 'enabled': True, 'target': '192.168.0.1', 'transport': 'udp4', 'facility': [], 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'certificate': '', 'port': 5303, 'description': ''}}}}
c.run_module('list', params={'target': 'syslog'})
# {'error': None, 'result': {'changed': False, 'data': [{'target': '192.168.0.1', 'enabled': True, 'transport': 'udp4', 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'facility': [], 'certificate': '', 'port': 5303, 'rfc5424': False, 'description': '', 'uuid': '32b1ce94-93d0-4d20-93a2-4fff12d12a54'}]}}
### UPDATING ENTRY ###
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 9941, 'match_fields': ['target']})
# {'error': None, 'result': {'changed': True, 'diff': {'before': {'uuid': '4930e797-5111-4825-b5bb-c8e60f9d21d5', 'rfc5424': False, 'enabled': True, 'target': '192.168.0.1', 'transport': 'udp4', 'facility': [], 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'certificate': '', 'port': 5304, 'description': ''}, 'after': {'uuid': '4930e797-5111-4825-b5bb-c8e60f9d21d5', 'rfc5424': False, 'enabled': True, 'target': '192.168.0.1', 'transport': 'udp4', 'facility': [], 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'certificate': '', 'port': 9941, 'description': ''}}}}
c.run_module('list', params={'target': 'syslog'})
# {'error': None, 'result': {'changed': False, 'data': [{'target': '192.168.0.1', 'enabled': True, 'transport': 'udp4', 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'facility': [], 'certificate': '', 'port': 9941, 'rfc5424': False, 'description': '', 'uuid': '4930e797-5111-4825-b5bb-c8e60f9d21d5'}]}}
### DELETING ENTRY ###
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent', 'match_fields': ['target']})
# {'error': None, 'result': {'changed': True, 'diff': {'before': {'uuid': '2500dadc-ce43-4e23-994e-860516b0ef45', 'rfc5424': False, 'enabled': True, 'target': '192.168.0.1', 'transport': 'udp4', 'facility': [], 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'certificate': '', 'port': 5303, 'description': ''}}}}
c.run_module('list', params={'target': 'syslog'})
# {'error': None, 'result': {'changed': False, 'data': []}}
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent'})
# {'error': None, 'result': {'changed': False, 'diff': {}}}
### CHECK MODE (DRY-RUN) ###
c.run_module('syslog', check_mode=True, params={'target': '192.168.0.1', 'port': 5303})
# {'error': None, 'result': {'changed': True, 'diff': {'before': {'uuid': '7f3aba31-07ca-4cb9-b93d-dc442a5291c7', 'rfc5424': False, 'enabled': True, 'target': '192.168.0.1', 'transport': 'udp4', 'facility': [], 'program': [], 'level': ['alert', 'crit', 'emerg', 'err', 'info', 'notice', 'warn'], 'certificate': '', 'port': 5303, 'description': ''}}}}
c.run_module('list', params={'target': 'syslog'})
# {'error': None, 'result': {'changed': False, 'data': []}}
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent'})
# {'error': None, 'result': {'changed': False, 'diff': {}}}
Credentials
from oxl_opnsense_client import Client
# use the API credentials-file as downloaded from the WebUI
c = Client(firewall='<IP>', credential_file='/home/<YOU>/.opnsense.txt')
# use the token/key pair directly
c = Client(firewall='<IP>', token='<TOKEN>', secret='<SECRET>')
SSL Verification
from oxl_opnsense_client import Client
# provide the path to your custom CA public-key
c = Client(
firewall='<IP>',
credential_file='/home/<YOU>/.opnsense.txt',
ssl_ca_file='/home/<YOU>/ca.crt',
)
# ONLY USE FOR TESTING PURPOSES => you can disable the certificate-verification
c = Client(
firewall='<IP>',
credential_file='/home/<YOU>/.opnsense.txt',
ssl_verify=False,
)
Debug Output
This will show you the performed API calls and their JSON payload.
from oxl_opnsense_client import Client
c = Client(
firewall='<IP>',
credential_file='/home/<YOU>/.opnsense.txt',
debug=True,
)
c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303})
# INFO: REQUEST: GET | URL: https://172.17.1.52/api/syslog/settings/get
# INFO: RESPONSE: '{'status_code': 200, '_request': <Request('GET', 'https://172.17.1.52/api/syslog/settings/get')>, '_num_bytes_downloaded': 123, '_elapsed': datetime.timedelta(microseconds=194859), '_content': b'{"syslog":{"general":{"enabled":"1","loglocal":"1","maxpreserve":"31","maxfilesize":""},"destinations":{"destination":[]}}}'}'
# INFO: REQUEST: POST | URL: https://172.17.1.52/api/syslog/settings/addDestination | HEADERS: '{'Content-Type': 'application/json'}' | DATA: '{"destination": {"rfc5424": 0, "enabled": 1, "hostname": "192.168.0.1", "transport": "udp4", "facility": "", "program": "", "level": "alert,crit,emerg,err,info,notice,warn", "certificate": "", "port": 5303, "description": ""}}'
# INFO: RESPONSE: '{'status_code': 200, '_request': <Request('POST', 'https://172.17.1.52/api/syslog/settings/addDestination')>, '_num_bytes_downloaded': 64, '_elapsed': datetime.timedelta(microseconds=61852), '_content': b'{"result":"saved","uuid":"ed90d52a-63ac-4d7c-a35b-4f250350f85d"}'}'
# INFO: REQUEST: POST | URL: https://172.17.1.52/api/syslog/service/reconfigure | HEADERS: '{}'
# INFO: RESPONSE: '{'status_code': 200, '_request': <Request('POST', 'https://172.17.1.52/api/syslog/service/reconfigure')>, '_num_bytes_downloaded': 15, '_elapsed': datetime.timedelta(microseconds=657156), '_content': b'{"status":"ok"}'}'
This information is also logged to files:
ls /tmp/opnsense_client/
# api_calls.log syslog.log
The module-specific logs contain performance-profiling.
Metadata
Release files for oxl-opnsense-client 26.1.11
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| oxl_opnsense_client-26.1.11.tar.gz | 222.0 kB | Without provenance | Details for oxl_opnsense_client-26.1.11.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| oxl_opnsense_client-26.1.11-py3-none-any.whl | Python 3 | none | any | Details for oxl_opnsense_client-26.1.11-py3-none-any.whl |
Total release size: 721.8 kB
Release files / oxl_opnsense_client-26.1.11.tar.gz
| Download URL | oxl_opnsense_client-26.1.11.tar.gz |
|---|---|
| Size | 222.0 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
1af4032230202f390e525d0936773d2f341074befc4d7ea31d88a11763437f62
|
|
BLAKE2b-256 checksum How to use checksums |
acc39893938be7afab73c77206dca0d82ebefe9eb3a13b3374f435570b97d821
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Release files / oxl_opnsense_client-26.1.11-py3-none-any.whl
| Download URL | oxl_opnsense_client-26.1.11-py3-none-any.whl |
|---|---|
| Size | 499.8 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a14f805040366025139026fcd2dfb15c8a7eb11a81db5483451791ef816cd7f6
|
|
BLAKE2b-256 checksum How to use checksums |
f43a444b131dc07acbde6ef46e1ee04307616eddd0620c2296fab8b4250fbb09
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.1.0 CPython/3.13.12
|
Security for oxl-opnsense-client 26.1.11
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
No provenance found
None of the files in this release were uploaded with provenance metadata.
A note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.