From 3488e660ad3535332f59ba5c613d0e1b558e630b Mon Sep 17 00:00:00 2001 From: Jack Ivanov <17044561+jackivanov@users.noreply.github.com> Date: Thu, 24 May 2018 18:15:27 +0300 Subject: [PATCH] Add WireGuard support for Android (#910) * WireGuard Implementation * Update client-android.md * Update README.md * WireGuard unattended upgrades * Update README.md * reload-module-on-update and syntax fix * SaveConfig to true * Azure firewall. Fixes #962 * Update README.md * Update client-android.md --- .travis.yml | 9 ++- CHANGELOG.md | 10 ++++ README.md | 4 +- config.cfg | 2 + deploy.yml | 1 + docs/client-android.md | 48 +-------------- roles/cloud-azure/tasks/main.yml | 6 ++ roles/cloud-ec2/files/stack.yml | 6 ++ roles/cloud-ec2/tasks/cloudformation.yml | 1 + roles/cloud-gce/tasks/main.yml | 2 +- roles/cloud-lightsail/tasks/main.yml | 3 + roles/cloud-openstack/tasks/main.yml | 1 + roles/common/tasks/ubuntu.yml | 1 + .../common/templates/50unattended-upgrades.j2 | 3 + roles/vpn/tasks/client_configs.yml | 19 ------ roles/vpn/templates/android_html_helper.j2 | 1 - roles/vpn/templates/rules.v4.j2 | 14 +++-- roles/vpn/templates/rules.v6.j2 | 11 ++-- roles/vpn/templates/sswan.j2 | 15 ----- roles/wireguard/defaults/main.yml | 18 ++++++ roles/wireguard/handlers/main.yml | 5 ++ roles/wireguard/meta/main.yml | 3 + roles/wireguard/tasks/keys.yml | 60 +++++++++++++++++++ roles/wireguard/tasks/main.yml | 57 ++++++++++++++++++ roles/wireguard/templates/client.conf.j2 | 10 ++++ roles/wireguard/templates/server.conf.j2 | 18 ++++++ tests/local-deploy.sh | 2 +- 27 files changed, 235 insertions(+), 95 deletions(-) delete mode 100644 roles/vpn/templates/android_html_helper.j2 delete mode 100644 roles/vpn/templates/sswan.j2 create mode 100644 roles/wireguard/defaults/main.yml create mode 100644 roles/wireguard/handlers/main.yml create mode 100644 roles/wireguard/meta/main.yml create mode 100644 roles/wireguard/tasks/keys.yml create mode 100644 roles/wireguard/tasks/main.yml create mode 100644 roles/wireguard/templates/client.conf.j2 create mode 100644 roles/wireguard/templates/server.conf.j2 diff --git a/.travis.yml b/.travis.yml index b06bf3b..2a2fa1d 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 7864479..5d3028a 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 53619d1..61d61c5 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 e71e7d0..731c71d 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 e58f3c5..532820c 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 1175da7..1e98f6d 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 bee7e98..6a6e9de 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 5a8abf5..3660613 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 032a59b..7c6fe37 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 dafa755..24a825c 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 437e844..31f73e6 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 63dbb72..d470e89 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 e1d9714..e5d9165 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 0c55b70..a902c7a 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 4c6cbe9..52dff83 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 d27528a..0000000 --- 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 c51568a..fe2878d 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 82ca8e1..df0603a 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 405d44a..0000000 --- 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 0000000..d94f3ff --- /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 0000000..1063f5e --- /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 0000000..a766ccc --- /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 0000000..322f974 --- /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 0000000..017e2ac --- /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 0000000..59e5d52 --- /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 0000000..a90e3fd --- /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 c151488..efd127c 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