diff --git a/openvpn/defaults/main.yml b/openvpn/defaults/main.yml index 5feb942..bf13e47 100644 --- a/openvpn/defaults/main.yml +++ b/openvpn/defaults/main.yml @@ -5,14 +5,24 @@ openvpn_pkg_state: latest openvpn_pkgs: - openvpn +# Authentication choices +openvpn_cert_auth_enabled: True +openvpn_username_pam_auth: False + openvpn_radius_auth: False openvpn_radius_pkg: - openvpn-auth-radius +# With openvpn-auth-ldap. Broken on Ubuntu trusty openvpn_ldap_auth: False openvpn_ldap_pkg: - openvpn-auth-ldap +openvpn_ldap_perl_auth: False +openvpn_perl_pkg: + - libnet-ldap-perl + +# Server con parameters openvpn_conf_dir: /etc/openvpn openvpn_conf_name: openvpn.conf @@ -26,12 +36,13 @@ openvpn_push_routes: #openvpn_push_settings: # - "dhcp-option DNS 10.66.0.4" - + openvpn_tls_server: True openvpn_dh: /etc/openvpn/dh2048.pem openvpn_tls_auth: '/etc/openvpn/ta.key 0' openvpn_install_alternative_ca: False openvpn_alternative_ca_name: ca.pem +openvpn_ca_dir: False openvpn_ca: '/var/lib/acme/live/{{ ansible_fqdn }}/chain' openvpn_cert: '/var/lib/acme/live/{{ ansible_fqdn }}/cert' openvpn_key: '/var/lib/acme/live/{{ ansible_fqdn }}/privkey' @@ -39,9 +50,6 @@ openvpn_key: '/var/lib/acme/live/{{ ansible_fqdn }}/privkey' openvpn_compression_enabled: False openvpn_keepalive: '10 120' -openvpn_cert_auth_enabled: True -openvpn_username_pam_auth: False - openvpn_max_clients: 50 openvpn_run_unprivileged: True openvpn_unprivileged_user: nobody @@ -50,3 +58,33 @@ openvpn_letsencrypt_managed: True openvpn_verbosity_log: 3 openvpn_mute_after: 20 + +# LDAP conf +openvpn_ldap_uri: 'ldap:' +openvpn_ldap_host: ldap.example.org +openvpn_ldap_url: '{{ openvpn_ldap_uri }}//{{ openvpn_ldap_host }}' +openvpn_ldap_nonanon_bind: False +openvpn_ldap_binddn: uid=admin +openvpn_ldap_bindpwd: test +openvpn_ldap_ca: '{{ openvpn_ca }}' +openvpn_ldap_use_ca_dir: False +openvpn_ldap_ca_dir: /etc/ssl/certs +openvpn_ldap_starttls: False +openvpn_ldap_tls_auth: False +openvpn_ldap_tls_cert: '{{ openvpn_cert }}' +openvpn_ldap_tls_key: '{{ openvpn_key }}' +openvpn_ldap_tls_ciphersuite: 'ALL:!ADH:@STRENGTH' +# LDAP auth +openvpn_ldap_base_dn: 'ou=People,dc=example,dc=org' +openvpn_ldap_user_search: '(&(uid=%u))' +openvpn_ldap_require_group: False +# See https://github.com/threerings/openvpn-auth-ldap/issues/7 +openvpn_ldap_without_posix_groups: True +openvpn_ldap_group_base: 'ou=Groups,dc=example,dc=org' +openvpn_ldap_group_filter: '(|(cn=developers)(cn=artists))' +openvpn_ldap_group_member_attr: uniqueMember + +# Perl LDAP conf +openvpn_ldap_perl_auth_ssl: True +openvpn_ldap_perl_auth_sslport: 636 +openvpn_ldap_perl_auth_group: vpn_ldap_posix_group diff --git a/openvpn/tasks/openvpn.yml b/openvpn/tasks/openvpn.yml index a3935d0..b3146aa 100644 --- a/openvpn/tasks/openvpn.yml +++ b/openvpn/tasks/openvpn.yml @@ -1,79 +1,113 @@ --- -- name: Install the OpenVPN main packages - apt: pkg={{ item }} state={{ openvpn_pkg_state }} update_cache=yes - with_items: '{{ openvpn_pkgs }}' - tags: openvpn +- 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 }}' -- name: Install the OpenVPN radius auth plugin package - apt: pkg={{ item }} state={{ openvpn_pkg_state }} - with_items: '{{ openvpn_radius_pkg }}' - when: openvpn_radius_auth - tags: openvpn + - name: Create the auth, ipp and status subdirs + file: dest={{ openvpn_conf_dir }}/{{ item }} state=directory owner={{ openvpn_unprivileged_user }} group=root mode=0770 + with_items: + - ipp + - status + - auth -- name: Install the OpenVPN ldap auth plugin package - apt: pkg={{ item }} state={{ openvpn_pkg_state }} - with_items: '{{ openvpn_ldap_pkg }}' - when: openvpn_ldap_auth - tags: openvpn - -- name: Install the OpenVPN PAM auth plugin - shell: cp /usr/lib/openvpn/openvpn-plugin-auth-pam.so {{ openvpn_conf_dir }}/openvpn-plugin-auth-pam.so - args: - creates: '{{ openvpn_conf_dir }}/openvpn-plugin-auth-pam.so' - when: openvpn_username_pam_auth - tags: openvpn - -- name: Remove the OpenVPN PSM auth plugin - file: dest={{ openvpn_conf_dir }}/openvpn-plugin-auth-pam.so state=absent - when: not openvpn_username_pam_auth - tags: openvpn - -- name: Create the ipp and status subdirs - file: dest={{ openvpn_conf_dir }}/{{ item }} state=directory - with_items: - - ipp - - status - tags: openvpn - -- name: Install the main OpenVPN configuration file - template: src=openvpn.conf.j2 dest={{ openvpn_conf_dir }}/{{ openvpn_conf_name }} owner=root group=root mode=0444 - notify: Reload OpenVPN - tags: openvpn - -- name: Create the dh file - shell: openssl dhparam -out {{ openvpn_conf_dir }}/dh2048.pem 2048 ; chmod 444 {{ openvpn_conf_dir }}/dh2048.pem - args: - creates: '{{ openvpn_conf_dir }}/dh2048.pem' - tags: openvpn - -- name: Create the ta key - shell: cd {{ openvpn_conf_dir }} ; openvpn --genkey --secret ta.key ; chmod 400 {{ openvpn_conf_dir }}/ta.key - args: - creates: '{{ openvpn_conf_dir }}/ta.key' - tags: openvpn - -- name: Ensure that the OpenVPN service is enabled and running - service: name=openvpn state=started enabled=yes when: openvpn_enabled tags: openvpn -- name: Ensure that the OpenVPN service is stopped and disabled - service: name=openvpn state=stopped enabled=no - when: not openvpn_enabled +- 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 }}' + + 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 + + - 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 + + - 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 }}' + + - 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: 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 }}' + + - 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 + + 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 + notify: Reload OpenVPN + + - name: Create the dh file + shell: openssl dhparam -out {{ openvpn_conf_dir }}/dh2048.pem 2048 ; chmod 444 {{ openvpn_conf_dir }}/dh2048.pem + args: + creates: '{{ openvpn_conf_dir }}/dh2048.pem' + + - name: Create the ta key + shell: cd {{ openvpn_conf_dir }} ; openvpn --genkey --secret ta.key ; chmod 400 {{ openvpn_conf_dir }}/ta.key + args: + creates: '{{ openvpn_conf_dir }}/ta.key' + + tags: [ 'openvpn', 'openvpn_conf' ] + + +- block: + - name: Enable kernel forwarding + sysctl: name={{ item }} value=1 reload=yes state=present + with_items: + - net.ipv4.ip_forward + # - net.ipv6.conf.all.forwarding + when: + - openvpn_enable_system_forward + - openvpn_enabled + + - name: Disable kernel forwarding + sysctl: name={{ item }} value=0 reload=yes state=present + with_items: + - net.ipv4.ip_forward + # - net.ipv6.conf.all.forwarding + when: not openvpn_enable_system_forward + + - name: Ensure that the OpenVPN service is enabled and running + service: name=openvpn state=started enabled=yes + when: openvpn_enabled + + - name: Ensure that the OpenVPN service is stopped and disabled + service: name=openvpn state=stopped enabled=no + when: not openvpn_enabled + tags: openvpn -- name: Enable kernel forwarding - sysctl: name={{ item }} value=1 reload=yes state=present - with_items: - - net.ipv4.ip_forward -# - net.ipv6.conf.all.forwarding - when: openvpn_enable_system_forward - tags: openvpn - -- name: Disable kernel forwarding - sysctl: name={{ item }} value=0 reload=yes state=present - with_items: - - net.ipv4.ip_forward -# - net.ipv6.conf.all.forwarding - when: not openvpn_enable_system_forward - tags: openvpn diff --git a/openvpn/templates/auth-ldap.conf.j2 b/openvpn/templates/auth-ldap.conf.j2 new file mode 100644 index 0000000..6403aa1 --- /dev/null +++ b/openvpn/templates/auth-ldap.conf.j2 @@ -0,0 +1,67 @@ + + # LDAP server URL + URL {{ openvpn_ldap_url }} + +{% if openvpn_ldap_nonanon_bind %} + # Bind DN (If your LDAP server doesn't support anonymous binds) + BindDN {{ openvpn_ldap_binddn }} + # Bind Password + Password {{ openvpn_ldap_bindpwd }} +{% endif %} + + # Network timeout (in seconds) + Timeout 15 + +{% if openvpn_ldap_starttls %} + # Enable Start TLS + TLSEnable yes +{% endif %} + + # Follow LDAP Referrals (anonymously) + FollowReferrals yes + + # TLS CA Certificate File + TLSCACertFile {{ openvpn_ldap_ca }} + +{% if openvpn_ldap_use_ca_dir %} + # TLS CA Certificate Directory + # TLSCACertDir {{ openvpn_ldap_ca_dir }} +{% endif %} + +{% if openvpn_ldap_tls_auth %} + # Client Certificate and key + # If TLS client authentication is required + TLSCertFile {{ openvpn_ldap_tls_cert }} + TLSKeyFile {{ openvpn_ldap_tls_key }} +{% endif %} + + # Cipher Suite + # The defaults are usually fine here + TLSCipherSuite {{ openvpn_ldap_tls_ciphersuite }} + + + + # Base DN + BaseDN "{{ openvpn_ldap_base_dn }}" + + # User Search Filter + # SearchFilter "(&(uid=%u)(accountStatus=active))" + SearchFilter "{{ openvpn_ldap_user_search }}" + + # Require Group Membership + RequireGroup {{ openvpn_ldap_require_group }} + +{% if openvpn_ldap_require_group %} + # Add non-group members to a PF table (disabled) + #PFTable ips_vpn_users + + + BaseDN "{{ openvpn_ldap_group_base }}" + SearchFilter "{{ openvpn_ldap_group_filter }}" + RFC2307bis {{ openvpn_ldap_without_posix_groups }} + MemberAttribute {{ openvpn_ldap_group_member_attr }} + # Add group members to a PF table (disabled) + # #PFTable ips_vpn_eng + +{% endif %} + diff --git a/openvpn/templates/auth-ldap.pl.j2 b/openvpn/templates/auth-ldap.pl.j2 new file mode 100644 index 0000000..8bd14ae --- /dev/null +++ b/openvpn/templates/auth-ldap.pl.j2 @@ -0,0 +1,42 @@ +#!/usr/bin/perl -w + +{% if openvpn_ldap_perl_auth_ssl %} +use Net::LDAPS; +{% else %} +use Net::LDAP; +{% endif %} +use strict; + +my $ldap; +my $result; + +my $opt_uri = "{{ openvpn_ldap_host }}"; +my $opt_user = $ENV{'username'}; +my $opt_passwd = $ENV{'password'}; +my $opt_group = "cn={{ openvpn_ldap_perl_auth_group }},{{ openvpn_ldap_group_base }}"; +my $opt_binddn = "uid=".$opt_user.",{{ openvpn_ldap_base_dn }}"; + +{% if openvpn_ldap_perl_auth_ssl %} +$ldap = Net::LDAPS->new($opt_uri, version => 3, + port => '{{ openvpn_ldap_perl_auth_sslport }}', + verify => 'require', + {% if openvpn_ca_dir %} + capath => '{{ openvpn_ldap_ca }}' + {% else %} + cafile => '{{ openvpn_ldap_ca }}' + {% endif %} + ) or die("LDAPS connect to $opt_uri failed!"); +{% else %} +$ldap = Net::LDAP->new($opt_uri) or die("LDAP connect to $opt_uri failed!"); +{% endif %} + +{% if openvpn_ldap_nonanon_bind %} +$result = $ldap->bind('{{ openvpn_ldap_binddn }}', password => '{{ openvpn_ldap_bindpwd }}'); +{% else %} +$result = $ldap->bind($opt_binddn, password => $opt_passwd); +{% endif %} +$result->code and die($result->error); +$result = $ldap->search(base=>$opt_group, filter => "(&({{ openvpn_ldap_group_member_attr }}=$opt_user))"); +$result->code(); +if ($result->count == 1) { exit 0; } +unless($result->count){ exit 1; } diff --git a/openvpn/templates/openvpn.conf.j2 b/openvpn/templates/openvpn.conf.j2 index cc08d93..7da699f 100644 --- a/openvpn/templates/openvpn.conf.j2 +++ b/openvpn/templates/openvpn.conf.j2 @@ -44,7 +44,16 @@ client-cert-not-required {% if openvpn_username_pam_auth %} username-as-common-name # PAM login -plugin /etc/openvpn/openvpn-plugin-auth-pam.so 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 }} diff --git a/ubuntu-deb-general/tasks/packages.yml b/ubuntu-deb-general/tasks/packages.yml index dc7ca2c..c34810b 100644 --- a/ubuntu-deb-general/tasks/packages.yml +++ b/ubuntu-deb-general/tasks/packages.yml @@ -53,6 +53,12 @@ ignore_errors: True tags: packages +- name: setup system apt repository for specific distributions + apt_repository: repo='deb http://ppa.research-infrastructures.eu/system {{ ansible_distribution_release }} main' update_cache=yes + when: is_trusty + ignore_errors: True + tags: packages + - name: install common packages apt: pkg={{ item }} state={{ pkg_state }} with_items: '{{ common_packages }}'