diff --git a/openvpn/defaults/main.yml b/openvpn/defaults/main.yml index 38026914..fb866932 100644 --- a/openvpn/defaults/main.yml +++ b/openvpn/defaults/main.yml @@ -31,15 +31,20 @@ openvpn_dev: tun openvpn_port: 1194 openvpn_protocol: udp openvpn_server_net: '192.168.254.0 255.255.255.0' -openvpn_push_routes: - - '192.168.253.0 255.255.255.0' +#openvpn_push_routes: [] +# - '192.168.253.0 255.255.255.0' #openvpn_push_settings: # - "dhcp-option DNS 10.66.0.4" +#openvpn_remote_servers: [] + +# openvpn_users_customizations: + # - { user: '', config: '', route: '' } + openvpn_tls_server: True openvpn_dh: /etc/openvpn/dh2048.pem -openvpn_tls_auth: '/etc/openvpn/ta.key 0' +openvpn_tls_auth: '/etc/openvpn/ta.key' openvpn_install_alternative_ca: False openvpn_alternative_ca_name: ca.pem openvpn_ca_dir: False diff --git a/openvpn/tasks/openvpn.yml b/openvpn/tasks/openvpn.yml index 600f039a..c2075e54 100644 --- a/openvpn/tasks/openvpn.yml +++ b/openvpn/tasks/openvpn.yml @@ -1,63 +1,56 @@ --- - block: - name: Install the OpenVPN main packages - apt: pkg={{ item }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - with_items: '{{ openvpn_pkgs }}' + apt: pkg={{ openvpn_pkgs }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - - name: Create the auth, ipp and status subdirs + - name: Create the auth, ipp, ccd and status subdirs file: dest={{ openvpn_conf_dir }}/{{ item }} state=directory owner={{ openvpn_unprivileged_user }} group=root mode=0770 with_items: - ipp - status - auth + - ccd when: openvpn_enabled tags: openvpn - block: - name: Install the OpenVPN radius auth plugin package - apt: pkg={{ item }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - with_items: '{{ openvpn_radius_pkg }}' + apt: pkg={{ openvpn_radius_pkg }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 when: openvpn_radius_auth tags: [ 'openvpn', 'openvpn_radius' ] - - block: - name: apt key for the internal ppa repository. Needed by the openvpn ldap auth with posix groups apt_key: url=http://ppa.research-infrastructures.eu/system/keys/system-archive.asc state=present - when: - - openvpn_ldap_auth - - not openvpn_ldap_without_posix_groups + when: not openvpn_ldap_without_posix_groups - name: Setup the internal apt repository - apt_repository: repo='deb http://ppa.research-infrastructures.eu/system trusty main' - when: - - openvpn_ldap_auth - - not openvpn_ldap_without_posix_groups + apt_repository: repo='deb http://ppa.research-infrastructures.eu/system trusty main' update_cache=yes + when: not openvpn_ldap_without_posix_groups - name: Install the OpenVPN ldap auth plugin package - apt: pkg={{ item }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - with_items: '{{ openvpn_ldap_pkg }}' + apt: pkg={{ openvpn_ldap_pkg }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - name: Install the LDAP auth configuration file template: src=auth-ldap.conf.j2 dest={{ openvpn_conf_dir }}/auth/auth-ldap.conf owner=root group={{ openvpn_unprivileged_group }} mode=0440 notify: Reload OpenVPN - - name: Remove the LDAP auth configuration file if LDAP is not used - file: dest={{ openvpn_conf_dir }}/auth/auth-ldap.conf state=absent - notify: Reload OpenVPN - when: not openvpn_ldap_auth - - when: openvpn_ldap_auth tags: [ 'openvpn', 'openvpn_ldap' ] +- block: + - name: Remove the LDAP auth configuration file if LDAP is not used + file: dest={{ openvpn_conf_dir }}/auth/auth-ldap.conf state=absent + notify: Reload OpenVPN + + when: not openvpn_ldap_auth + tags: [ 'openvpn', 'openvpn_ldap' ] - block: - name: Install the perl libraries needed by the LDAP client authentication script - apt: pkg={{ item }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - with_items: '{{ openvpn_perl_pkg }}' + apt: pkg={{ openvpn_perl_pkg }} state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 - name: Install the perl LDAP auth script template: src=auth-ldap.pl.j2 dest={{ openvpn_conf_dir }}/auth/auth-ldap owner=root group={{ openvpn_unprivileged_group }} mode=0550 @@ -65,14 +58,32 @@ when: openvpn_ldap_perl_auth tags: [ 'openvpn', 'openvpn_ldap' ] - - block: - - name: Install the main OpenVPN configuration file - template: src=openvpn.conf.j2 dest={{ openvpn_conf_dir }}/{{ openvpn_conf_name }} owner=root group={{ openvpn_unprivileged_group }} mode=0440 + - name: Install the main OpenVPN configuration file on the servers + template: src=server.conf.j2 dest={{ openvpn_conf_dir }}/{{ openvpn_conf_name }} owner=root group={{ openvpn_unprivileged_group }} mode=0440 notify: Reload OpenVPN + - name: Install the custom configuration for specific OpenVPN users in the servers + template: src=user-ccd.conf.j2 dest={{ openvpn_conf_dir }}/ccd/{{ item.user }} owner=root group={{ openvpn_unprivileged_group }} mode=0440 + with_items: '{{ openvpn_users_customizations | default([]) }}' + notify: Reload OpenVPN + + - name: Install the easy-rsa package on servers when we use the certificate authentication + apt: pkg=easy-rsa state={{ openvpn_pkg_state }} update_cache=yes cache_valid_time=1800 + when: + - openvpn_cert_auth_enabled + - openvpn_is_master_host + + when: openvpn_mode == 'server' tags: [ 'openvpn', 'openvpn_conf' ] +- block: + - name: Install the main OpenVPN configuration file on the clients + template: src=client.conf.j2 dest={{ openvpn_conf_dir }}/{{ openvpn_conf_name }} owner=root group={{ openvpn_unprivileged_group }} mode=0440 + notify: Reload OpenVPN + + when: openvpn_mode != 'server' + tags: [ 'openvpn', 'openvpn_conf' ] - block: - name: Create the dh file @@ -88,19 +99,23 @@ when: openvpn_is_master_host or not openvpn_ha tags: [ 'openvpn', 'openvpn_conf' ] -# Does not work right now. The error is -# fatal: [gw2.d4science.org -> gw1.d4science.org]: FAILED! => {"changed": false, "failed": true, "msg": "Boolean root not in either boolean list"} -# - block: -# - name: Get the dh file from the master host -# synchronize: src={{ openvpn_conf_dir }}/dh2048.pem dest=rsync://root@{{ ansible_fqdn }}/{{ openvpn_conf_dir }}/dh2048.pem -# delegate_to: '{{ openvpn_master_host }}' +- block: + - name: Get the dh file from the master host + synchronize: + src: '{{ openvpn_conf_dir }}/dh2048.pem' + dest: rsync://root@{{ ansible_fqdn }}/{{ openvpn_conf_dir }}/dh2048.pem + delegate_to: '{{ openvpn_master_host }}' -# - name: Get the ta key from the master host -# synchronize: src={{ openvpn_conf_dir }}/ta.key dest=rsync://root@{{ ansible_fqdn }}/{{ openvpn_conf_dir }}/ta.key -# delegate_to: '{{ openvpn_master_host }}' + - name: Get the ta key from the master host + synchronize: + src: '{{ openvpn_conf_dir }}/ta.key' + dest: rsync://root@{{ ansible_fqdn }}/{{ openvpn_conf_dir }}/ta.key + delegate_to: '{{ openvpn_master_host }}' -# when: openvpn_ha and not openvpn_is_master_host -# tags: [ 'openvpn', 'openvpn_conf', 'openvpn_shared_secrets' ] + when: + - openvpn_ha + - not openvpn_is_master_host + tags: [ 'openvpn', 'openvpn_conf', 'openvpn_shared_secrets' ] - block: diff --git a/openvpn/templates/client.conf.j2 b/openvpn/templates/client.conf.j2 new file mode 100644 index 00000000..81b82d41 --- /dev/null +++ b/openvpn/templates/client.conf.j2 @@ -0,0 +1,118 @@ +############################################## +# Sample client-side OpenVPN 2.0 config file # +# for connecting to multi-client server. # +# # +# This configuration can be used by multiple # +# clients, however each client should have # +# its own cert and key files. # +# # +# On Windows, you might want to rename this # +# file so it has a .ovpn extension # +############################################## + +# Specify that we are a client and that we +# will be pulling certain config file directives +# from the server. +client + +# Use the same setting as you are using on +# the server. +# On most systems, the VPN will not function +# unless you partially or fully disable +# the firewall for the TUN/TAP interface. +dev {{ openvpn_dev }} + +# Are we connecting to a TCP or +# UDP server? Use the same setting as +# on the server. +proto {{ openvpn_protocol }} + +# The hostname/IP and port of the server. +# You can have multiple remote entries +# to load balance between the servers. +{% for srv in openvpn_remote_servers %} +remote {{ srv.host }} {{ srv.port }} +{% endfor %} + +# Choose a random host from the remote +# list for load-balancing. Otherwise +# try hosts in the order specified. +remote-random + +# Keep trying indefinitely to resolve the +# host name of the OpenVPN server. Very useful +# on machines which are not permanently connected +# to the internet such as laptops. +resolv-retry infinite + +# Most clients don't need to bind to +# a specific local port number. +nobind + +{% if openvpn_run_unprivileged %} +# Downgrade privileges after initialization (non-Windows only) +user {{ openvpn_unprivileged_user }} +group {{ openvpn_unprivileged_group }} +{% endif %} + +# Try to preserve some state across restarts. +persist-key +persist-tun + +# If you are connecting through an +# HTTP proxy to reach the actual OpenVPN +# server, put the proxy server/IP and +# port number here. See the man page +# if your proxy server requires +# authentication. +;http-proxy-retry # retry on connection failures +;http-proxy [proxy server] [proxy port #] + +# Wireless networks often produce a lot +# of duplicate packets. Set this flag +# to silence duplicate packet warnings. +;mute-replay-warnings + +# SSL/TLS parms. +# See the server config file for more +# description. It's best to use +# a separate .crt/.key file pair +# for each client. A single ca +# file can be used for all clients. +ca {{ openvpn_ca }} +cert {{ openvpn_cert }} +key {{ openvpn_key }} + +# Verify server certificate by checking that the +# certificate has the correct key usage set. +# This is an important precaution to protect against +# a potential attack discussed here: +# http://openvpn.net/howto.html#mitm +# +# To use this feature, you will need to generate +# your server certificates with the keyUsage set to +# digitalSignature, keyEncipherment +# and the extendedKeyUsage to +# serverAuth +# EasyRSA can do this for you. +{% if openvpn_cert_auth_enabled %} +tls-client +remote-cert-tls server +{% endif %} + +# If a tls-auth key is used on the server +# then every client must also have the key. +tls-auth {{ openvpn_tls_auth }} 1 + +# Select a cryptographic cipher. +# If the cipher option is used on the server +# then you must also specify it here. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + +# Set log file verbosity. +verb {{ openvpn_verbosity_log }} +# Silence repeating messages +mute {{ openvpn_mute_after }} diff --git a/openvpn/templates/openvpn.conf.j2 b/openvpn/templates/openvpn.conf.j2 index 7da699f0..86106c2a 100644 --- a/openvpn/templates/openvpn.conf.j2 +++ b/openvpn/templates/openvpn.conf.j2 @@ -1,8 +1,59 @@ mode {{ openvpn_mode }} dev {{ openvpn_dev }} +port {{ openvpn_port }} +proto {{ openvpn_protocol }} + +{% if openvpn_tls_server %} +tls-server +{% endif %} + +dh {{ openvpn_dh }} +ca {{ openvpn_ca }} +cert {{ openvpn_cert }} +key {{ openvpn_key }} + +topology subnet + server {{ openvpn_server_net }} + ifconfig-pool-persist ipp/ipp.txt + +client-config-dir ccd +# EXAMPLE: Suppose the client +# having the certificate common name "Thelonious" +# also has a small subnet behind his connecting +# machine, such as 192.168.40.128/255.255.255.248. +# First, uncomment out these lines: +;client-config-dir ccd +;route 192.168.40.128 255.255.255.248 +# Then create a file ccd/Thelonious with this line: +# iroute 192.168.40.128 255.255.255.248 +# This will allow Thelonious' private subnet to +# access the VPN. This example will only work +# if you are routing, not bridging, i.e. you are +# using "dev tun" and "server" directives. + +# EXAMPLE: Suppose you want to give +# Thelonious a fixed VPN IP address of 10.9.0.1. +# First uncomment out these lines: +;client-config-dir ccd +;route 10.9.0.0 255.255.255.252 +# Then add this line to ccd/Thelonious: +# ifconfig-push 10.9.0.1 10.9.0.2 + +# Suppose that you want to enable different +# firewall access policies for different groups +# of clients. There are two methods: +# (1) Run multiple OpenVPN daemons, one for each +# group, and firewall the TUN/TAP interface +# for each group/daemon appropriately. +# (2) (Advanced) Create a script to dynamically +# modify the firewall in response to access +# from different clients. See man +# page for more info on learn-address script. +;learn-address ./script + {% for route in openvpn_push_routes %} push "route {{ route }}" {% endfor %} @@ -17,21 +68,20 @@ push "{{ dhcp_opt }}" {% endfor %} {% endif %} -port {{ openvpn_port }} -proto {{ openvpn_protocol }} - -{% if openvpn_tls_server %} -tls-server -{% endif %} - -dh {{ openvpn_dh }} -ca {{ openvpn_ca }} -cert {{ openvpn_cert }} -key {{ openvpn_key }} tls-auth {{ openvpn_tls_auth }} +# Select a cryptographic cipher. +# This config item must be copied to +# the client config file as well. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + + {% if openvpn_compression_enabled %} -comp-lzo +compress lz4-v2 +push "compress lz4-v2" {% endif %} keepalive {{ openvpn_keepalive }} @@ -70,3 +120,7 @@ group {{ openvpn_unprivileged_group }} verb {{ openvpn_verbosity_log }} mute {{ openvpn_mute_after }} + +# Notify the client that when the server restarts so it +# can automatically reconnect. +explicit-exit-notify 1 diff --git a/openvpn/templates/server.conf.j2 b/openvpn/templates/server.conf.j2 new file mode 100644 index 00000000..6ce58212 --- /dev/null +++ b/openvpn/templates/server.conf.j2 @@ -0,0 +1,127 @@ +mode {{ openvpn_mode }} +dev {{ openvpn_dev }} + +port {{ openvpn_port }} +proto {{ openvpn_protocol }} + +topology subnet + +server {{ openvpn_server_net }} + +ifconfig-pool-persist ipp/ipp.txt + +client-config-dir ccd +# EXAMPLE: Suppose the client +# having the certificate common name "Thelonious" +# also has a small subnet behind his connecting +# machine, such as 192.168.40.128/255.255.255.248. +# First, uncomment out these lines: +;route 192.168.40.128 255.255.255.248 +# Then create a file ccd/Thelonious with this line: +# iroute 192.168.40.128 255.255.255.248 +# This will allow Thelonious' private subnet to +# access the VPN. This example will only work +# if you are routing, not bridging, i.e. you are +# using "dev tun" and "server" directives. + +# EXAMPLE: Suppose you want to give +# Thelonious a fixed VPN IP address of 10.9.0.1. +# First uncomment out these lines: +;client-config-dir ccd +;route 10.9.0.0 255.255.255.252 +# Then add this line to ccd/Thelonious: +# ifconfig-push 10.9.0.1 10.9.0.2 + +# Suppose that you want to enable different +# firewall access policies for different groups +# of clients. There are two methods: +# (1) Run multiple OpenVPN daemons, one for each +# group, and firewall the TUN/TAP interface +# for each group/daemon appropriately. +# (2) (Advanced) Create a script to dynamically +# modify the firewall in response to access +# from different clients. See man +# page for more info on learn-address script. +;learn-address ./script + +{% if openvpn_client_routes is defined %} +{% for route in openvpn_client_routes %} +route {{ route }} +{% endfor %} +{% endif %} + +{% if openvpn_push_routes is defined %} +{% for route in openvpn_push_routes %} +push "route {{ route }}" +{% endfor %} +{% endif %} + +{% if openvpn_push_settings is defined %} +{% for dhcp_opt in openvpn_push_settings %} +push "{{ dhcp_opt }}" +{% endfor %} +{% endif %} + +# Select a cryptographic cipher. +# This config item must be copied to +# the client config file as well. +# Note that v2.4 client/server will automatically +# negotiate AES-256-GCM in TLS mode. +# See also the ncp-cipher option in the manpage +cipher AES-256-CBC + +{% if openvpn_compression_enabled %} +compress lz4-v2 +push "compress lz4-v2" +{% endif %} + +keepalive {{ openvpn_keepalive }} + +{% if openvpn_cert_auth_enabled %} +tls-server +{% endif %} + +tls-auth {{ openvpn_tls_auth }} 0 +dh {{ openvpn_dh }} +ca {{ openvpn_ca }} +cert {{ openvpn_cert }} +key {{ openvpn_key }} + +{% if not openvpn_cert_auth_enabled %} +# Disable cert-auth +client-cert-not-required +{% endif %} + +{% if openvpn_username_pam_auth %} +username-as-common-name +# PAM login +plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so login +{% endif %} + +{% if openvpn_ldap_auth %} +plugin /usr/lib/openvpn/openvpn-auth-ldap.so /etc/openvpn/auth/auth-ldap.conf +{% endif %} + +{% if openvpn_ldap_perl_auth %} +auth-user-pass-verify /etc/openvpn/auth/auth-ldap via-env +script-security 3 execve +{% endif %} + +max-clients {{ openvpn_max_clients }} + +persist-tun +persist-key + +status status/openvpn-status.log + +{% if openvpn_run_unprivileged %} +user {{ openvpn_unprivileged_user }} +group {{ openvpn_unprivileged_group }} +{% endif %} + +verb {{ openvpn_verbosity_log }} +mute {{ openvpn_mute_after }} + +# Notify the client that when the server restarts so it +# can automatically reconnect. +explicit-exit-notify 1 diff --git a/openvpn/templates/user-ccd.conf.j2 b/openvpn/templates/user-ccd.conf.j2 new file mode 100644 index 00000000..acb8ebf4 --- /dev/null +++ b/openvpn/templates/user-ccd.conf.j2 @@ -0,0 +1,4 @@ +{{ item.config }} +{% if item.route is defined %}} +{{ item.route }} +{% endif %}