bwinfosec.openvpn
TODO: Update this README for the bwinfosec fork changes.
OpenVPN
GitHub Actions (PRs & mainline):
Travis CI (Actually running OpenVPN):
This role installs OpenVPN, configures it as a server, sets up networking and firewalls (mainly firewalld; ufw and iptables are also supported but not guaranteed), and can create client certificates if needed.
Supported OSes in CI build:
- Fedora 32+
- CentOS 7 & 8
Note: You are accessing my code under an open-source license from my personal repository, not my employer.
Requirements
OpenVPN must be available in yum/dnf/apt! For CentOS users, this role will run yum install epel-release
to make sure OpenVPN is available.
Ubuntu precise has a weird bug that may cause installation of iptables-persistent to fail. A workaround exists.
Ansible 2.10 and higher
With Ansible 2.10, modules have moved into collections. You need to install additional collections for certain modules, such as seboolean (now ansible.posix.seboolean). The required collections now are: ansible.posix
and if using ufw: community.general
. Install the collections using:
ansible-galaxy collection install ansible.posix
ansible-galaxy collection install community.general
Support Notes/Expectations
I use this role to manage OpenVPN on CentOS 8. I focus on keeping it fully functional on that platform with the default configuration. Please understand that I am one person with a full-time job and other commitments.
Responses to issues are on a best-effort basis, and I may not respond at all. Issues resulting from non-default settings (including major community contributions) will be lower priority.
Major community contributions:
- Ability to revoke certificates
- Full LDAP support
Role Variables
Role Options
These options modify how the role works. Here's a summary table:
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
clients | list | [] | List of clients to add to OpenVPN | |
openvpn_base_dir | string | /etc/openvpn | Directory where your OpenVPN configurations will be stored | |
openvpn_client_config_no_log | boolean | true, false | true | Prevent logging of client configuration files by Ansible |
openvpn_key_dir | string | /etc/openvpn/keys | Directory for server private keys and CA | |
openvpn_ovpn_dir | string | /etc/openvpn | Directory for client configurations | |
openvpn_revoke_these_certs | list | [] | List of client certificates to revoke | |
openvpn_selinux_module | string | my-openvpn-server | Name of the SELinux module | |
openvpn_service_name | string | openvpn | Name of the service for systemctl | |
openvpn_sync_certs | boolean | true, false | false | Revoke certificates not in the 'clients' list |
openvpn_uninstall | boolean | true, false | false | Set to true to uninstall the OpenVPN service |
openvpn_use_ldap | boolean | true, false | false | Enable LDAP backend for authentication; client certificates not needed anymore |
Config Fetching
Change these options if you need to adjust how the configs are downloaded to your local system:
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_fetch_client_configs | boolean | true, false | true | Download generated client configurations to the local system |
openvpn_fetch_client_configs_dir | string | /tmp/ansible | Directory to download client config files into | |
openvpn_fetch_client_configs_suffix | string | "" | Suffix to append to downloaded client config files before the .ovpn extension |
Firewall
Adjust these options to enforce a specific firewall or change how the playbook interacts with it:
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
firewalld_default_interface_zone | string | public | Firewalld zone where the "ansible_default_ipv4.interface" will be pushed into | |
iptables_service | string | iptables | Override the iptables service name | |
manage_firewall_rules | boolean | true, false | true | Allow the playbook to manage iptables |
openvpn_firewall | string | auto, firewalld, ufw, iptables | auto | The firewall software to configure network rules |
openvpn_masquerade_not_snat | boolean | true, false | false | Set to true to set up MASQUERADE instead of the default SNAT in iptables |
OpenVPN Config Options
These options change how OpenVPN itself works.
Networking
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_client_register_dns | boolean | true, false | true | Add register-dns option to client config (Windows only). |
openvpn_client_to_client | boolean | true, false | false | Set to true for clients to access each other. |
openvpn_custom_dns | list[string] | [] | List of DNS servers, applied if openvpn_set_dns is true |
|
openvpn_dualstack | boolean | true | Whether to use a dualstack (IPv4 + v6) socket | |
openvpn_keepalive_ping | int | 5 | Set keepalive ping interval in seconds. |
|
openvpn_keepalive_timeout | int | 30 | Set keepalive timeout in seconds |
|
openvpn_local | string | unset |
Local host name or IP address to bind; if unspecified, OpenVPN binds to all interfaces | |
openvpn_port | int | 1194 | Desired port for OpenVPN; set different ports in your inventory file if needed | |
openvpn_proto | string | udp, tcp | udp | The protocol for OpenVPN |
openvpn_redirect_gateway | boolean | true, false | true | Defines the OpenVPN gateway push |
openvpn_resolv_retry | int/string | any int, infinite | 5 | Hostname resolve failure retry in seconds. Use "infinite" to retry indefinitely if there are connection issues |
openvpn_server_hostname | string | {{ inventory_hostname }} |
Server name for client configuration | |
openvpn_server_ipv6_network | string | unset |
Network address and prefix for an IPv6 network for clients. | |
openvpn_server_netmask | string | 255.255.255.0 | Netmask for the private network | |
openvpn_server_network | string | 10.9.0.0 | Private network used by OpenVPN service | |
openvpn_set_dns | boolean | true, false | true | Pushes DNS to the client (Cloudflare and Google) |
openvpn_tun_mtu | int | unset |
Sets tun-mtu value; empty for default |
Security
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_auth_alg | string | SHA256 | Set auth authentication algorithm. |
|
openvpn_ca_key | dict | unset |
Contains "crt" and "key". Automatically generate CA cert and key if not set. | |
openvpn_cipher | string | AES-256-CBC | Defines cipher option for server and client. |
|
openvpn_crl_path | string | unset |
Path to CRL file for server revocation check. | |
openvpn_duplicate_cn | boolean | true, false | false | Allows clients to connect multiple times with one key. IP addresses won't be static anymore if set! |
openvpn_rsa_bits | int | 2048 | Number of bits for generated certificates protection. | |
openvpn_script_security | int | 1 | Set OpenVPN script security options. | |
openvpn_tls_auth_key | string | unset |
Single item with a pre-generated TLS authentication key. | |
openvpn_use_crl | boolean | true, false | false | Configure OpenVPN server to respect certificate revocation list. |
openvpn_use_hardened_tls | boolean | true, false | true | Enforce a minimum version of TLS 1.2. |
openvpn_use_modern_tls | boolean | true, false | true | Use modern Cipher for TLS encryption (Not recommended with OpenVPN 2.4). |
openvpn_use_pregenerated_dh_params | boolean | true, false | false | DH params are generated by default during installation. |
openvpn_verify_cn | boolean | true, false | false | Verify that the CN of the certificate matches the FQDN. |
tls_auth_required | boolean | true, false | true | Require the client to push the server's generated ta.key during the connection process. |
Operations
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_addl_client_options | list | empty | List of user-defined client options not already present in the template. (e.g. - mssfix 1400 ) |
|
openvpn_addl_server_options | list | empty | List of user-defined server options not already in the server template. (e.g. - ping-timer-rem ) |
|
openvpn_compression | string | lzo | Sets compress option; empty for no compression. |
|
openvpn_config_file | string | openvpn_{{ openvpn_proto }}_{{ openvpn_port }} | The config file name you wish to use (set in vars/main.yml). | |
openvpn_enable_management | boolean | true, false | false | Enable management interface. |
openvpn_ifconfig_pool_persist_file | string | ipp.txt | Filename for managing IP assignments. | |
openvpn_management_bind | string | /var/run/openvpn/management unix | Interface binding for the management interface. | |
openvpn_management_client_user | string | root | User for Unix socket management interface. | |
openvpn_push | list | empty | List of strings to be inserted into the config file as push "" . E.g., - route 10.20.30.0 255.255.255.0 . |
|
openvpn_script_client_connect | string | unset |
Path to the OpenVPN client-connect script. | |
openvpn_script_client_disconnect | string | unset |
Path to the OpenVPN client-disconnect script. | |
openvpn_script_down | string | unset |
Path to the OpenVPN down script. | |
openvpn_script_up | string | unset |
Path to the OpenVPN up script. | |
openvpn_service_group | string | nogroup | Set the OpenVPN service group. | |
openvpn_service_user | string | nobody | Set the OpenVPN service user. | |
openvpn_status_version | int | 1, 2, 3 | 1 | Define the openvpn-status.log file formatting for current client connections. |
openvpn_topology | string | unset |
Specifies the "topology" keyword in the server config. |
OpenVPN Custom Client Config (Server Pushed)
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_client_config | Boolean | false | Set to true to enable client configuration directory | |
openvpn_client_config_dir | string | ccd | Path for client-config-dir |
|
openvpn_client_configs | dict | {} | Dict of settings for custom client configs |
Logrotate
Set your own custom logrotate options:
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
openvpn_log_dir | string | /var/log | Set location for OpenVPN log files. This is part of log-append configuration value. |
|
openvpn_log_file | string | openvpn.log | Set log filename. This is part of log-append configuration value. |
|
openvpn_logrotate_config | string | rotate 4 weekly missingok notifempty sharedscripts copytruncate delaycompress |
Configure logrotate script. |
Packaging
This role includes several packages. Override as needed:
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
epel_package_name | string | epel-release | Name of the epel-release package to install. | |
iptables_persistent_package_name | string | iptables-persistent | Name of the iptables-persistent package to install. | |
iptables_services_package_name | string | iptables-services | Name of iptables-services package to install. | |
openssl_package_name | string | openssl | Name of openssl package to install. | |
openvpn_ldap_plugin_package_name | string | openvpn-auth-ldap | Name of openvpn-auth-ldap package to install. | |
openvpn_package_name | string | openvpn | Name of the OpenVPN package to install. | |
python_firewall_package_name | string | python-firewall | Name of the python-firewall package to install. |
LDAP Object
Variable | Type | Choices | Default | Comment |
---|---|---|---|---|
ldap | dict | Dictionary that contains LDAP configuration | ||
url | string | ldap://host.example.com | Address of your LDAP backend in ldap[s]://host[:port] format. | |
anonymous_bind | string | False, True | False | Not an Ansible boolean; string pushed into the configuration file. |
bind_dn | string | uid=Manager,ou=People,dc=example,dc=com | Bind DN used if "anonymous_bind" is set to "False". | |
bind_password | string | mysecretpassword | Password for the bind_dn user. | |
tls_enable | string | true, no | no | Force TLS encryption (not necessary with ldaps addresses). |
tls_ca_cert_file | string | /etc/openvpn/auth/ca.pem | Path to the CA for the LDAP backend, must be defined first. | |
tls_cert_file | string | Path to client authentication certificate. | ||
tls_key_file | string | Path to client authentication key. | ||
base_dn | string | ou=People,dc=example,dc=com | Base DN where the backend looks for valid users. | |
search_filter | string | (&(uid=%u)(accountStatus=active)) | LDAP search filter. | |
require_group | string | False, True | Not an Ansible boolean; string pushed into the configuration file. | |
group_base_dn | string | ou=Groups,dc=example,dc=com | Specifies which group to look for; required if require_group is set to "True". | |
group_search_filter | string | ((cn=developers)(cn=artists)) | Specifies valid groups. | |
verify_client_cert | string | none, optional, require | client-cert-not-required | In OpenVPN 2.4+, client-cert-not-required has been deprecated; use verify-client-cert . |
Dependencies
No dependencies on other roles.
Example Playbook
- hosts: vpn
gather_facts: true
roles:
- role: kyl191.openvpn
openvpn_port: 4300
openvpn_sync_certs: true
clients:
- client1
- client2
Note: To help the role identify the remote platform (32 or 64 bits), ensure
gather_facts
is set totrue
in your playbook.
License
MIT
Author Information
Written by Kyle Lexmond
Ansible role to install and configure openvpn.
ansible-galaxy install bwinfosec.openvpn