From e52e381aedc81b79a34992a3de038d3f63c4a84b Mon Sep 17 00:00:00 2001 From: Ad Schellevis Date: Thu, 12 Mar 2020 17:47:10 +0100 Subject: [PATCH] firewall add api docs and examples for https://github.com/opnsense/plugins/issues/1720 --- source/development/api/plugins/firewall.rst | 107 ++++++++++++++++++ .../development/api/plugins/firewall.rst.in | 99 ++++++++++++++++ .../api/plugins/firewall.sample_create.py | 44 +++++++ .../api/plugins/firewall.savepoint.py | 38 +++++++ source/manual/firewall.rst | 8 ++ 5 files changed, 296 insertions(+) create mode 100644 source/development/api/plugins/firewall.rst create mode 100644 source/development/api/plugins/firewall.rst.in create mode 100644 source/development/api/plugins/firewall.sample_create.py create mode 100644 source/development/api/plugins/firewall.savepoint.py diff --git a/source/development/api/plugins/firewall.rst b/source/development/api/plugins/firewall.rst new file mode 100644 index 00000000..3bac34c2 --- /dev/null +++ b/source/development/api/plugins/firewall.rst @@ -0,0 +1,107 @@ +Firewall +~~~~~~~~ + +The firewall API plugin is a first step into migrating the legacy firewall components from OPNsense, although it does contain +a user interface, it's main focus is only to provide machine to machine interaction between custom applications and OPNsense +for selected features. + + +.. csv-table:: Resources (FilterController.php) + :header: "Method", "Module", "Controller", "Command", "Parameters" + :widths: 4, 15, 15, 30, 40 + + "``POST``","firewall","filter","addRule","" + "``POST``","firewall","filter","apply","$rollback_revision=null" + "``POST``","firewall","filter","cancelRollback","$rollback_revision" + "``POST``","firewall","filter","delRule","$uuid" + "``GET``","firewall","filter","getRule","$uuid=null" + "``POST``","firewall","filter","revert","$revision" + "``POST``","firewall","filter","savepoint","" + "``*``","firewall","filter","searchRule","" + "``POST``","firewall","filter","setRule","$uuid" + "``POST``","firewall","filter","toggleRule","$uuid,$enabled=null" + + + +----------------------- +Concept +----------------------- + +The firewall plugin injects rules in the standard OPNsense firewall while maintaining visibility on them in the +standard user interface. + +We use our standard :code:`ApiMutableModelControllerBase` to allow crud operations on rule entries and offer a set of +specific actions to apply the new configuration. +Since firewall rules can be quite sensitive with a higher risk of lockout, we also support a rollback mechanism here, +which offers the ability to rollback this components changes. + +.. blockdiag:: + :scale: 100% + + diagram init { + savepoint [label = "savepoint()"]; + administration [label = "administration"]; + apply [label = "apply(savepoint)"]; + cancelRollback [label = "cancelRollback(sp)"]; + savepoint -> administration -> apply ; + apply -> cancelRollback [label = ".. 60s", style = dashed]; + } + + +The diagram above contains the basic steps to change rules, apply and eventually rollback if not being able to access the machine again. +When calling :code:`savepoint()` a new config revision will be created and the timestamp will be returned for later use. +If the :code:`cancelRollback(savepoint)` is not called within 60 seconds, the firewall will rollback to the previous state +identified by the savepoint timestamp (if available). + + +.. Note:: + + The examples in this document disable certificate validation, make sure when using this in a production environment to + remove the :code:`verify=False` from the :code:`requests` calls + +.. Tip:: + + The number of versions kept can be configured as "backup count" in :menuselection:`System -> Configuration -> History`. + This affectively determines within how many configuration changes you can still rollback, if the backup is removed, a rollback + will keep the current state (do nothing). + + +----------------------- +Administration example +----------------------- + +Administrative endpoints are pretty standard use of :code:`ApiMutableModelControllerBase`, the example below searches for +a rule named "OPNsense_fw_api_testrule_1", when not found one will be added otherwise it will print the internal uuid. +Inline you will find a brief description of the steps performed. + + +.. literalinclude:: firewall.sample_create.py + :language: python + :linenos: + :caption: administrative_example.py + + +.. Tip:: + + Since our model contains default values for most attributes, we only need to feed the changes if we would like to keep the + defaults. In this case the TCP/IP version was IPv4 by default for example. In most cases one would like to set all relevant properties + in case defaults change over time. + +----------------------- +Apply / revert example +----------------------- + +This example will disable the rule created in the previous example and apply the changes using a savepoint, since we're not +calling :code:`cancelRollback(savepoint)` it will revert after 60 seconds to the original state. + + +.. literalinclude:: firewall.savepoint.py + :language: python + :linenos: + :caption: savepoint_example.py + + +.. Note:: + + The savepoint will only revert this components changes, other changes won't be affected by this revert, for example + add an additional interface between savepoint and revert won't be affected. \ No newline at end of file diff --git a/source/development/api/plugins/firewall.rst.in b/source/development/api/plugins/firewall.rst.in new file mode 100644 index 00000000..4e72fc83 --- /dev/null +++ b/source/development/api/plugins/firewall.rst.in @@ -0,0 +1,99 @@ +{{ title }} +{{ title_underline }} + +The firewall API plugin is a first step into migrating the legacy firewall components from OPNsense, although it does contain +a user interface, it's main focus is only to provide machine to machine interaction between custom applications and OPNsense +for selected features. + +{% for controller in controllers %} +.. csv-table:: {{controller.type}} ({{controller.filename}}) + :header: "Method", "Module", "Controller", "Command", "Parameters" + :widths: 4, 15, 15, 30, 40 +{% for endpoint in controller.endpoints %} + "``{{endpoint.method}}``","{{endpoint.module}}","{{endpoint.controller}}","{{endpoint.command}}","{{endpoint.parameters}}" +{%- endfor %} +{% endfor %} + + +----------------------- +Concept +----------------------- + +The firewall plugin injects rules in the standard OPNsense firewall while maintaining visibility on them in the +standard user interface. + +We use our standard :code:`ApiMutableModelControllerBase` to allow crud operations on rule entries and offer a set of +specific actions to apply the new configuration. +Since firewall rules can be quite sensitive with a higher risk of lockout, we also support a rollback mechanism here, +which offers the ability to rollback this components changes. + +.. blockdiag:: + :scale: 100% + + diagram init { + savepoint [label = "savepoint()"]; + administration [label = "administration"]; + apply [label = "apply(savepoint)"]; + cancelRollback [label = "cancelRollback(sp)"]; + savepoint -> administration -> apply ; + apply -> cancelRollback [label = ".. 60s", style = dashed]; + } + + +The diagram above contains the basic steps to change rules, apply and eventually rollback if not being able to access the machine again. +When calling :code:`savepoint()` a new config revision will be created and the timestamp will be returned for later use. +If the :code:`cancelRollback(savepoint)` is not called within 60 seconds, the firewall will rollback to the previous state +identified by the savepoint timestamp (if available). + + +.. Note:: + + The examples in this document disable certificate validation, make sure when using this in a production environment to + remove the :code:`verify=False` from the :code:`requests` calls + +.. Tip:: + + The number of versions kept can be configured as "backup count" in :menuselection:`System -> Configuration -> History`. + This affectively determines within how many configuration changes you can still rollback, if the backup is removed, a rollback + will keep the current state (do nothing). + + +----------------------- +Administration example +----------------------- + +Administrative endpoints are pretty standard use of :code:`ApiMutableModelControllerBase`, the example below searches for +a rule named "OPNsense_fw_api_testrule_1", when not found one will be added otherwise it will print the internal uuid. +Inline you will find a brief description of the steps performed. + + +.. literalinclude:: firewall.sample_create.py + :language: python + :linenos: + :caption: administrative_example.py + + +.. Tip:: + + Since our model contains default values for most attributes, we only need to feed the changes if we would like to keep the + defaults. In this case the TCP/IP version was IPv4 by default for example. In most cases one would like to set all relevant properties + in case defaults change over time. + +----------------------- +Apply / revert example +----------------------- + +This example will disable the rule created in the previous example and apply the changes using a savepoint, since we're not +calling :code:`cancelRollback(savepoint)` it will revert after 60 seconds to the original state. + + +.. literalinclude:: firewall.savepoint.py + :language: python + :linenos: + :caption: savepoint_example.py + + +.. Note:: + + The savepoint will only revert this components changes, other changes won't be affected by this revert, for example + add an additional interface between savepoint and revert won't be affected. diff --git a/source/development/api/plugins/firewall.sample_create.py b/source/development/api/plugins/firewall.sample_create.py new file mode 100644 index 00000000..d83d910c --- /dev/null +++ b/source/development/api/plugins/firewall.sample_create.py @@ -0,0 +1,44 @@ +#!/usr/bin/env python3.7 +import requests +import json + +# key + secret from downloaded apikey.txt +api_key="3RhWOno+HwvtmT406I6zw8of8J6n9FOKlWK6U0B+K7stt/fDaJg7bjeF3QAshlScYqC+3o5THy3vQViW" +api_secret="uaBk27NKhQCZSDpfAlG6YJ473MzvsCNiED6kzbYuykzU05fCRkcJADhDm5nxbZt8yREC74ZpvD/vbcEx" + +# define the basics, hostname to use and description used to identify our test rule +rule_description='OPNsense_fw_api_testrule_1' +remote_uri="https://192.168.1.1" + +# search for rule +r = requests.get( + "%s/api/firewall/filter/searchRule?current=1&rowCount=7&searchPhrase=%s" % ( + remote_uri, rule_description + ), + auth=(api_key, api_secret), verify=False +) + +if r.status_code == 200: + response = json.loads(r.text) + if len(response['rows']) == 0: + # create a new rule, identified by rule_description allowing traffic from + # 192.168.0.0/24 to 10.0.0.0/24 using TCP protocol + data = {"rule" : + { + "description": rule_description, + "source_net": "192.168.0.0/24", + "protocol": "TCP", + "destination_net": "10.0.0.0/24" + } + } + r = requests.post( + "%s/api/firewall/filter/addRule" % remote_uri, auth=(api_key, api_secret), verify=False, json=data + ) + if r.status_code == 200: + print("created : %s" % json.loads(r.text)['uuid']) + else: + print("error : %s" % r.text) + + else: + for row in response['rows']: + print ("found uuid %s" % row['uuid']) diff --git a/source/development/api/plugins/firewall.savepoint.py b/source/development/api/plugins/firewall.savepoint.py new file mode 100644 index 00000000..286377d2 --- /dev/null +++ b/source/development/api/plugins/firewall.savepoint.py @@ -0,0 +1,38 @@ +#!/usr/bin/env python3.7 +import requests +import json + +# key + secret from downloaded apikey.txt +api_key="3RhWOno+HwvtmT406I6zw8of8J6n9FOKlWK6U0B+K7stt/fDaJg7bjeF3QAshlScYqC+3o5THy3vQViW" +api_secret="uaBk27NKhQCZSDpfAlG6YJ473MzvsCNiED6kzbYuykzU05fCRkcJADhDm5nxbZt8yREC74ZpvD/vbcEx" + +# define the basics, hostname to use and description used to identify our test rule +rule_description='OPNsense_fw_api_testrule_1' +remote_uri="https://192.168.1.1" + +# search for rule +r = requests.get( + "%s/api/firewall/filter/searchRule?current=1&rowCount=7&searchPhrase=%s" % ( + remote_uri, rule_description + ), + auth=(api_key, api_secret), verify=False +) + +if r.status_code == 200: + response = json.loads(r.text) + if len(response['rows']) > 0: + rule_uuid = response['rows'][0]['uuid'] + r = requests.post("%s/api/firewall/filter/savepoint" % remote_uri, auth=(api_key, api_secret), verify=False) + if r.status_code == 200: + sp_response = json.loads(r.text) + # disable rule + r = requests.post("%s/api/firewall/filter/toggleRule/%s/0" % (remote_uri, rule_uuid), + auth=(api_key, api_secret), verify=False + ) + # apply changes, revert to sp_response['revision'] after 60 seconds + r = requests.post("%s/api/firewall/filter/apply/%s" % (remote_uri, sp_response['revision']), + auth=(api_key, api_secret), verify=False + ) + print("revert to revision %s in 60 seconds (%s changed)" % (sp_response['revision'], rule_uuid)) + else: + print("rule %s not found" % rule_description) diff --git a/source/manual/firewall.rst b/source/manual/firewall.rst index 6809abed..64934c65 100644 --- a/source/manual/firewall.rst +++ b/source/manual/firewall.rst @@ -363,3 +363,11 @@ State Type Influence the state tracking mechanism use and modulate state combined. * None :menuselection:`-->` Do not use state mechanisms to keep track. ==================================== =============================================================================== + +-------------------- +API access +-------------------- + + +Partial API access is provided with the :code:`os-firewall` plugin, which is described in more detail in +the :doc:`firewall <../development/api/plugins/firewall>` api reference manual.