diff --git a/group_vars/all/00-secret_template.yml b/group_vars/all/00-secret_template.yml index e7e72c8..94925fa 100644 --- a/group_vars/all/00-secret_template.yml +++ b/group_vars/all/00-secret_template.yml @@ -26,3 +26,18 @@ form_secret: "" # paperless secret key paperless_secret: "" + +wireguard_secret: + # server secret + # generate with `wg genkey`, available in the 'wireguard-tools' package + server_key: "" + # pipe the secret key (see secret_template in group_vars/) into `wg pubkey` to get this + server_pub_key: "" + + # list of clients to generate configs for + peers: + # name of the client + - name: test_client + addr: "10.66.77.2" + priv_key: "" + pub_key: "" diff --git a/inventory.example.yml b/inventory.example.yml index 5f753c1..c203c6d 100644 --- a/inventory.example.yml +++ b/inventory.example.yml @@ -62,6 +62,9 @@ all: haproxy: hosts: your_bastion_host: + wireguard: + hosts: + your_bastion_host: sshd: hosts: your_bastion_host: diff --git a/roles/firewall/tasks/main.yml b/roles/firewall/tasks/main.yml index e3b1178..890eda7 100644 --- a/roles/firewall/tasks/main.yml +++ b/roles/firewall/tasks/main.yml @@ -61,6 +61,11 @@ proto: any src: "{{ local_subnet }}" + - name: "wireguard" + port: "{{ wireguard.ip.port | default('51820') }}" + proto: udp + src: any + - name: Deny all ports by default community.general.ufw: state: enabled diff --git a/roles/networking/nameserver/templates/named.conf.j2 b/roles/networking/nameserver/templates/named.conf.j2 index bfb7cf6..b824ba4 100644 --- a/roles/networking/nameserver/templates/named.conf.j2 +++ b/roles/networking/nameserver/templates/named.conf.j2 @@ -1,6 +1,12 @@ // vim:set ts=4 sw=4 et: -acl internals { 127.0.0.0/8; {{ local_subnet }}; }; +acl internals { + 127.0.0.0/8; + {{ local_subnet }}; + {% if wireguard is defined %} + {{ wireguard.ip.cidr }}; + {% endif %} +}; options { directory "/var/named"; diff --git a/roles/wireguard/defaults/main.yml b/roles/wireguard/defaults/main.yml new file mode 100644 index 0000000..ff3d187 --- /dev/null +++ b/roles/wireguard/defaults/main.yml @@ -0,0 +1,24 @@ +--- +# these are defaults +# change these in group/host vars + +# NOTE: copy the *entire* wireguard config if you wish to override it (all or nothing) + +# also see group_vars/all/00-secret-template.yml + +wireguard: + dns_servers: + - "{{ dns_forward }}" + interface: "wg0" + ip: + # address for the server + address: "10.66.77.1/32" + # cidr range in tunnel + cidr: "10.66.77.0/24" + + server_public: "www.{{ domain }}" + # UDP port + port: 51820 + + # place to output client configs + client_folder: "/tmp/wireguard-clients" diff --git a/roles/wireguard/handlers/main.yml b/roles/wireguard/handlers/main.yml new file mode 100644 index 0000000..0277d67 --- /dev/null +++ b/roles/wireguard/handlers/main.yml @@ -0,0 +1,9 @@ +--- + +- name: Start wireguard + systemd: + name: "wg-quick@{{ wireguard.interface }}.service" + enabled: yes + daemon_reload: yes + state: restarted + diff --git a/roles/wireguard/tasks/main.yml b/roles/wireguard/tasks/main.yml new file mode 100644 index 0000000..fe478b0 --- /dev/null +++ b/roles/wireguard/tasks/main.yml @@ -0,0 +1,57 @@ +--- + +- name: Install wireguard packages + community.general.pacman: + name: + - wireguard-tools + # for encoding .conf as a qr code + - qrencode + notify: + - Start wireguard + +- name: Enable IP forwarding + sysctl: + name: net.ipv4.ip_forward + value: 1 + state: present + reload: yes + +- name: Setup UFW rules to accept VPN traffic + community.general.ufw: + rule: allow + direction: in + src: "{{ wireguard.ip.cidr }}" + dest: any + +- name: Deploy wireguard server config + template: + src: server.conf.j2 + dest: "/etc/wireguard/{{ wireguard.interface }}.conf" + owner: root + group: root + mode: 0600 + lstrip_blocks: true + no_log: true + notify: + - Start wireguard + +- name: Create wireguard client config output folder + file: + path: "{{ wireguard.client_folder }}" + owner: root + group: root + mode: 0700 + state: directory + +- name: Create wireguard client configs + template: + src: client.conf.j2 + dest: "{{ wireguard.client_folder }}/wg-{{ item.name }}.conf" + owner: root + group: root + mode: 0600 + lstrip_blocks: true + no_log: true + with_items: "{{ wireguard_secret.peers }}" + notify: + - Start wireguard diff --git a/roles/wireguard/templates/client.conf.j2 b/roles/wireguard/templates/client.conf.j2 new file mode 100644 index 0000000..ba911b4 --- /dev/null +++ b/roles/wireguard/templates/client.conf.j2 @@ -0,0 +1,16 @@ +[Interface] +# device's address in the VPN +Address = {{ item.addr }} +# device privkey +PrivateKey = {{ item.priv_key }} +DNS = {{ wireguard.ip.address }} + +[Peer] +# server stuff +PublicKey = {{ wireguard_secret.server_pub_key }} +Endpoint = {{ wireguard.ip.server_public }}:{{ wireguard.ip.port }} + +# allow traffic for all subnets into the VPN +AllowedIPs = 0.0.0.0/0 + +PersistentKeepalive = 25 diff --git a/roles/wireguard/templates/server.conf.j2 b/roles/wireguard/templates/server.conf.j2 new file mode 100644 index 0000000..c458c88 --- /dev/null +++ b/roles/wireguard/templates/server.conf.j2 @@ -0,0 +1,14 @@ +[Interface] +Address = {{ wireguard.ip.address }} +PrivateKey = {{ wireguard_secret.server_key }} +ListenPort = {{ wireguard.ip.port }} + +PostUp = iptables -A FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o {{ net_interface }} -j MASQUERADE +PostDown = iptables -D FORWARD -i %i -j ACCEPT; iptables -t nat -A POSTROUTING -o {{ net_interface }} -j MASQUERADE +SaveConfig = false + +{% for peer in wireguard_secret.peers %} +[Peer] +PublicKey = {{ peer.pub_key }} +AllowedIPs = {{ peer.addr }} +{% endfor %} diff --git a/run.yml b/run.yml index 4956f1c..5d308fa 100644 --- a/run.yml +++ b/run.yml @@ -70,6 +70,11 @@ - haproxy when: '"haproxy" in group_names' + - role: wireguard + tags: + - wireguard + when: '"wireguard" in group_names' + - role: synapse tags: - synapse