diff --git a/defaults/main.yml b/defaults/main.yml index e15ccae..2f70cca 100755 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -4,26 +4,28 @@ cloud_storage: /opt/storage cloud_stage: prod cloud_update: false -sysctl_configs: - - net.ipv4.ip_forward=1 +vpn_internal_dns: 1.1.1.1 -vpn_host: "vpn.{{ domain_external | default('my-domain.tld') }}" -vpn_protocol: "udp" -vpn_server: "cloud-openvpn" -vpn_cidr: 10.10.10.0 -vpn_mask: 255.255.255.0 -vpn_port: 1194 -vpn_log: /var/log/openvpn/openvpn.log -vpn_dns: - - 208.67.222.222 - - 208.67.220.220 +vpn_allow_adjacent_client_traffic: True +vpn_keepalive: 25 -vpn_clients: - - name: username - state: present +vpn_gateway_clientfolder: /etc/wireguard/clients +vpn_gateway_interface: eth0 +vpn_gateway_host: my-wireguard-server.tld +vpn_gateway_port: 51820 +vpn_gateway_net_prefix: 10.10.123 +vpn_gateway_net_cidr: 28 +vpn_gateway_public_key: your-public-key +vpn_gateway_private_key: your-privat-key -easy_rsa_home: "/usr/share/easy-rsa" +vpn_gateway_forward: [] +# - server_port: 22 +# client_port: "{{ ssh_port }}" +# client_index: 0 -easy_rsa_clients: - - name: easyrsa_username - state: present + +vpn_clients: [] +# - name: +# index: 1 +# private_key: +# public_key: diff --git a/handlers/main.yml b/handlers/main.yml index f377e6f..ed97d53 100755 --- a/handlers/main.yml +++ b/handlers/main.yml @@ -1,9 +1 @@ --- -- name: restart sysctl - command: sysctl -p - -- name: restart openvpn - systemd: - name: openvpn@server - state: restarted - enabled: yes diff --git a/meta/main.yml b/meta/main.yml index 9455611..1313445 100755 --- a/meta/main.yml +++ b/meta/main.yml @@ -1,17 +1,16 @@ --- galaxy_info: role_name: vpn - namespace: hahn-cloud + namespace: opendevchain author: Lars Hahn company: OpenDevChain license: MIT - description: Role to setup an OpenVPN server, to make e.g. personal networks available from remote. + description: Role to setup a wireguard server. min_ansible_version: 2.7 platforms: - name: Debian versions: - - 10 + - 12 galaxy_tags: - vpn -dependencies: - - easy-rsa +dependencies: [] diff --git a/tasks/clients.yml b/tasks/clients.yml deleted file mode 100755 index a2ff28c..0000000 --- a/tasks/clients.yml +++ /dev/null @@ -1,57 +0,0 @@ ---- -- name: install client ovpn configs - template: - src: etc/openvpn/client/client.ovpn.j2 - dest: "{{ vpn_home }}/client/{{ client }}.ovpn" - mode: 0600 - owner: root - group: vpn - loop: "{{ vpn_clients_active }}" - loop_control: - loop_var: client - label: "{{ client }}" - -- name: find abstent clients ovpn config - find: - paths: "{{ vpn_home }}/client/" - pattern: "{{ client }}.*" - loop: "{{ vpn_clients_passive }}" - loop_control: - loop_var: client - label: "{{ client }}" - register: absent_clients - -- name: remove absent clients ovpn config - file: - state: absent - path: "{{ client }}" - loop: "{{ absent_clients.results | json_query('[*].files[*].path') | flatten }}" - loop_control: - loop_var: client - label: "{{ client | basename }}" - when: absent_clients.results | length > 0 - -- name: setup OpenVPN config folder for each vpn client - file: - state: directory - path: "/home/{{ user }}/.openvpn" - mode: 0700 - owner: "{{ user }}" - group: "{{ user }}" - loop: "{{ vpn_clients_active | map('regex_replace','\\.[^\\.]+$','') | list | unique }}" - loop_control: - loop_var: user - label: "{{ user }}" - -- name: rollout .ovpn single-file config for active clients - copy: - src: "{{ vpn_home }}/client/{{ client }}.ovpn" - dest: "/home/{{ client.split('.')[0] }}/.openvpn/" - mode: 0400 - owner: "{{ client.split('.')[0] }}" - group: "{{ client.split('.')[0] }}" - loop: "{{ vpn_clients_active }}" - loop_control: - loop_var: client - label: "{{ client }}" - \ No newline at end of file diff --git a/tasks/main.yml b/tasks/main.yml index 6a787b7..3b89a06 100755 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -1,32 +1,53 @@ --- -- name: install openvpn and recommendations +- name: install fail2ban service apt: update_cache: yes state: "{% if cloud_update | bool %}latest{% else %}present{% endif %}" install_recommends: yes - pkg: - - "openvpn" + pkg: wireguard + register: wireguard_installed -- name: setup sysctl config for openvpn - lineinfile: - path: "{{ sysctl_conf }}" - regexp: '^#?{{ configline.split("=")[0] }}=' - line: "{{ configline }}" - backrefs: yes +- name: setup key files + template: + src: "etc/wireguard/{{ item }}.j2" + dest: "/etc/wireguard/{{ item }}" owner: root - group: root - mode: 0644 - loop: "{{ sysctl_configs }}" - loop_control: - loop_var: configline - label: "{{ configline }}" - notify: restart sysctl + mode: 0600 + loop: + - private.key + - public.key + notify: restart wireguard service -# run in a block only when for every vpn_client user there is a certificate -# otherwise ignore ... -# It is better to have a matching config (dependency currently only to vpn) -# then to catch spectacular cases. -- block: - - include_tasks: server.yml - - include_tasks: clients.yml - when: vpn_clients | difference(easy_rsa_clients) | length == 0 +- name: setup wireguard config + template: + src: "etc/wireguard/wireguard.conf.j2" + dest: "/etc/wireguard/{{ cloud_name }}.conf" + owner: root + mode: 0600 + notify: restart wireguard service + +- name: setup client folder + file: + state: directory + mode: 0600 + owner: root + path: "{{ vpn_gateway_clientfolder }}" + +- name: setup client configs + template: + src: "etc/wireguard/clients/wireguard-client.conf.j2" + dest: "{{ vpn_gateway_clientfolder }}/{{ vpn_client.name }}.conf" + owner: root + mode: 0600 + loop: "{{ vpn_clients }}" + loop_control: + loop_var: vpn_client + label: "{{ vpn_client.name }}" + + +- name: enable wireguard systemd unit + systemd: + name: wg-quick@{{ cloud_name }} + enabled: yes + daemon_reload: yes + state: started diff --git a/tasks/server.yml b/tasks/server.yml deleted file mode 100755 index 11ccb62..0000000 --- a/tasks/server.yml +++ /dev/null @@ -1,78 +0,0 @@ ---- -- name: find installed openvpn clients - find: - paths: "{{ vpn_home }}/client/" - patterns: "*.crt" - register: easyrsa_key_file - -#- name: Setup default OpenVPN configuration -# shell: -# cmd: "gunzip -c {{ vpn_doc_examples }}/server.conf.gz > {{ vpn_home }}/server.conf" -# creates: "{{ vpn_home }}/server.conf" - -- name: Setup default OpenVPN configuration - copy: - src: "{{ vpn_doc_examples }}/server.conf" - dest: "{{ vpn_home }}/server.conf" - owner: root - group: root - force: no - -- name: find server TLS-Auth key - find: - paths: "{{ vpn_home }}/server/" - patterns: "ta.key" - register: tlsauth_key_files - -- name: generate TLS-Auth key - command: "openvpn --genkey --secret {{ vpn_tlsauth_key_file }}" - when: tlsauth_key_files.matched == 0 - -- name: install easy-rsa CA and server certs - copy: - src: "{{ easy_rsa_home }}/pki/{{ item }}" - dest: "{{ vpn_home }}/server/" - mode: 0600 - owner: root - group: root - loop: - - "ca.crt" - - "dh.pem" - - "private/{{ vpn_server }}.key" - - "issued/{{ vpn_server }}.crt" - -- name: setup OpenVPN configuration - lineinfile: - path: "{{ vpn_home }}/server.conf" - regexp: '^;?{{ configline.split(" ")[0] }}{% if configline.split(" ") | length > 1 %} {% endif %}' - line: "{{ configline }}" - owner: root - group: root - mode: 0644 - loop: "{{ vpn_server_conf }}" - loop_control: - loop_var: configline - label: "{{ configline }}" - notify: restart openvpn - -- name: off-setup OpenVPN configuration - lineinfile: - path: "{{ vpn_home }}/server.conf" - regexp: '^{{ configline.split(" ")[0] }}{% if configline.split(" ") | length > 1 %} {% endif %}' - line: ";{{ configline }}" - backrefs: yes - owner: root - group: root - mode: 0644 - loop: "{{ vpn_server_conf_off }}" - loop_control: - loop_var: configline - label: ";{{ configline }}" - notify: restart openvpn - -- name: enable openvpn@server systemd unit - systemd: - name: openvpn@server - enabled: yes - daemon_reload: yes - state: started \ No newline at end of file diff --git a/templates/etc/openvpn/client/client.ovpn.j2 b/templates/etc/openvpn/client/client.ovpn.j2 deleted file mode 100755 index 100a7ac..0000000 --- a/templates/etc/openvpn/client/client.ovpn.j2 +++ /dev/null @@ -1,29 +0,0 @@ -client -dev tun -proto {{ vpn_protocol }} -remote {{ vpn_host }} {{ vpn_port }} -remote-cert-tls server -key-direction 1 -cipher AES-256-CBC -auth SHA512 -auth-nocache -tls-version-min 1.2 -tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 -comp-lzo -nobind -persist-key -persist-tun -mute-replay-warnings -verb 3 - -{{ lookup("file", easy_rsa_home + "/pki/ca.crt") }} - - -{{ lookup("file", easy_rsa_home + "/pki/issued/" + client + ".crt") }} - - -{{ lookup("file", easy_rsa_home + "/pki/private/" + client + ".key") }} - - -{{ lookup("file", vpn_tlsauth_key_file) }} - diff --git a/templates/etc/wireguard/clients/wireguard-client.conf.j2 b/templates/etc/wireguard/clients/wireguard-client.conf.j2 new file mode 100644 index 0000000..1d1b91c --- /dev/null +++ b/templates/etc/wireguard/clients/wireguard-client.conf.j2 @@ -0,0 +1,11 @@ +[Interface] +Address = {{ vpn_gateway_net_prefix }}.{{ vpn_client.index }}/32 +PrivateKey = {{ vpn_client.private_key }} +DNS = {{ vpn_internal_dns }} + +[Peer] +PublicKey = {{ vpn_gateway_public_key }} +Endpoint = {{ vpn_gateway_host }}:{{ vpn_gateway_port }} +AllowedIPs = {{ vpn_gateway_net_prefix }}.1/{% if vpn_allow_adjacent_client_traffic %}{{ vpn_gateway_net_cidr }}{% else %}32{% endif %} + +PersistentKeepalive = {{ vpn_keepalive }} diff --git a/templates/etc/wireguard/private.key.j2 b/templates/etc/wireguard/private.key.j2 new file mode 100644 index 0000000..3fc053d --- /dev/null +++ b/templates/etc/wireguard/private.key.j2 @@ -0,0 +1 @@ +{{ vpn_gateway_private_key }} \ No newline at end of file diff --git a/templates/etc/wireguard/public.key.j2 b/templates/etc/wireguard/public.key.j2 new file mode 100644 index 0000000..7a794c7 --- /dev/null +++ b/templates/etc/wireguard/public.key.j2 @@ -0,0 +1 @@ +{{ vpn_gateway_public_key }} \ No newline at end of file diff --git a/templates/etc/wireguard/wireguard.conf.j2 b/templates/etc/wireguard/wireguard.conf.j2 new file mode 100644 index 0000000..909d8d4 --- /dev/null +++ b/templates/etc/wireguard/wireguard.conf.j2 @@ -0,0 +1,25 @@ +[Interface] +Address = {{ vpn_gateway_net_prefix }}.1/{{ vpn_gateway_net_cidr }} +ListenPort = {{ vpn_gateway_port }} +PrivateKey = {{ vpn_gateway_private_key }} + +{% if vpn_gateway_forward is defined and vpn_gateway_forward | length > 0 %} +PreUp = sysctl -w net.ipv4.ip_forward=1 +PreUp = sysctl -w net.ipv6.conf.all.forwarding=1 + +{% for config in vpn_gateway_forward %} +PreUp = iptables -t nat -A PREROUTING -i {{ vpn_gateway_interface }} -p {{ config.protocol | default('tcp') }} --dport {{ config.server_port }} -j DNAT --to-destination {{ vpn_gateway_net_prefix }}.{{ config.client_index }}:{{ config.client_port }} +PostDown = iptables -t nat -D PREROUTING -i {{ vpn_gateway_interface }} -p {{ config.protocol | default('tcp') }} --dport {{ config.server_port }} -j DNAT --to-destination {{ vpn_gateway_net_prefix }}.{{ config.client_index }}:{{ config.client_port }} + +{% endfor %} +PreUp = iptables -t nat -A POSTROUTING -o {{ cloud_name }} -j MASQUERADE +PostDown = iptables -t nat -D POSTROUTING -o {{ cloud_name }} -j MASQUERADE +{% endif %} + +{% for client in vpn_clients %} +## vpn {{ cloud_name }} - {{ client }} ## +[Peer] +PublicKey = {{ vpn_clients[client].public_key }} +AllowedIPs = {{ vpn_gateway_net_prefix }}.{{ vpn_clients[client].index }}/32 + +{% endfor %} \ No newline at end of file diff --git a/vars/main.yml b/vars/main.yml index 8d090b0..e69de29 100755 --- a/vars/main.yml +++ b/vars/main.yml @@ -1,43 +0,0 @@ ---- -sysctl_path: "/etc/" -sysctl_conf: "{{ sysctl_path }}/sysctl.conf" - -vpn_doc_examples: /usr/share/doc/openvpn/examples/sample-config-files/ - -vpn_home: "/etc/openvpn" - -vpn_clients_active: "{{ vpn_clients | json_query('[?state==`present`].name') }}" -vpn_clients_passive: "{{ vpn_clients | json_query('[?state!=`present`].name') }}" - -vpn_tlsauth_key: ta.key -vpn_tlsauth_key_file: "{{ vpn_home }}/server/{{ vpn_tlsauth_key }}" - -vpn_server_conf: - - "port {{ vpn_port }}" - - "proto {{ vpn_protocol }}" - - dev tun - - "ca {{ vpn_home }}/server/ca.crt" - - "cert {{ vpn_home }}/server/{{ vpn_server }}.crt" - - "key {{ vpn_home }}/server/{{ vpn_server }}.key" - - "dh {{ vpn_home }}/server/dh.pem" - - topology subnet - - "server {{ vpn_cidr }} {{ vpn_mask }}" - - cipher AES-256-CBC - - "tls-auth {{ vpn_home }}/server/ta.key 0" - - tls-version-min 1.2 - - tls-cipher TLS-DHE-RSA-WITH-AES-256-GCM-SHA384:TLS-DHE-RSA-WITH-AES-256-CBC-SHA256:TLS-DHE-RSA-WITH-AES-128-GCM-SHA256:TLS-DHE-RSA-WITH-AES-128-CBC-SHA256 - - auth SHA512 - - auth-nocache - - keepalive 20 60 - - persist-key - - persist-tun - - client-to-client - - comp-lzo - - user nobody - - group nogroup - - "log-append {{ vpn_log }}" - - verb 3 - -vpn_server_conf_off: - - explicit-exit-notify 1 -