diff --git a/.travis.yml b/.travis.yml index b06bf3b6..2a2fa1d9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ addons: apt: sources: - sourceline: 'ppa:ubuntu-lxc/stable' + - sourceline: 'ppa:wireguard/wireguard' packages: - python-pip - lxd @@ -27,6 +28,8 @@ addons: - libssl-dev - libffi-dev - python-dev + - linux-headers-$(uname -r) + - wireguard-dkms cache: directories: @@ -43,7 +46,7 @@ env: - LXC_NAME=docker LXC_DISTRO=ubuntu LXC_RELEASE=18.04 before_install: - - test "${LXC_NAME}" != "docker" || docker build -t travis/algo . + - test "${LXC_NAME}" != "docker" && sudo modprobe wireguard || docker build -t travis/algo . install: - sudo tar xf $HOME/lxc/cache.tar -C / || echo "Didn't extract cache." @@ -63,8 +66,8 @@ install: script: # - awesome_bot --allow-dupe --skip-save-results *.md docs/*.md --white-list paypal.com,do.co,microsoft.com,https://github.com/trailofbits/algo/archive/master.zip,https://github.com/trailofbits/algo/issues/new -# - shellcheck algo -# - ansible-lint deploy.yml users.yml deploy_client.yml +# - shellcheck algo +# - ansible-lint deploy.yml users.yml deploy_client.yml - ansible-playbook deploy.yml --syntax-check - ./tests/local-deploy.sh diff --git a/CHANGELOG.md b/CHANGELOG.md index 78644798..5d3028a5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,13 @@ +## 30 Apr 2018 +### Added +- WireGuard support + +### Removed +- Android StrongSwan profiles + +### Release notes +- StrongSwan profiles for Android are deprecated now. Use WireGuard + ## 25 Apr 2018 ### Added - DNScrypt-proxy added diff --git a/README.md b/README.md index 53619d10..61d61c54 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ Algo VPN is a set of Ansible scripts that simplify the setup of a personal IPSEC ## Features -* Supports only IKEv2 with strong crypto: AES-GCM, SHA2, and P-256 +* Supports only IKEv2 with strong crypto (AES-GCM, SHA2, and P-256) and [WireGuard](https://www.wireguard.com/) * Generates Apple profiles to auto-configure iOS and macOS devices * Includes a helper script to add and remove users * Blocks ads with a local DNS resolver (optional) @@ -97,7 +97,7 @@ Certificates and configuration files that users will need are placed in the `con ### Android Devices -No version of Android supports IKEv2. Install the [strongSwan VPN Client for Android 4 and newer](https://play.google.com/store/apps/details?id=org.strongswan.android). Import the corresponding user.p12 certificate to your device. See the [Android setup instructions](/docs/client-android.md) for more a more detailed walkthrough. +WireGuard is used to provide VPN services on Android. Install the [WireGuard VPN Client](https://play.google.com/store/apps/details?id=com.wireguard.android). Import the corresponding `wireguard/.conf` file to your device, then setup a new connection with it. See the [Android setup instructions](/docs/client-android.md) for more detailed walkthrough. ### Windows 10 diff --git a/config.cfg b/config.cfg index e71e7d01..731c71de 100644 --- a/config.cfg +++ b/config.cfg @@ -15,6 +15,8 @@ easyrsa_reinit_existent: False vpn_network: 10.19.48.0/24 vpn_network_ipv6: 'fd9d:bc11:4020::/48' +wireguard_enabled: true +wireguard_port: 51820 server_name: "{{ ansible_ssh_host }}" IP_subject_alt_name: "{{ ansible_ssh_host }}" diff --git a/deploy.yml b/deploy.yml index e58f3c5a..532820c7 100644 --- a/deploy.yml +++ b/deploy.yml @@ -64,6 +64,7 @@ roles: - { role: dns_adblocking, tags: [ 'dns', 'adblock' ] } - { role: ssh_tunneling, tags: [ 'ssh_tunneling' ] } + - { role: wireguard, tags: [ 'vpn', 'wireguard' ], when: wireguard_enabled } - { role: vpn, tags: [ 'vpn' ] } post_tasks: diff --git a/docs/client-android.md b/docs/client-android.md index 1175da79..1e98f6d7 100644 --- a/docs/client-android.md +++ b/docs/client-android.md @@ -2,48 +2,6 @@ ## Installation via profiles -1. [Install the strongSwan VPN Client](https://play.google.com/store/apps/details?id=org.strongswan.android). -2. Copy `android_{username}.sswan` and `android_{username}_helper.html` to your phone's internal storage. -3. Open the StrongSwan app and go to 'Import VPN profile'. -4. Select the `android_{username}.sswan` file to configure the VPN with your profile. - -## Manual installation - -**NOTE:** If you are a Project Fi user, you must disable WiFi Assistant before continuing. See the [strongSwan documentation](https://wiki.strongswan.org/projects/strongswan/wiki/AndroidVPNClient) for details. - -| Instruction | Screenshot(s) | -| ----------- | ---------- | -| 1. Copy your `{username}.p12` certificate to your phone's internal storage. | | -| 2. [Install the strongSwan VPN Client](https://play.google.com/store/apps/details?id=org.strongswan.android) (Android 4+) | | -| 3. Open the app and tap "ADD VPN PROFILE" in the top right. | [![step3-thumb]][step3-screen] | -| 4. Enter the IP address or hostname of your Algo server and set the "VPN Type" to "IKEv2 Certificate". | [![step4-thumb]][step4-screen] | -| 5. Tap "Select user certificate". You will be shown a prompt, tap "INSTALL". | [![step5-thumb]][step5-screen] | -| 6. Use the "Open from" menu to select your certificate. If you downloaded your certificate to your phone, you may find that using the "Downloads" shortcut results in your `{username}.p12` certificate being grayed out. If this happens go back to the "Open from" menu and tap on the name of your phone. This will bring up the filesystem. From here, navigate to the folder where you saved your cert (such as "Downloads"), and try again. | [![step6-thumb]][step6-screen] | -| 7. Enter the password for your certificate. This password was printed to your console at the end of running the `algo` deployment script. Please note that in some cases, extracting the certificate can take several minutes. | [![step7-thumb]][step7-screen] | -| 8. Give your certificate a name (it will default to your Algo username), and ensure that "Credential use" is set to "VPN and apps". Tap "OK". | [![step8-thumb]][step8-screen] | -| 9. You'll then be brought to another prompt. Ensure your newly imported certificate is selected, and tap "ALLOW". Then, tap "SAVE" in the top right. | [![step9-thumb]][step9-screen] | -| 10. You will be returned to the main menu, and your newly-configured VPN profile should be listed. Tap the profile to connect. | [![step10-thumb]][step10-screen] | - -## Troubleshooting -### Tapping the VPN profile in strongSwan has no effect. -Ensure that "WiFi Assistant" and any other always-on VPNs are disabled before attempting to enable a strongSwan VPN. If any other VPN is active, strongSwan may silently fail to initialize a VPN connection. On Android 7, your can manage your VPNs by going to: Settings > Tap "More" under "Wireless & networks" > VPN > tap the gear icon next to any non-strongSwan VPNs listed and ensure they are disabled. - - -[step3-thumb]: https://i.imgur.com/LPwIGJE.png -[step4-thumb]: https://i.imgur.com/sFkDILg.png -[step5-thumb]: https://i.imgur.com/IliT5oD.png -[step6-thumb]: https://i.imgur.com/oghdCVp.png -[step7-thumb]: https://i.imgur.com/nDzJ7KS.png -[step8-thumb]: https://i.imgur.com/RPXSpCo.png -[step9-thumb]: https://i.imgur.com/uMinDPe.png -[step10-thumb]: https://i.imgur.com/hUEDjdo.png - - -[step3-screen]: https://i.imgur.com/xNMihCd.png -[step4-screen]: https://i.imgur.com/xYjoNNO.png -[step5-screen]: https://i.imgur.com/4qhKT1Z.png -[step6-screen]: https://i.imgur.com/MAaQuxH.png -[step7-screen]: https://i.imgur.com/aT2MPih.png -[step8-screen]: https://i.imgur.com/gvaKzkh.png -[step9-screen]: https://i.imgur.com/eZp8DNb.png -[step10-screen]: https://i.imgur.com/Nd8rYMJ.png +1. [Install the WireGuard VPN Client](https://play.google.com/store/apps/details?id=com.wireguard.android). +2. Copy `wireguard/{username}.conf` to your phone's internal storage. +3. Open the WireGuard app and add a connection using your AlgoVPN configuration file. diff --git a/roles/cloud-azure/tasks/main.yml b/roles/cloud-azure/tasks/main.yml index bee7e982..6a6e9de4 100644 --- a/roles/cloud-azure/tasks/main.yml +++ b/roles/cloud-azure/tasks/main.yml @@ -58,6 +58,12 @@ access: Allow priority: 120 direction: Inbound + - name: AllowWireGuard + protocol: Udp + destination_port_range: "{{ wireguard_port }}" + access: Allow + priority: 130 + direction: Inbound - name: Create a subnet azure_rm_subnet: diff --git a/roles/cloud-ec2/files/stack.yml b/roles/cloud-ec2/files/stack.yml index 5a8abf52..3660613b 100644 --- a/roles/cloud-ec2/files/stack.yml +++ b/roles/cloud-ec2/files/stack.yml @@ -9,6 +9,8 @@ Parameters: Type: String ImageIdParameter: Type: String + WireGuardPort: + Type: String Resources: VPC: Type: AWS::EC2::VPC @@ -132,6 +134,10 @@ Resources: FromPort: '4500' ToPort: '4500' CidrIp: 0.0.0.0/0 + - IpProtocol: udp + FromPort: !Ref WireGuardPort + ToPort: !Ref WireGuardPort + CidrIp: 0.0.0.0/0 Tags: - Key: Name Value: Algo diff --git a/roles/cloud-ec2/tasks/cloudformation.yml b/roles/cloud-ec2/tasks/cloudformation.yml index 032a59b6..7c6fe374 100644 --- a/roles/cloud-ec2/tasks/cloudformation.yml +++ b/roles/cloud-ec2/tasks/cloudformation.yml @@ -11,6 +11,7 @@ InstanceTypeParameter: "{{ cloud_providers.ec2.size }}" PublicSSHKeyParameter: "{{ lookup('file', SSH_keys.public) }}" ImageIdParameter: "{{ ami_image }}" + WireGuardPort: "{{ wireguard_port }}" tags: Environment: Algo register: stack diff --git a/roles/cloud-gce/tasks/main.yml b/roles/cloud-gce/tasks/main.yml index dafa7553..24a825cf 100644 --- a/roles/cloud-gce/tasks/main.yml +++ b/roles/cloud-gce/tasks/main.yml @@ -15,7 +15,7 @@ gce_net: name: "algo-net-{{ server_name }}" fwname: "algo-net-{{ server_name }}-fw" - allowed: "udp:500,4500;tcp:22" + allowed: "udp:500,4500,{{ wireguard_port }};tcp:22" state: "present" mode: auto src_range: 0.0.0.0/0 diff --git a/roles/cloud-lightsail/tasks/main.yml b/roles/cloud-lightsail/tasks/main.yml index 437e8448..31f73e6f 100644 --- a/roles/cloud-lightsail/tasks/main.yml +++ b/roles/cloud-lightsail/tasks/main.yml @@ -22,6 +22,9 @@ - from_port: 500 to_port: 500 protocol: udp + - from_port: "{{ wireguard_port }}" + to_port: "{{ wireguard_port }}" + protocol: udp user_data: | #!/bin/bash mkdir -p /home/ubuntu/.ssh/ diff --git a/roles/cloud-openstack/tasks/main.yml b/roles/cloud-openstack/tasks/main.yml index 63dbb726..d470e89e 100644 --- a/roles/cloud-openstack/tasks/main.yml +++ b/roles/cloud-openstack/tasks/main.yml @@ -20,6 +20,7 @@ - { proto: icmp, port_min: -1, port_max: -1, range: 0.0.0.0/0 } - { proto: udp, port_min: 4500, port_max: 4500, range: 0.0.0.0/0 } - { proto: udp, port_min: 500, port_max: 500, range: 0.0.0.0/0 } + - { proto: udp, port_min: "{{ wireguard_port }}", port_max: "{{ wireguard_port }}", range: 0.0.0.0/0 } - name: Keypair created os_keypair: diff --git a/roles/common/tasks/ubuntu.yml b/roles/common/tasks/ubuntu.yml index e1d97149..e5d9165a 100644 --- a/roles/common/tasks/ubuntu.yml +++ b/roles/common/tasks/ubuntu.yml @@ -89,6 +89,7 @@ - iptables-persistent - cgroup-tools - openssl + - resolvconf sysctl: - item: net.ipv4.ip_forward value: 1 diff --git a/roles/common/templates/50unattended-upgrades.j2 b/roles/common/templates/50unattended-upgrades.j2 index 0c55b702..a902c7ad 100644 --- a/roles/common/templates/50unattended-upgrades.j2 +++ b/roles/common/templates/50unattended-upgrades.j2 @@ -2,6 +2,9 @@ Unattended-Upgrade::Allowed-Origins { "${distro_id}:${distro_codename}-security"; "${distro_id}:${distro_codename}-updates"; +{% if wireguard_enabled %} + "LP-PPA-wireguard-wireguard:${distro_codename}"; +{% endif %} // "${distro_id}:${distro_codename}-proposed"; // "${distro_id}:${distro_codename}-backports"; }; diff --git a/roles/vpn/tasks/client_configs.yml b/roles/vpn/tasks/client_configs.yml index 4c6cbe92..52dff83c 100644 --- a/roles/vpn/tasks/client_configs.yml +++ b/roles/vpn/tasks/client_configs.yml @@ -21,25 +21,6 @@ - "{{ PayloadContent.results }}" no_log: True -- name: Build the strongswan app android config - template: - src: sswan.j2 - dest: configs/{{ IP_subject_alt_name }}/android_{{ item.0 }}.sswan - mode: 0600 - with_together: - - "{{ users }}" - - "{{ PayloadContent.results }}" - no_log: True - -- name: Build the android helper html - template: - src: android_html_helper.j2 - dest: configs/{{ IP_subject_alt_name }}/android_{{ item.0 }}_helper.html - mode: 0600 - with_together: - - "{{ users }}" - no_log: True - - name: Build the client ipsec config file template: src: client_ipsec.conf.j2 diff --git a/roles/vpn/templates/android_html_helper.j2 b/roles/vpn/templates/android_html_helper.j2 deleted file mode 100644 index d27528aa..00000000 --- a/roles/vpn/templates/android_html_helper.j2 +++ /dev/null @@ -1 +0,0 @@ -{{ item.0 }} diff --git a/roles/vpn/templates/rules.v4.j2 b/roles/vpn/templates/rules.v4.j2 index c51568aa..fe2878d6 100644 --- a/roles/vpn/templates/rules.v4.j2 +++ b/roles/vpn/templates/rules.v4.j2 @@ -19,7 +19,7 @@ # - https://github.com/trailofbits/algo/issues/216 # - https://github.com/trailofbits/algo/issues?utf8=%E2%9C%93&q=is%3Aissue%20mtu # - https://serverfault.com/questions/601143/ssh-not-working-over-ipsec-tunnel-strongswan --A FORWARD -s {{ vpn_network }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }} +-A FORWARD -s {{ vpn_network }}{% if wireguard_enabled %},{{ wireguard_vpn_network }}{% endif %} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }} {% endif %} COMMIT @@ -35,7 +35,8 @@ COMMIT :POSTROUTING ACCEPT [0:0] # Allow traffic from the VPN network to the outside world, and replies --A POSTROUTING -s {{ vpn_network }} -m policy --pol none --dir out -j MASQUERADE +-A POSTROUTING -s {{ vpn_network }}{% if wireguard_enabled %},{{ wireguard_vpn_network }}{% endif %} -m policy --pol none --dir out -j MASQUERADE + COMMIT @@ -62,7 +63,7 @@ COMMIT # rate limit ICMP traffic per source -A INPUT -p icmp --icmp-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT # Accept IPSEC traffic to ports 500 (IPSEC) and 4500 (MOBIKE aka IKE + NAT traversal) --A INPUT -p udp -m multiport --dports 500,4500 -j ACCEPT +-A INPUT -p udp -m multiport --dports 500,4500{% if wireguard_enabled %},{{ wireguard_port}}{% endif %} -j ACCEPT # Allow new traffic to port 22 (SSH) -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT # Allow any traffic from the VPN @@ -78,7 +79,7 @@ COMMIT {% if BetweenClients_DROP is defined and BetweenClients_DROP == "Y" %} # Drop traffic between VPN clients --A FORWARD -s {{ vpn_network }} -d {{ vpn_network }} -j DROP +-A FORWARD -s {{ vpn_network }}{% if wireguard_enabled %},{{ wireguard_vpn_network }}{% endif %} -d {{ vpn_network }}{% if wireguard_enabled %},{{ wireguard_vpn_network }}{% endif %} -j DROP {% endif %} # Forward any packet that's part of an established connection @@ -92,4 +93,9 @@ COMMIT # Forward any IPSEC traffic from the VPN network -A FORWARD -m conntrack --ctstate NEW -s {{ vpn_network }} -m policy --pol ipsec --dir in -j ACCEPT +# Forward any traffic from the WireGuard VPN network +{% if wireguard_enabled %} +-A FORWARD -m conntrack --ctstate NEW -s {{ wireguard_vpn_network }} -m policy --pol none --dir in -j ACCEPT +{% endif %} + COMMIT diff --git a/roles/vpn/templates/rules.v6.j2 b/roles/vpn/templates/rules.v6.j2 index 82ca8e16..df0603a8 100644 --- a/roles/vpn/templates/rules.v6.j2 +++ b/roles/vpn/templates/rules.v6.j2 @@ -13,7 +13,7 @@ {% if max_mss is defined %} # MSS is the TCP Max Segment Size # See rules.v4 for a more complete explanation --A FORWARD -s {{ vpn_network_ipv6 }} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }} +-A FORWARD -s {{ vpn_network_ipv6 }}{% if wireguard_enabled %},{{ wireguard_vpn_network_ipv6 }}{% endif %} -p tcp -m tcp --tcp-flags SYN,RST SYN -j TCPMSS --set-mss {{ max_mss }} {% endif %} COMMIT @@ -28,7 +28,7 @@ COMMIT :POSTROUTING ACCEPT [0:0] # Allow traffic from the VPN network to the outside world, and replies --A POSTROUTING -s {{ vpn_network_ipv6 }} -m policy --pol none --dir out -j MASQUERADE +-A POSTROUTING -s {{ vpn_network_ipv6 }}{% if wireguard_enabled %},{{ wireguard_vpn_network_ipv6 }}{% endif %} -m policy --pol none --dir out -j MASQUERADE COMMIT @@ -63,7 +63,7 @@ COMMIT # rate limit ICMP traffic per source -A INPUT -p icmpv6 --icmpv6-type echo-request -m hashlimit --hashlimit-upto 5/s --hashlimit-mode srcip --hashlimit-srcmask 32 --hashlimit-name icmp-echo-drop -j ACCEPT # Accept IPSEC traffic to ports 500 (IPSEC) and 4500 (MOBIKE aka IKE + NAT traversal) --A INPUT -p udp -m multiport --dports 500,4500 -j ACCEPT +-A INPUT -p udp -m multiport --dports 500,4500{% if wireguard_enabled %},{{ wireguard_port}}{% endif %} -j ACCEPT # Allow new traffic to port 22 (SSH) -A INPUT -p tcp --dport 22 -m conntrack --ctstate NEW -j ACCEPT @@ -85,7 +85,7 @@ COMMIT -A INPUT -d fcaa::1 -p udp --dport 53 -j ACCEPT {% if BetweenClients_DROP is defined and BetweenClients_DROP == "Y" %} --A FORWARD -s {{ vpn_network_ipv6 }} -d {{ vpn_network_ipv6 }} -j DROP +-A FORWARD -s {{ vpn_network_ipv6 }}{% if wireguard_enabled %},{{ wireguard_vpn_network_ipv6 }}{% endif %} -d {{ vpn_network_ipv6 }}{% if wireguard_enabled %},{{ wireguard_vpn_network_ipv6 }}{% endif %} -j DROP {% endif %} -A FORWARD -j ICMPV6-CHECK -A FORWARD -p tcp --dport 445 -j DROP @@ -93,6 +93,9 @@ COMMIT -A FORWARD -p tcp -m multiport --ports 137,139 -j DROP -A FORWARD -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT -A FORWARD -m conntrack --ctstate NEW -s {{ vpn_network_ipv6 }} -m policy --pol ipsec --dir in -j ACCEPT +{% if wireguard_enabled %} +-A FORWARD -m conntrack --ctstate NEW -s {{ wireguard_vpn_network_ipv6 }} -m policy --pol none --dir in -j ACCEPT +{% endif %} # Use the ICMPV6-CHECK chain, described above -A ICMPV6-CHECK -p icmpv6 -m hl ! --hl-eq 255 --icmpv6-type router-solicitation -j ICMPV6-CHECK-LOG diff --git a/roles/vpn/templates/sswan.j2 b/roles/vpn/templates/sswan.j2 deleted file mode 100644 index 405d44a2..00000000 --- a/roles/vpn/templates/sswan.j2 +++ /dev/null @@ -1,15 +0,0 @@ -{ - "uuid": "{{ 600000 | random | to_uuid }}", - "name": "Algo {{ IP_subject_alt_name }}", - "type": "ikev2-cert", - "remote": { - "addr": "{{ IP_subject_alt_name }}", - "cert": "{{ PayloadContentCA }}" - }, - "local": { - "p12": "{{ item.1.stdout }}" - }, - "ike-proposal": "{{ ciphers.defaults.ike | replace('!', '') }}", - "esp-proposal": "{{ ciphers.defaults.esp | replace('!', '') }}", - "mtu": 1280 -} diff --git a/roles/wireguard/defaults/main.yml b/roles/wireguard/defaults/main.yml new file mode 100644 index 00000000..d94f3ff6 --- /dev/null +++ b/roles/wireguard/defaults/main.yml @@ -0,0 +1,18 @@ +--- +wireguard_config_path: "configs/{{ IP_subject_alt_name }}/wireguard/" +wireguard_interface: wg0 +wireguard_network_ipv4: + subnet: 10.19.49.0 + prefix: 24 + gateway: 10.19.49.1 + clients_range: 10.19.49 + clients_start: 100 +wireguard_network_ipv6: + subnet: 'fd9d:bc11:4021::' + prefix: 48 + gateway: 'fd9d:bc11:4021::1' + clients_range: 'fd9d:bc11:4021::' + clients_start: 100 +wireguard_vpn_network: "{{ wireguard_network_ipv4['subnet'] }}/{{ wireguard_network_ipv4['prefix'] }}" +wireguard_vpn_network_ipv6: "{{ wireguard_network_ipv6['subnet'] }}/{{ wireguard_network_ipv6['prefix'] }}" +easyrsa_reinit_existent: false diff --git a/roles/wireguard/handlers/main.yml b/roles/wireguard/handlers/main.yml new file mode 100644 index 00000000..1063f5e6 --- /dev/null +++ b/roles/wireguard/handlers/main.yml @@ -0,0 +1,5 @@ +--- +- name: restart wireguard + service: + name: "wg-quick@{{ wireguard_interface }}" + state: restarted diff --git a/roles/wireguard/meta/main.yml b/roles/wireguard/meta/main.yml new file mode 100644 index 00000000..a766ccc1 --- /dev/null +++ b/roles/wireguard/meta/main.yml @@ -0,0 +1,3 @@ +--- +dependencies: + - { role: common, tags: common } diff --git a/roles/wireguard/tasks/keys.yml b/roles/wireguard/tasks/keys.yml new file mode 100644 index 00000000..322f974f --- /dev/null +++ b/roles/wireguard/tasks/keys.yml @@ -0,0 +1,60 @@ +--- +- name: Delete the lock files + file: + dest: "/etc/wireguard/private_{{ item }}.lock" + state: absent + when: easyrsa_reinit_existent|bool == True + with_items: + - "{{ users }}" + - "{{ IP_subject_alt_name }}" + +- name: Generate private keys + command: wg genkey + register: wg_genkey + args: + creates: "/etc/wireguard/private_{{ item }}.lock" + executable: bash + with_items: + - "{{ users }}" + - "{{ IP_subject_alt_name }}" + +- block: + - name: Save private keys + copy: + dest: "{{ wireguard_config_path }}/private/{{ item['item'] }}" + content: "{{ item['stdout'] }}" + mode: "0600" + no_log: true + when: item.changed + with_items: "{{ wg_genkey['results'] }}" + delegate_to: localhost + become: false + + - name: Touch the lock file + file: + dest: "/etc/wireguard/private_{{ item }}.lock" + state: touch + with_items: + - "{{ users }}" + - "{{ IP_subject_alt_name }}" + when: wg_genkey.changed + +- name: Generate public keys + shell: echo "{{ lookup('file', wireguard_config_path + '/private/' + item) }}" | wg pubkey + register: wg_pubkey + changed_when: false + args: + executable: bash + with_items: + - "{{ users }}" + - "{{ IP_subject_alt_name }}" + +- name: Save public keys + copy: + dest: "{{ wireguard_config_path }}/public/{{ item['item'] }}" + content: "{{ item['stdout'] }}" + mode: "0600" + no_log: true + with_items: "{{ wg_pubkey['results'] }}" + delegate_to: localhost + become: false diff --git a/roles/wireguard/tasks/main.yml b/roles/wireguard/tasks/main.yml new file mode 100644 index 00000000..017e2ac3 --- /dev/null +++ b/roles/wireguard/tasks/main.yml @@ -0,0 +1,57 @@ +--- +- name: WireGuard repository configured + apt_repository: + repo: ppa:wireguard/wireguard + state: present + +- name: WireGuard installed + apt: + name: wireguard + state: present + update_cache: true + +- name: Ensure the required directories exist + file: + dest: "{{ wireguard_config_path }}/{{ item }}" + state: directory + recurse: true + with_items: + - private + - public + delegate_to: localhost + become: false + +- name: Generate keys + import_tasks: keys.yml + tags: update-users + +- name: WireGuard configured + template: + src: server.conf.j2 + dest: "/etc/wireguard/{{ wireguard_interface }}.conf" + mode: "0600" + notify: restart wireguard + tags: update-users + +- name: WireGuard reload-module-on-update + file: + dest: /etc/wireguard/.reload-module-on-update + state: touch + +- name: WireGuard users config generated + template: + src: client.conf.j2 + dest: "{{ wireguard_config_path }}/{{ item.1 }}.conf" + mode: "0600" + with_indexed_items: "{{ users }}" + tags: update-users + delegate_to: localhost + become: false + +- name: WireGuard enabled and started + service: + name: "wg-quick@{{ wireguard_interface }}" + state: started + enabled: true + +- meta: flush_handlers diff --git a/roles/wireguard/templates/client.conf.j2 b/roles/wireguard/templates/client.conf.j2 new file mode 100644 index 00000000..59e5d52d --- /dev/null +++ b/roles/wireguard/templates/client.conf.j2 @@ -0,0 +1,10 @@ +[Interface] +PrivateKey = {{ lookup('file', wireguard_config_path + '/private/' + item.1) }} +Address = {{ wireguard_network_ipv4['clients_range'] }}.{{ wireguard_network_ipv4['clients_start'] + item.0 + 1 }}/32{% if ipv6_support %},{{ wireguard_network_ipv6['clients_range'] }}{{ wireguard_network_ipv6['clients_start'] + item.0 + 1 }}/{{ wireguard_network_ipv6['prefix'] }} +{% endif %} +DNS = {{ local_service_ip }} + +[Peer] +PublicKey = {{ lookup('file', wireguard_config_path + '/public/' + IP_subject_alt_name) }} +AllowedIPs = 0.0.0.0/0, ::/0 +Endpoint = {{ IP_subject_alt_name }}:{{ wireguard_port }} diff --git a/roles/wireguard/templates/server.conf.j2 b/roles/wireguard/templates/server.conf.j2 new file mode 100644 index 00000000..a90e3fdc --- /dev/null +++ b/roles/wireguard/templates/server.conf.j2 @@ -0,0 +1,18 @@ +[Interface] +Address = {{ wireguard_network_ipv4['subnet'] }}/{{ wireguard_network_ipv4['prefix'] }}{% if ipv6_support %},{{ wireguard_network_ipv6['gateway'] }}/{{ wireguard_network_ipv6['prefix'] }} +{% endif %} + +DNS = {{ local_service_ip }} +ListenPort = {{ wireguard_port }} +PrivateKey = {{ lookup('file', wireguard_config_path + '/private/' + IP_subject_alt_name) }} +SaveConfig = true +Table = off + +{% for u in users %} + +[Peer] +# {{ u }} +PublicKey = {{ lookup('file', wireguard_config_path + '/public/' + u) }} +AllowedIPs = {{ wireguard_network_ipv4['clients_range'] }}.{{ wireguard_network_ipv4['clients_start'] + loop.index }}/32{% if ipv6_support %},{{ wireguard_network_ipv6['clients_range'] }}{{ wireguard_network_ipv6['clients_start'] + loop.index }}/128 +{% endif %} +{% endfor %} diff --git a/tests/local-deploy.sh b/tests/local-deploy.sh index c151488f..efd127cb 100755 --- a/tests/local-deploy.sh +++ b/tests/local-deploy.sh @@ -6,7 +6,7 @@ DEPLOY_ARGS="server_ip=$LXC_IP server_user=ubuntu IP_subject_alt_name=$LXC_IP lo if [ "${LXC_NAME}" == "docker" ] then - docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -e "DEPLOY_ARGS=${DEPLOY_ARGS}" travis/algo /bin/sh -c "chown -R 0:0 /root/.ssh && source env/bin/activate && ansible-playbook deploy.yml -t cloud,local,vpn,dns,ssh_tunneling,security,tests,dns_over_https -e \"${DEPLOY_ARGS}\" --skip-tags apparmor" + docker run -it -v $(pwd)/config.cfg:/algo/config.cfg -v ~/.ssh:/root/.ssh -e "DEPLOY_ARGS=${DEPLOY_ARGS}" travis/algo /bin/sh -c "chown -R 0:0 /root/.ssh && source env/bin/activate && ansible-playbook deploy.yml -t cloud,local,vpn,dns,ssh_tunneling,security,tests,dns_over_https -e \"${DEPLOY_ARGS}\" --skip-tags apparmor,wireguard" else ansible-playbook deploy.yml -t cloud,local,vpn,dns,dns_over_https,ssh_tunneling,tests -e "${DEPLOY_ARGS}" --skip-tags apparmor fi