From a9e41c6511d9ec9181bbda231700a26b097d4df0 Mon Sep 17 00:00:00 2001 From: AnsibleGuy Date: Mon, 11 Mar 2024 20:56:03 +0100 Subject: [PATCH] basic implementation (untested) of openvpn_client (#30) --- README.md | 165 +++++++++--------- docs/source/modules/openvpn.rst | 63 +++++++ plugins/module_utils/main/openvpn_client.py | 70 ++++++++ plugins/modules/openvpn_client.py | 184 ++++++++++++++++++++ plugins/modules/openvpn_server.py | 62 +++++++ 5 files changed, 462 insertions(+), 82 deletions(-) create mode 100644 docs/source/modules/openvpn.rst create mode 100644 plugins/module_utils/main/openvpn_client.py create mode 100644 plugins/modules/openvpn_client.py create mode 100644 plugins/modules/openvpn_server.py diff --git a/README.md b/README.md index a96f0b65..0aa51110 100644 --- a/README.md +++ b/README.md @@ -81,93 +81,94 @@ not implemented => development => [testing](https://github.com/ansibleguy/collec ### Implemented -| Function | Module | Usage | State | -|:--------------------|:-----------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------|:------------| -| **Base** | ansibleguy.opnsense.list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/2_list.html) | stable | -| **Base** | ansibleguy.opnsense.reload | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/2_reload.html) | stable | -| **Services** | ansibleguy.opnsense.service | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/service.html) | stable | -| **Alias** | ansibleguy.opnsense.alias | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias.html) | stable | -| **Alias** | ansibleguy.opnsense.alias_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias_multi.html) | stable | -| **Alias** | ansibleguy.opnsense.alias_purge | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias_multi.html#ansibleguy-opnsense-alias-purge) | unstable | -| **Rules** | ansibleguy.opnsense.rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule.html) | unstable | -| **Rules** | ansibleguy.opnsense.rule_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule_multi.html) | unstable | -| **Rules** | ansibleguy.opnsense.rule_purge | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule_multi.html#ansibleguy-opnsense-rule-purge) | unstable | -| **Savepoints** | ansibleguy.opnsense.savepoint | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/savepoint.html) | unstable | -| **Packages** | ansibleguy.opnsense.package | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/package.html) | stable | -| **System** | ansibleguy.opnsense.system | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/system.html) | stable | -| **Cron-Jobs** | ansibleguy.opnsense.cron | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/cron.html) | stable | -| **Routes** | ansibleguy.opnsense.route | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/route.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_general.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_acl.html) | unstable | -| **DNS** | ansibleguy.opnsense.unbound_forward | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_forwarding.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_dot | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_dot.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_host | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_host.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_domain | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_domain.html) | stable | -| **DNS** | ansibleguy.opnsense.unbound_host_alias | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_host_alias.html) | stable | -| **Syslog** | ansibleguy.opnsense.syslog | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/syslog.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_connection, ansibleguy.opnsense.ipsec_tunnel | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_pool, ansibleguy.opnsense.ipsec_network | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_auth_local | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_auth_remote | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_child | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_vti | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **IPSec** | ansibleguy.opnsense.ipsec_cert | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | -| **Traffic Shaper** | ansibleguy.opnsense.shaper_pipe | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | -| **Traffic Shaper** | ansibleguy.opnsense.shaper_queue | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | -| **Traffic Shaper** | ansibleguy.opnsense.shaper_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | -| **Monit** | ansibleguy.opnsense.monit_service | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | -| **Monit** | ansibleguy.opnsense.monit_alert | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | -| **Monit** | ansibleguy.opnsense.monit_test | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | -| **WireGuard** | ansibleguy.opnsense.wireguard_server | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | -| **WireGuard** | ansibleguy.opnsense.wireguard_peer | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | -| **WireGuard** | ansibleguy.opnsense.wireguard_show | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | -| **WireGuard** | ansibleguy.opnsense.wireguard_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | -| **Interfaces** | ansibleguy.opnsense.interface_vlan | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | -| **Interfaces** | ansibleguy.opnsense.interface_vxlan | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | -| **Interfaces** | ansibleguy.opnsense.interface_vip | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | -| **NAT** | ansibleguy.opnsense.source_nat, ansibleguy.opnsense.snat | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/source_nat.html) | unstable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_diagnostic | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_diagnostic.html) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_general.html) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bfd_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bfd.html#ansibleguy-opnsense-frr-bfd-general) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bfd_neighbor | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bfd.html#ansibleguy-opnsense-frr-bfd-neighbor) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-general) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_neighbor | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-neighbor) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_prefix_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-prefix-list) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_route_map | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-route-map) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_community_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-community-list) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_as_path | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-as-path) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-general) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_prefix_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-prefix-list) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_interface | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-interface) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_network | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-network) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf3_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf3-general) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf3_interface | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf3-interface) | stable | -| **Dynamic Routing** | ansibleguy.opnsense.frr_rip | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_rip.html) | stable | -| **DNS** | ansibleguy.opnsense.bind_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-general) | stable | -| **DNS** | ansibleguy.opnsense.bind_blocklist | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-blocklist) | stable | -| **DNS** | ansibleguy.opnsense.bind_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-acl) | stable | -| **DNS** | ansibleguy.opnsense.bind_domain | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-domain) | stable | -| **DNS** | ansibleguy.opnsense.bind_record | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-record) | stable | -| **DNS** | ansibleguy.opnsense.bind_record_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-record-multi) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id2) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_cache | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id3) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_parent | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id4) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_traffic | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id5) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_forward | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id7) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id8) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_icap | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id9) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_auth | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id10) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_remote_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id12) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_proxy | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id14) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_match | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id15) | stable | -| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id18) | stable | -| **IDS/IPS** | ansibleguy.opnsense.ids_action | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id2) | unstable | -| **IDS/IPS** | ansibleguy.opnsense.ids_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id3) | unstable | +| Function | Module | Usage | State | +|:--------------------|:-----------------------------------------------------------------------|:------------------------------------------------------------------------------------------------------------------|:---------| +| **Base** | ansibleguy.opnsense.list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/2_list.html) | stable | +| **Base** | ansibleguy.opnsense.reload | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/2_reload.html) | stable | +| **Services** | ansibleguy.opnsense.service | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/service.html) | stable | +| **Alias** | ansibleguy.opnsense.alias | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias.html) | stable | +| **Alias** | ansibleguy.opnsense.alias_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias_multi.html) | stable | +| **Alias** | ansibleguy.opnsense.alias_purge | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/alias_multi.html#ansibleguy-opnsense-alias-purge) | unstable | +| **Rules** | ansibleguy.opnsense.rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule.html) | unstable | +| **Rules** | ansibleguy.opnsense.rule_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule_multi.html) | unstable | +| **Rules** | ansibleguy.opnsense.rule_purge | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/rule_multi.html#ansibleguy-opnsense-rule-purge) | unstable | +| **Savepoints** | ansibleguy.opnsense.savepoint | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/savepoint.html) | unstable | +| **Packages** | ansibleguy.opnsense.package | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/package.html) | stable | +| **System** | ansibleguy.opnsense.system | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/system.html) | stable | +| **Cron-Jobs** | ansibleguy.opnsense.cron | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/cron.html) | stable | +| **Routes** | ansibleguy.opnsense.route | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/route.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_general.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_acl.html) | unstable | +| **DNS** | ansibleguy.opnsense.unbound_forward | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_forwarding.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_dot | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_dot.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_host | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_host.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_domain | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_domain.html) | stable | +| **DNS** | ansibleguy.opnsense.unbound_host_alias | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/unbound_host_alias.html) | stable | +| **Syslog** | ansibleguy.opnsense.syslog | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/syslog.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_connection, ansibleguy.opnsense.ipsec_tunnel | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_pool, ansibleguy.opnsense.ipsec_network | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_auth_local | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_auth_remote | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_child | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_vti | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **IPSec** | ansibleguy.opnsense.ipsec_cert | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ipsec.html) | stable | +| **Traffic Shaper** | ansibleguy.opnsense.shaper_pipe | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | +| **Traffic Shaper** | ansibleguy.opnsense.shaper_queue | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | +| **Traffic Shaper** | ansibleguy.opnsense.shaper_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/shaper.html) | stable | +| **Monit** | ansibleguy.opnsense.monit_service | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | +| **Monit** | ansibleguy.opnsense.monit_alert | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | +| **Monit** | ansibleguy.opnsense.monit_test | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/monit.html) | stable | +| **WireGuard** | ansibleguy.opnsense.wireguard_server | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | +| **WireGuard** | ansibleguy.opnsense.wireguard_peer | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | +| **WireGuard** | ansibleguy.opnsense.wireguard_show | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | +| **WireGuard** | ansibleguy.opnsense.wireguard_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/wireguard.html) | stable | +| **Interfaces** | ansibleguy.opnsense.interface_vlan | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | +| **Interfaces** | ansibleguy.opnsense.interface_vxlan | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | +| **Interfaces** | ansibleguy.opnsense.interface_vip | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/interface.html) | stable | +| **NAT** | ansibleguy.opnsense.source_nat, ansibleguy.opnsense.snat | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/source_nat.html) | unstable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_diagnostic | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_diagnostic.html) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_general.html) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bfd_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bfd.html#ansibleguy-opnsense-frr-bfd-general) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bfd_neighbor | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bfd.html#ansibleguy-opnsense-frr-bfd-neighbor) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-general) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_neighbor | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-neighbor) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_prefix_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-prefix-list) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_route_map | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-route-map) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_community_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-community-list) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_bgp_as_path | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_bgp.html#ansibleguy-opnsense-frr-bgp-as-path) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-general) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_prefix_list | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-prefix-list) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_interface | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-interface) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf_network | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf-network) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf3_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf3-general) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_ospf3_interface | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_ospf.html#ansibleguy-opnsense-frr-ospf3-interface) | stable | +| **Dynamic Routing** | ansibleguy.opnsense.frr_rip | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/frr_rip.html) | stable | +| **DNS** | ansibleguy.opnsense.bind_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-general) | stable | +| **DNS** | ansibleguy.opnsense.bind_blocklist | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-blocklist) | stable | +| **DNS** | ansibleguy.opnsense.bind_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-acl) | stable | +| **DNS** | ansibleguy.opnsense.bind_domain | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-domain) | stable | +| **DNS** | ansibleguy.opnsense.bind_record | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-record) | stable | +| **DNS** | ansibleguy.opnsense.bind_record_multi | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/bind.html#ansibleguy-opnsense-bind-record-multi) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id2) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_cache | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id3) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_parent | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id4) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_traffic | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id5) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_forward | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id7) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id8) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_icap | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id9) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_auth | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id10) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_remote_acl | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id12) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_proxy | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id14) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_match | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id15) | stable | +| **Web Proxy** | ansibleguy.opnsense.webproxy_pac_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/webproxy.html#id18) | stable | +| **IDS/IPS** | ansibleguy.opnsense.ids_action | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id2) | unstable | +| **IDS/IPS** | ansibleguy.opnsense.ids_general | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id3) | unstable | | **IDS/IPS** | ansibleguy.opnsense.ids_ruleset | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id4) | unstable | | **IDS/IPS** | ansibleguy.opnsense.ids_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id5) | unstable | | **IDS/IPS** | ansibleguy.opnsense.ids_user_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id6) | unstable | | **IDS/IPS** | ansibleguy.opnsense.ids_policy | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id7) | unstable | | **IDS/IPS** | ansibleguy.opnsense.ids_policy_rule | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/ids.html#id8) | unstable | +| **OpenVPN** | ansibleguy.opnsense.openvpn_client | [Docs](https://opnsense.ansibleguy.net/en/latest/modules/openvpn.html) | testing | ### Roadmap diff --git a/docs/source/modules/openvpn.rst b/docs/source/modules/openvpn.rst new file mode 100644 index 00000000..be1c1b38 --- /dev/null +++ b/docs/source/modules/openvpn.rst @@ -0,0 +1,63 @@ +.. _modules_openvpn: + +.. include:: ../_include/head.rst + +======= +OpenVPN +======= + +**STATE**: testing + +**TESTS**: `ansibleguy.opnsense.openvpn_client `_ + +**API Docs**: `OpenVPN `_ + +**Service Docs**: `OpenVPN `_ + + +Definition +********** + +ansibleguy.opnsense.openvpn_client +================================== + +.. csv-table:: Definition + :header: "Parameter", "Type", "Required", "Default", "Aliases", "Comment" + :widths: 15 10 10 10 10 45 + + "description","string","true","\-","name, desc","The name used to match this config to existing entries" + "remote","string","true","\-","peer, server","Remote host name or IP address with optional port" + "protocol","string","false","udp","proto","One of: 'udp', 'udp4', 'udp6', 'tcp', 'tcp4', 'tcp6'. Use protocol for communicating with remote host." + "port","integer","false","\-","\-","Port number to use. Specifies a bind address, or nobind when client does not have a specific bind address." + "address","string","false","\-","bind_address, bind, ip","Optional IP address for bind. If specified, OpenVPN will bind to this address only. If unspecified, OpenVPN will bind to all interfaces." + "mode","string","false","tun","type","One of: 'tun', 'tap'. Choose the type of tunnel, OSI Layer 3 [tun] is the most common option to route IPv4 or IPv6 traffic, [tap] offers Ethernet 802.3 (OSI Layer 2) connectivity between hosts and is usually combined with a bridge." + "log_level","integer","false","\-","verbosity, verb","From 0 to 11. Output verbosity level. 0 = no output, 1-4 = normal, 5 = log packets, 6-11 debug" + "keepalive_interval","integer","false","\-","kai","Ping interval in seconds. 0 to disable keep alive" + "keepalive_timeout","integer","false","\-","kat","Causes OpenVPN to restart after n seconds pass without reception of a ping or other packet from remote." + "carp_depend_on","string","false","\-","vip, vip_depend, carp, carp_depend","The CARP VHID to depend on. When this virtual address is not in master state, then the instance will be shutdown." + "certificate","string","true","\-","cert","Certificate to use for this service." + "ca","string","false","\-","certificate_authority, authority","Select a certificate authority when it differs from the attached certificate." + "tls_key","string","false","\-","tls_static_key","Add an additional layer of HMAC authentication on top of the TLS control channel to mitigate DoS attacks and attacks on the TLS stack. The prefixed mode determines if this measurement is only used for authentication (--tls-auth) or includes encryption (--tls-crypt)." + "authentication","string","false","\-","auth, auth_algo","One of: 'BLAKE2b512', 'BLAKE2s256', 'whirlpool', 'none', 'MD4', 'MD5', 'MD5-SHA1', 'RIPEMD160', 'SHA1', 'SHA224', 'SHA256', 'SHA3-224', 'SHA3-256', 'SHA3-384', 'SHA3-512', 'SHA384', 'SHA512', 'SHA512-224', 'SHA512-256', 'SHAKE128', 'SHAKE256'. Authenticate data channel packets and (if enabled) tls-auth control channel packets with HMAC using message digest algorithm alg." + "username","string","false","\-","user","(optional) Username to send to the server for authentication when required." + "password","string","false","\-","pwd","Password belonging to the user specified above" + "renegotiate_time","integer","false","\-","reneg_time, reneg","Renegotiate data channel key after n seconds (default=3600). When using a one time password, be advised that your connection will automatically drop because your password is not valid anymore. Set to 0 to disable, remember to change your client as well." + "network_local","list","false","\-","local, net_local, push_route","These are the networks accessible on this host, these are pushed via route{-ipv6} clauses in OpenVPN to the client" + "network_remote","list","false","\-","remote, net_remote, route","Remote networks for the server, add route to routing table after connection is established" + "options","list","false","\-","opts","One or multiple of: 'client-to-client', 'duplicate-cn', 'passtos', 'persist-remote-ip', 'route-nopull', 'route-noexec', 'remote-random'. Various less frequently used yes/no options which can be set for this instance." + "mtu","integer","false","\-","tun_mtu","Take the TUN device MTU to be tun-mtu and derive the link MTU from it." + "fragment_size","string","false","\-","frag_size","Enable internal datagram fragmentation so that no UDP datagrams are sent which are larger than the specified byte size." + "mss_fix","string","false","\-","mss","Announce to TCP sessions running over the tunnel that they should limit their send packet sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that OpenVPN sends to its peer will not exceed the recommended size." + "reload","boolean","false","true","\-", .. include:: ../_include/param_reload.rst + +.. include:: ../_include/param_basic.rst + +Usage +***** + +The instance description/name is used to match your config to the existing entries. + +Examples +******** + +tbd diff --git a/plugins/module_utils/main/openvpn_client.py b/plugins/module_utils/main/openvpn_client.py new file mode 100644 index 00000000..216243c9 --- /dev/null +++ b/plugins/module_utils/main/openvpn_client.py @@ -0,0 +1,70 @@ +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.api import \ + Session +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ + validate_int_fields +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.cls import BaseModule + + +class Client(BaseModule): + FIELD_ID = 'description' + CMDS = { + 'add': 'addItem', + 'del': 'delItem', + 'set': 'setItem', + 'search': 'get', + 'toggle': 'toggleItem', + } + API_KEY_PATH = 'openvpn.Instances.Instance' + API_MOD = 'openvpn' + API_CONT = 'instances' + API_CONT_REL = 'service' + API_CMD_REL = 'reconfigure' + FIELDS_CHANGE = [] + FIELDS_ALL = ['enabled', FIELD_ID] + FIELDS_ALL.extend(FIELDS_CHANGE) + FIELDS_TRANSLATE = { + 'protocol': 'proto', + 'address': 'local', + 'mode': 'dev_type', + 'log_level': 'verb', + 'certificate': 'cert', + 'ca': 'ca', + 'authentication': 'auth', + 'renegotiate_time': 'reneg-sec', + 'network_local': 'push_route', + 'network_remote': 'route', + 'options': 'various_flags', + 'mtu': 'tun_mtu', + 'fragment_size': 'fragment', + 'mss_fix': 'mssfix', + } + FIELDS_BOOL_INVERT = [] + FIELDS_TYPING = { + 'bool': ['enabled', 'mss_fix'], + 'list': ['network_local', 'network_remote', 'options'], + 'select': [ + 'certificate', 'ca', 'tls_key', 'authentication', 'carp_depend_on', 'log_level', + 'mode', 'protocol', + ], + 'int': ['fragment_size', 'mtu'], + } + INT_VALIDATIONS = { + 'mtu': {'min': 60, 'max': 65535}, + 'fragment_size': {'min': 0, 'max': 65528}, + } + EXIST_ATTR = 'instance' + + def __init__(self, module: AnsibleModule, result: dict, session: Session = None): + BaseModule.__init__(self=self, m=module, r=result, s=session) + self.instance = {} + + def check(self) -> None: + self.p['role'] = 'client' + self.p['log_level'] = f"o{self.p['log_level']}" + + if self.p['state'] == 'present': + validate_int_fields(module=self.m, data=self.p, field_minmax=self.INT_VALIDATIONS) + + self._base_check() diff --git a/plugins/modules/openvpn_client.py b/plugins/modules/openvpn_client.py new file mode 100644 index 00000000..3278e63f --- /dev/null +++ b/plugins/modules/openvpn_client.py @@ -0,0 +1,184 @@ +#!/usr/bin/env python3 + +# Copyright: (C) 2024, AnsibleGuy +# GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.handler import \ + module_dependency_error, MODULE_EXCEPTIONS + +try: + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.wrapper import module_wrapper + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ + diff_remove_empty + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.defaults.main import \ + OPN_MOD_ARGS, STATE_MOD_ARG, RELOAD_MOD_ARG + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main.openvpn_client import Client + +except MODULE_EXCEPTIONS: + module_dependency_error() + + +# DOCUMENTATION = 'https://opnsense.ansibleguy.net/en/latest/modules/openvpn.html' +# EXAMPLES = 'https://opnsense.ansibleguy.net/en/latest/modules/openvpn.html' + +def run_module(): + module_args = dict( + # general + description=dict( + type='str', required=True, default='', aliases=['desc', 'name'], + description='The name used to match this config to existing entries' + ), + remote=dict( + type='str', required=True, aliases=['peer', 'server'], + description='Remote host name or IP address with optional port' + ), + protocol=dict( + type='str', required=False, default='udp', aliases=['proto'], + choices=['udp', 'udp4', 'udp6', 'tcp', 'tcp4', 'tcp6'], + description='Use protocol for communicating with remote host.' + ), + port=dict( + type='str', required=False, default='', + description='Port number to use.' + 'Specifies a bind address, or nobind when client does not have a specific bind address.' + ), + address=dict( + type='str', required=False, default='', aliases=['bind_address', 'ip', 'bind'], + description='Optional IP address for bind.' + 'If specified, OpenVPN will bind to this address only.' + 'If unspecified, OpenVPN will bind to all interfaces.' + ), + mode=dict( + type='str', required=False, default='tun', aliases=['type'], choices=['tun', 'tap'], + description='Choose the type of tunnel, OSI Layer 3 [tun] is the most common option ' + 'to route IPv4 or IPv6 traffic, [tap] offers Ethernet 802.3 (OSI Layer 2) connectivity ' + 'between hosts and is usually combined with a bridge.' + ), + log_level=dict( + type='int', required=False, default=3, aliases=['verbosity', 'verb'], + choices=[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11], + description='Output verbosity level. 0 = no output, 1-4 = normal, 5 = log packets, 6-11 debug' + ), + keepalive_interval=dict( + type='str', required=False, default='', aliases=['kai'], + description='Ping interval in seconds. 0 to disable keep alive' + ), + keepalive_timeout=dict( + type='str', required=False, default='', aliases=['kat'], + description='Causes OpenVPN to restart after n seconds pass without reception of a ' + 'ping or other packet from remote.' + ), + carp_depend_on=dict( + aliases=['vip', 'vip_depend', 'carp', 'carp_depend'], + type='str', required=False, default='', + description='The carp VHID to depend on, when this virtual address is not in ' + 'master state, the interface cost will be set to the demoted cost' + ), + # trust + certificate=dict( + type='str', required=True, default='', aliases=['cert'], + description='Certificate to use for this service.' + ), + ca=dict( + type='str', required=False, default='', aliases=['certificate_authority', 'authority'], + description='Select a certificate authority when it differs from the attached certificate.' + ), + tls_key=dict( + type='str', required=False, default='', aliases=['tls_static_key'], + description='Add an additional layer of HMAC authentication on top of the TLS control channel to ' + 'mitigate DoS attacks and attacks on the TLS stack. The prefixed mode determines if ' + 'this measurement is only used for authentication (--tls-auth) or includes encryption ' + '(--tls-crypt).' + ), + authentication=dict( + type='str', required=False, default='', aliases=['auth', 'auth_algo'], + choices=[ + 'BLAKE2b512', 'BLAKE2s256', 'whirlpool', 'none', + 'MD4', 'MD5', 'MD5-SHA1', 'RIPEMD160', 'SHA1', 'SHA224', 'SHA256', 'SHA3-224', 'SHA3-256', + 'SHA3-384', 'SHA3-512', 'SHA384', 'SHA512', 'SHA512-224', 'SHA512-256', 'SHAKE128', 'SHAKE256', + ], + description='Authenticate data channel packets and (if enabled) tls-auth control channel packets with ' + 'HMAC using message digest algorithm alg.' + ), + # auth + username=dict( + type='str', required=False, default='', aliases=['user'], + description='(optional) Username to send to the server for authentication when required.' + ), + password=dict( + type='str', required=False, default='', aliases=['pwd'], no_log=True, + description='Password belonging to the user specified above' + ), + renegotiate_time=dict( + type='str', required=False, default='', aliases=['reneg_time', 'reneg'], + description='Renegotiate data channel key after n seconds (default=3600). When using a one time ' + 'password, be advised that your connection will automatically drop because your ' + 'password is not valid anymore. Set to 0 to disable, remember to change your ' + 'client as well.' + ), + # routing + network_local=dict( + type='list', elements='str', required=False, default=[], aliases=['local', 'net_local', 'push_route'], + description='These are the networks accessible on this host, these are pushed via route{-ipv6} ' + 'clauses in OpenVPN to the client.' + ), + network_remote=dict( + type='list', elements='str', required=False, default=[], aliases=['remote', 'net_remote', 'route'], + description='Remote networks for the server, add route to routing table after connection is established' + ), + # misc + options=dict( + type='list', elements='str', required=False, default=[], aliases=['opts'], + description='Various less frequently used yes/no options which can be set for this instance.', + choices=[ + 'client-to-client', 'duplicate-cn', 'passtos', 'persist-remote-ip', 'route-nopull', 'route-noexec', + 'remote-random', + ], + ), + mtu=dict( + type='str', required=False, default='', aliases=['tun_mtu'], + description='Take the TUN device MTU to be tun-mtu and derive the link MTU from it.' + ), + fragment_size=dict( + type='str', required=False, default='', aliases=['frag_size'], + description='Enable internal datagram fragmentation so that no UDP datagrams are sent which are larger ' + 'than the specified byte size.' + ), + mss_fix=dict( + type='bool', required=False, default=False, aliases=['mss'], + description='Announce to TCP sessions running over the tunnel that they should limit their send packet ' + 'sizes such that after OpenVPN has encapsulated them, the resulting UDP packet size that ' + 'OpenVPN sends to its peer will not exceed the recommended size.' + ), + **RELOAD_MOD_ARG, + **STATE_MOD_ARG, + **OPN_MOD_ARGS, + ) + + result = dict( + changed=False, + diff={ + 'before': {}, + 'after': {}, + } + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + ) + + module_wrapper(Client(module=module, result=result)) + + result['diff'] = diff_remove_empty(result['diff']) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main() diff --git a/plugins/modules/openvpn_server.py b/plugins/modules/openvpn_server.py new file mode 100644 index 00000000..d031c30b --- /dev/null +++ b/plugins/modules/openvpn_server.py @@ -0,0 +1,62 @@ +#!/usr/bin/env python3 + +# Copyright: (C) 2023, AnsibleGuy +# GNU General Public License v3.0+ (see https://www.gnu.org/licenses/gpl-3.0.txt) + +# template to be copied to implement new modules + +from ansible.module_utils.basic import AnsibleModule + +from ansible_collections.ansibleguy.opnsense.plugins.module_utils.base.handler import \ + module_dependency_error, MODULE_EXCEPTIONS + +try: + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.wrapper import module_wrapper + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.helper.main import \ + diff_remove_empty + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.defaults.main import \ + OPN_MOD_ARGS, STATE_MOD_ARG, RELOAD_MOD_ARG + from ansible_collections.ansibleguy.opnsense.plugins.module_utils.main._tmpl import TMPL + +except MODULE_EXCEPTIONS: + module_dependency_error() + + +# DOCUMENTATION = 'https://opnsense.ansibleguy.net/en/latest/modules/openvpn.html' +# EXAMPLES = 'https://opnsense.ansibleguy.net/en/latest/modules/openvpn.html' + + +def run_module(): + module_args = dict( + description=dict(type='str', required=False, default='', aliases=['desc']), + port=dict(type='int', required=False, default=1194), + **RELOAD_MOD_ARG, + **STATE_MOD_ARG, + **OPN_MOD_ARGS, + ) + + result = dict( + changed=False, + diff={ + 'before': {}, + 'after': {}, + } + ) + + module = AnsibleModule( + argument_spec=module_args, + supports_check_mode=True, + ) + + module_wrapper(TMPL(module=module, result=result)) + + result['diff'] = diff_remove_empty(result['diff']) + module.exit_json(**result) + + +def main(): + run_module() + + +if __name__ == '__main__': + main()