# OPNsense API Client
[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/lint.yml)
[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/unit_test.yml)
[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/functional_test.yml)
[](https://pypi.org/project/oxl-opnsense-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](https://github.com/O-X-L/ansible-opnsense) that was refactored for use within raw Python.
This can be useful if you want to automate your Infrastructure and do not use [Ansible](https://www.ansible.com/how-ansible-works/).
An interactive CLI interface might be added later on.
<img src="https://raw.githubusercontent.com/O-X-L/opnsense-api-client/refs/heads/latest/docs/source/_static/img/intro.gif" alt="Intro GIF" width="70%"/>
----
## Install
```bash
pip install oxl-opnsense-client
```
Get to know the available modules:
* [Documentation](https://python-opnsense.oxl.app)
* [Module list](https://github.com/O-X-L/opnsense-api-client/tree/main/src/oxl_opnsense_client/plugins/modules)
* [Ansible Docs](https://ansible-opnsense.oxl.app)
----
## Contribute
The codebase of this library will be automatically synced with the upstream code of [the OPNsense Ansible-Module](https://github.com/O-X-L/ansible-opnsense)!
Thus, new features (*and feature-requests*) should be made there.
Feel free to [report issues/bugs](https://github.com/O-X-L/opnsense-api-client/issues), [take part in discussions](https://github.com/O-X-L/opnsense-api-client/discussions) and [add/extend tests](https://github.com/O-X-L/opnsense-api-client/tree/latest/src/tests).
Note: Only the [API-enabled](https://docs.opnsense.org/development/api.html) functionalities can be implemented.
----
## Usage
[Documentation](https://python-opnsense.oxl.app), [Ansible OPNsense-Collection Docs](https://ansible-opnsense.oxl.app/en/latest/usage/2_basic.html)
```python3
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
```python3
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
```python3
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.
```python3
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:
```bash
ls /tmp/opnsense_client/
# api_calls.log syslog.log
```
The module-specific logs contain performance-profiling.
Raw data
{
"_id": null,
"home_page": null,
"name": "oxl-opnsense-client",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.10",
"maintainer_email": null,
"keywords": "api, client, opnsense, firewall, network, network-as-code, nac, infrastructure-as-code, iac",
"author": null,
"author_email": "Rath Pascal <contact@oxl.at>",
"download_url": "https://files.pythonhosted.org/packages/45/42/d10d5d1ea8181a2824dc2b11bd3d76490fcec642e88af8fe7cc0f966022b/oxl_opnsense_client-25.7.3.post1.tar.gz",
"platform": null,
"description": "# OPNsense API Client\n\n[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/lint.yml)\n[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/unit_test.yml)\n[](https://github.com/O-X-L/opnsense-api-client/actions/workflows/functional_test.yml)\n[](https://pypi.org/project/oxl-opnsense-client/)\n\nThis is a Python3 client for interacting with the official OPNsense API.\n\nIt enables easy management and automation of OPNsense firewalls.\n\nThe base-code is a Fork of [this OPNsense Ansible-Collection](https://github.com/O-X-L/ansible-opnsense) that was refactored for use within raw Python.\n\nThis can be useful if you want to automate your Infrastructure and do not use [Ansible](https://www.ansible.com/how-ansible-works/).\n\nAn interactive CLI interface might be added later on.\n\n<img src=\"https://raw.githubusercontent.com/O-X-L/opnsense-api-client/refs/heads/latest/docs/source/_static/img/intro.gif\" alt=\"Intro GIF\" width=\"70%\"/>\n\n----\n\n## Install\n\n```bash\npip install oxl-opnsense-client\n```\n\nGet to know the available modules:\n\n* [Documentation](https://python-opnsense.oxl.app)\n* [Module list](https://github.com/O-X-L/opnsense-api-client/tree/main/src/oxl_opnsense_client/plugins/modules)\n* [Ansible Docs](https://ansible-opnsense.oxl.app)\n\n----\n\n## Contribute\n\nThe codebase of this library will be automatically synced with the upstream code of [the OPNsense Ansible-Module](https://github.com/O-X-L/ansible-opnsense)!\n\nThus, new features (*and feature-requests*) should be made there.\n\nFeel free to [report issues/bugs](https://github.com/O-X-L/opnsense-api-client/issues), [take part in discussions](https://github.com/O-X-L/opnsense-api-client/discussions) and [add/extend tests](https://github.com/O-X-L/opnsense-api-client/tree/latest/src/tests).\n\nNote: Only the [API-enabled](https://docs.opnsense.org/development/api.html) functionalities can be implemented.\n\n----\n\n## Usage\n\n[Documentation](https://python-opnsense.oxl.app), [Ansible OPNsense-Collection Docs](https://ansible-opnsense.oxl.app/en/latest/usage/2_basic.html)\n\n```python3\nfrom oxl_opnsense_client import Client\n\nwith Client(\n firewall='192.168.10.20',\n port=443, # default\n credential_file='/tmp/.opnsense.txt',\n # token='0pWN/C3tnXem6OoOp0zc9K5GUBoqBKCZ8jj8nc4LEjbFixjM0ELgEyXnb4BIqVgGNunuX0uLThblgp9Z',\n # secret='Vod5ug1kdSu3KlrYSzIZV9Ae9YFMgugCIZdIIYpefPQVhvp6KKuT7ugUIxCeKGvN6tj9uqduOzOzUlv',\n) as c:\n c.test()\n # True\n\n ### CHECK SUPPORTED MODULES ###\n c.list_modules()\n # ['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']\n\n ### CHECK MODULE ARGUMENTS / SPECS ###\n c.module_specs('route')\n # {'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}}}\n c.module_specs('wireguard_show', stdout=True)\n # prints in pretty-JSON\n\n ### CREATE ENTRY ###\n\n c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303})\n # {'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': ''}}}}\n c.run_module('list', params={'target': 'syslog'})\n # {'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'}]}}\n\n ### UPDATING ENTRY ###\n\n c.run_module('syslog', params={'target': '192.168.0.1', 'port': 9941, 'match_fields': ['target']})\n # {'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': ''}}}}\n c.run_module('list', params={'target': 'syslog'})\n # {'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'}]}}\n\n ### DELETING ENTRY ###\n\n c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent', 'match_fields': ['target']})\n # {'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': ''}}}}\n c.run_module('list', params={'target': 'syslog'})\n # {'error': None, 'result': {'changed': False, 'data': []}}\n c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent'})\n # {'error': None, 'result': {'changed': False, 'diff': {}}}\n\n ### CHECK MODE (DRY-RUN) ###\n\n c.run_module('syslog', check_mode=True, params={'target': '192.168.0.1', 'port': 5303})\n # {'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': ''}}}}\n c.run_module('list', params={'target': 'syslog'})\n # {'error': None, 'result': {'changed': False, 'data': []}}\n c.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303, 'state': 'absent'})\n # {'error': None, 'result': {'changed': False, 'diff': {}}}\n```\n\n----\n\n### Credentials\n\n```python3\nfrom oxl_opnsense_client import Client\n\n# use the API credentials-file as downloaded from the WebUI\nc = Client(firewall='<IP>', credential_file='/home/<YOU>/.opnsense.txt')\n\n# use the token/key pair directly\nc = Client(firewall='<IP>', token='<TOKEN>', secret='<SECRET>')\n```\n\n----\n\n### SSL Verification\n\n```python3\nfrom oxl_opnsense_client import Client\n\n# provide the path to your custom CA public-key\nc = Client(\n firewall='<IP>',\n credential_file='/home/<YOU>/.opnsense.txt',\n ssl_ca_file='/home/<YOU>/ca.crt',\n)\n\n# ONLY USE FOR TESTING PURPOSES => you can disable the certificate-verification\nc = Client(\n firewall='<IP>',\n credential_file='/home/<YOU>/.opnsense.txt',\n ssl_verify=False,\n)\n```\n\n----\n\n### Debug Output\n\nThis will show you the performed API calls and their JSON payload.\n\n```python3\nfrom oxl_opnsense_client import Client\nc = Client(\n firewall='<IP>',\n credential_file='/home/<YOU>/.opnsense.txt',\n debug=True,\n)\n\nc.run_module('syslog', params={'target': '192.168.0.1', 'port': 5303})\n# INFO: REQUEST: GET | URL: https://172.17.1.52/api/syslog/settings/get\n# 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\":[]}}}'}'\n# 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\": \"\"}}'\n# 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\"}'}'\n# INFO: REQUEST: POST | URL: https://172.17.1.52/api/syslog/service/reconfigure | HEADERS: '{}'\n# 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\"}'}'\n```\n\nThis information is also logged to files:\n\n```bash\nls /tmp/opnsense_client/\n# api_calls.log syslog.log\n```\n\nThe module-specific logs contain performance-profiling.\n",
"bugtrack_url": null,
"license": null,
"summary": "OXL OPNSense API Client",
"version": "25.7.3.post1",
"project_urls": {
"Documentation": "https://github.com/O-X-L/opnsense-api-client",
"Homepage": "https://www.OXL.at",
"Issues": "https://github.com/O-X-L/opnsense-api-client/issues",
"Repository": "https://github.com/O-X-L/opnsense-api-client.git"
},
"split_keywords": [
"api",
" client",
" opnsense",
" firewall",
" network",
" network-as-code",
" nac",
" infrastructure-as-code",
" iac"
],
"urls": [
{
"comment_text": null,
"digests": {
"blake2b_256": "1169032dda98251baf7ebbd8b719be709965db9f24d49cdeba577e6749dbcf7c",
"md5": "7e44632a933d058fb4b7d357bf348616",
"sha256": "6157b0e036b72467fe625a7d28e84f5dd9c85ec7a83eb90951186d2cc0c889ff"
},
"downloads": -1,
"filename": "oxl_opnsense_client-25.7.3.post1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "7e44632a933d058fb4b7d357bf348616",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.10",
"size": 661203,
"upload_time": "2025-10-12T12:03:04",
"upload_time_iso_8601": "2025-10-12T12:03:04.805873Z",
"url": "https://files.pythonhosted.org/packages/11/69/032dda98251baf7ebbd8b719be709965db9f24d49cdeba577e6749dbcf7c/oxl_opnsense_client-25.7.3.post1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": null,
"digests": {
"blake2b_256": "4542d10d5d1ea8181a2824dc2b11bd3d76490fcec642e88af8fe7cc0f966022b",
"md5": "b2b636a873968d5103943f95425d542c",
"sha256": "3e5dee3f25c7c3f398058a53eb76d6f051993fed5c2f270fe7590a04c484783c"
},
"downloads": -1,
"filename": "oxl_opnsense_client-25.7.3.post1.tar.gz",
"has_sig": false,
"md5_digest": "b2b636a873968d5103943f95425d542c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.10",
"size": 298918,
"upload_time": "2025-10-12T12:03:06",
"upload_time_iso_8601": "2025-10-12T12:03:06.373918Z",
"url": "https://files.pythonhosted.org/packages/45/42/d10d5d1ea8181a2824dc2b11bd3d76490fcec642e88af8fe7cc0f966022b/oxl_opnsense_client-25.7.3.post1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2025-10-12 12:03:06",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "O-X-L",
"github_project": "opnsense-api-client",
"travis_ci": false,
"coveralls": true,
"github_actions": true,
"requirements": [
{
"name": "httpx",
"specs": []
},
{
"name": "ansible-core",
"specs": [
[
"==",
"2.19.*"
]
]
}
],
"lcname": "oxl-opnsense-client"
}