diff --git a/.yamllint.yml b/.yamllint.yml index a65e4d4..8a41797 100644 --- a/.yamllint.yml +++ b/.yamllint.yml @@ -13,7 +13,7 @@ rules: document-start: present: true line-length: - max: 140 + max: 160 octal-values: forbid-implicit-octal: true forbid-explicit-octal: true diff --git a/playbooks/deploy.yml b/playbooks/deploy.yml new file mode 100644 index 0000000..9e4e451 --- /dev/null +++ b/playbooks/deploy.yml @@ -0,0 +1,5 @@ +--- +- name: 'Deploy openvpn server role to host group' + hosts: 'openvpn_server' + roles: + - 'enbewe.openvpn.server' diff --git a/roles/server/defaults/main.yml b/roles/server/defaults/main.yml new file mode 100644 index 0000000..db598c8 --- /dev/null +++ b/roles/server/defaults/main.yml @@ -0,0 +1,19 @@ +--- +server_openvpn_port: '1194' +server_openvpn_config_name: 'server' +server_openvpn_directory: 'server' +server_openvpn_routes: [] +server_openvpn_client_configs: {} +server_openvpn_sysctl_settings: {} + +server_openvpn_ca: '{{ server_openvpn_directory }}/ca.crt' +server_openvpn_cert: '{{ server_openvpn_directory }}/cert.crt' +server_openvpn_key: '{{ server_openvpn_directory }}/cert.key' +server_openvpn_passfile: '{{ server_openvpn_directory }}/cert.pwd' +server_openvpn_crl: '{{ server_openvpn_directory }}/crl.pem' +server_openvpn_dhfile: '{{ server_openvpn_directory }}/dh2048.pem' +server_openvpn_tlsauth: '{{ server_openvpn_directory }}/tls-auth.key' + +server_openvpn_signing_file: '/etc/apt/keyrings/openvpn-repo-public.asc' +server_openvpn_repo_url: 'https://build.openvpn.net/debian/openvpn/stable' +server_openvpn_source_line: 'deb [arch=amd64 signed-by={{ server_openvpn_signing_file }}] {{ server_openvpn_repo_url }} {{ ansible_distribution_release }} main' diff --git a/roles/server/handlers/main.yml b/roles/server/handlers/main.yml new file mode 100644 index 0000000..e2c8652 --- /dev/null +++ b/roles/server/handlers/main.yml @@ -0,0 +1,11 @@ +--- +- name: 'Reload openvpn services' + become: true + ansible.builtin.service: + daemon_reload: true + +- name: 'Restart openvpn server' + become: true + ansible.builtin.service: + name: 'openvpn@{{ server_openvpn_config_name }}' + state: 'restarted' diff --git a/roles/server/tasks/main.yml b/roles/server/tasks/main.yml new file mode 100644 index 0000000..528928e --- /dev/null +++ b/roles/server/tasks/main.yml @@ -0,0 +1,102 @@ +--- +- name: 'Install the official package repository for OpenVPN' + block: + - name: 'Add the signing key' + become: true + ansible.builtin.get_url: + url: 'https://swupdate.openvpn.net/repos/repo-public.gpg' + dest: '{{ server_openvpn_signing_file }}' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + + - name: 'Add the actual repo' + become: true + ansible.builtin.apt_repository: + repo: '{{ server_openvpn_source_line }}' + state: 'present' + +- name: 'Install server software and kernel module' + become: true + ansible.builtin.apt: + name: '{{ item }}' + update_cache: true + state: 'present' + loop: + - 'openvpn' + - 'openvpn-dco-dkms' + +- name: 'Prepare the folder for vpn server files' + become: true + ansible.builtin.file: + path: '{{ item }}' + state: 'directory' + owner: 'root' + group: 'root' + mode: 'u=rwx,g=rx,o=rx' + loop: + - '/etc/openvpn/{{ server_openvpn_directory }}' + - '/etc/openvpn/{{ server_openvpn_directory }}/ccd' + +- name: 'Deploy config files' + become: true + ansible.builtin.template: + src: '{{ item.src }}' + dest: '{{ item.dest }}' + owner: 'root' + group: 'root' + mode: '{{ item.mode }}' + loop: + - src: 'ca.crt.j2' + dest: '/etc/openvpn/{{ server_openvpn_ca }}' + mode: 'u=rw,g=r,o=r' + - src: 'cert.crt.j2' + dest: '/etc/openvpn/{{ server_openvpn_cert }}' + mode: 'u=rw,g=r,o=r' + - src: 'cert.key.j2' + dest: '/etc/openvpn/{{ server_openvpn_key }}' + mode: 'u=rw,g=,o=' + - src: 'cert.pwd.j2' + dest: '/etc/openvpn/{{ server_openvpn_passfile }}' + mode: 'u=rw,g=,o=' + - src: 'crl.pem.j2' + dest: '/etc/openvpn/{{ server_openvpn_crl }}' + mode: 'u=rw,g=r,o=r' + - src: 'tls-auth.key.j2' + dest: '/etc/openvpn/{{ server_openvpn_tlsauth }}' + mode: 'u=rw,g=,o=' + - src: 'dh2048.pem.j2' + dest: '/etc/openvpn/{{ server_openvpn_dhfile }}' + mode: 'u=rw,g=r,o=r' + notify: 'Restart openvpn server' + +- name: 'Deploy client specific config' + become: true + ansible.builtin.template: + src: 'ccd.j2' + dest: '/etc/openvpn/{{ server_openvpn_directory }}/ccd/{{ item.key }}' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + loop: '{{ server_openvpn_client_configs | dict2items }}' + notify: 'Restart openvpn server' + +- name: 'Deploy server config' + become: true + ansible.builtin.template: + src: 'openvpn_server.conf.j2' + dest: '/etc/openvpn/{{ server_openvpn_config_name }}.conf' + owner: 'root' + group: 'root' + mode: 'u=rw,g=r,o=r' + notify: + - 'Reload openvpn services' + - 'Restart openvpn server' + +- name: 'Configure ip forwarding to allow external communication throught the vpn' + become: true + ansible.posix.sysctl: + name: '{{ item.key }}' + value: '{{ item.value }}' + loop: '{{ server_openvpn_sysctl_settings | dict2items }}' + notify: 'Restart openvpn server' diff --git a/roles/server/templates/ca.crt.j2 b/roles/server/templates/ca.crt.j2 new file mode 100644 index 0000000..e24d211 --- /dev/null +++ b/roles/server/templates/ca.crt.j2 @@ -0,0 +1 @@ +{{ server_openvpn_ca_content }} diff --git a/roles/server/templates/ccd.j2 b/roles/server/templates/ccd.j2 new file mode 100644 index 0000000..6b1a02a --- /dev/null +++ b/roles/server/templates/ccd.j2 @@ -0,0 +1 @@ +{{ item.value }} diff --git a/roles/server/templates/cert.crt.j2 b/roles/server/templates/cert.crt.j2 new file mode 100644 index 0000000..43e83af --- /dev/null +++ b/roles/server/templates/cert.crt.j2 @@ -0,0 +1 @@ +{{ server_openvpn_cert_content }} diff --git a/roles/server/templates/cert.key.j2 b/roles/server/templates/cert.key.j2 new file mode 100644 index 0000000..bd1a0ef --- /dev/null +++ b/roles/server/templates/cert.key.j2 @@ -0,0 +1 @@ +{{ server_openvpn_key_content }} diff --git a/roles/server/templates/cert.pwd.j2 b/roles/server/templates/cert.pwd.j2 new file mode 100644 index 0000000..0b90879 --- /dev/null +++ b/roles/server/templates/cert.pwd.j2 @@ -0,0 +1 @@ +{{ server_openvpn_askpass_content }} diff --git a/roles/server/templates/crl.pem.j2 b/roles/server/templates/crl.pem.j2 new file mode 100644 index 0000000..af9ecdf --- /dev/null +++ b/roles/server/templates/crl.pem.j2 @@ -0,0 +1 @@ +{{ server_openvpn_crl_content }} diff --git a/roles/server/templates/dh2048.pem.j2 b/roles/server/templates/dh2048.pem.j2 new file mode 100644 index 0000000..a24248f --- /dev/null +++ b/roles/server/templates/dh2048.pem.j2 @@ -0,0 +1 @@ +{{ server_openvpn_dh_content }} diff --git a/roles/server/templates/openvpn_server.conf.j2 b/roles/server/templates/openvpn_server.conf.j2 new file mode 100644 index 0000000..b5cb4c4 --- /dev/null +++ b/roles/server/templates/openvpn_server.conf.j2 @@ -0,0 +1,111 @@ + ###### ######## ## ## ######## ######## ### ## +## ## ## ### ## ## ## ## ## ## ## +## ## #### ## ## ## ## ## ## ## +## #### ###### ## ## ## ###### ######## ## ## ## +## ## ## ## #### ## ## ## ######### ## +## ## ## ## ### ## ## ## ## ## ## + ###### ######## ## ## ######## ## ## ## ## ######## + +# Reduce the OpenVPN daemon's privileges after initialization +user nobody +group nogroup + +# TCP or UDP server? +proto udp +proto udp6 + +# Subnet mode instead of p2p +topology subnet + +# Which TCP/UDP port should OpenVPN listen on? +port {{ server_openvpn_port }} + +# "dev tun" will create a routed IP tunnel, "dev tap" will create an +# ethernet tunnel +dev tun + +# Enable compression on the VPN link +comp-lzo + +# Maintain a record of client virtual IP address associations in this file. +ifconfig-pool-persist {{ server_openvpn_directory }}/ipp.txt + +# Output a short status file showing current connections, truncated +# and rewritten every minute. +status {{ server_openvpn_directory }}/openvpn-status.log + +# Configure server mode and supply a VPN subnet for OpenVPN to draw client +# addresses from. The server will take subnet ip .1 for itself, the rest will +# be made available to clients. +server {{ server_openvpn_ipv4_pool }} {{ server_openvpn_ipv4_subnet }} +server-ipv6 {{ server_openvpn_ipv6 }} + +{% for route in server_openvpn_routes %} +route {{route.network }} {{ route.subnet }} +{% endfor %} + +# Uncomment this directive to allow different clients to be able +# to "see" each other. +client-to-client + +# Ping every 10 seconds, assume that remote peer is down if no ping received +# during a 120 second time period. +keepalive 10 120 + +# The persist options will try to avoid accessing certain resources on restart +# that may no longer be accessible because of the privilege downgrade. +persist-key +persist-tun + +# Allow client specific configurations +client-config-dir {{ server_openvpn_directory }}/ccd + +# Set the appropriate level of log +# file verbosity. +# +# 0 is silent, except for fatal errors +# 4 is reasonable for general usage +# 5 and 6 can help to debug connection problems +# 9 is extremely verbose +verb 4 + + + ###### ######## ###### ## ## ######## #### ######## ## ## +## ## ## ## ## ## ## ## ## ## ## ## ## +## ## ## ## ## ## ## ## ## #### + ###### ###### ## ## ## ######## ## ## ## + ## ## ## ## ## ## ## ## ## ## +## ## ## ## ## ## ## ## ## ## ## ## + ###### ######## ###### ####### ## ## #### ## ## +# SSL/TLS root certificate (ca), certificate (cert), and private key (key) +ca {{ server_openvpn_ca }} +cert {{ server_openvpn_cert }} +key {{ server_openvpn_key }} + +# Password for certificate provided in separate file +askpass {{ server_openvpn_passfile }} +auth-nocache + +# Verify against revoked certificates +crl-verify {{ server_openvpn_crl }} + +# Diffie hellman parameters +dh {{ server_openvpn_dhfile }} + +# For extra security beyond that provided by SSL/TLS, create an "HMAC firewall" +# to help block DoS attacks and UDP port flooding. +# The server and each client must have a copy of this key. +# The second parameter should be '0' on the server and '1' on the clients. +tls-auth {{ server_openvpn_tlsauth }} 0 + +# Select a cryptographic cipher +cipher AES-256-CBC + +# Improve message authentication +auth SHA256 + +# Enforce TLSv1.2 +tls-version-min 1.2 + +# Limit the available cipersuites to reasonably safe choices +tls-cipher TLS-ECDHE-RSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-ECDSA-WITH-AES-128-GCM-SHA256:TLS-ECDHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256 diff --git a/roles/server/templates/tls-auth.key.j2 b/roles/server/templates/tls-auth.key.j2 new file mode 100644 index 0000000..28b8d46 --- /dev/null +++ b/roles/server/templates/tls-auth.key.j2 @@ -0,0 +1 @@ +{{ server_openvpn_tlsauth_content }}