Point of inception
This commit is contained in:
commit
b15d869de6
7
Makefile
Normal file
7
Makefile
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
INVENTORY = inventory
|
||||||
|
|
||||||
|
apply:
|
||||||
|
ansible-playbook -i "inventories/${INVENTORY}.yml" "wireguard.yml"
|
||||||
|
|
||||||
|
test:
|
||||||
|
ansible-playbook -i "inventories/${INVENTORY}.yml" "ping.yml"
|
111
README.md
Normal file
111
README.md
Normal file
@ -0,0 +1,111 @@
|
|||||||
|
# Multi server Wireguard mesh with ansible
|
||||||
|
|
||||||
|
A playbook which given an inventory file with:
|
||||||
|
|
||||||
|
* a list of hosts
|
||||||
|
* for each host a `wireguard_ip` variable with the desired host (private) Wireguard IP
|
||||||
|
* `wireguard_mask_bits` variable with the number of the wireguard (private) network mask bits
|
||||||
|
* `wireguard_port` variable with the UDP port to use
|
||||||
|
|
||||||
|
will:
|
||||||
|
|
||||||
|
* install wireguard in all hosts
|
||||||
|
* generate public/private key pairs in all hosts
|
||||||
|
* generate the pre-shared keys for all host pairs
|
||||||
|
* create a `wg0` virtual network device and a `wg0` network
|
||||||
|
|
||||||
|
optionally, when the `ufw_enabled` variable is set to `true`:
|
||||||
|
|
||||||
|
* enable ufw on all hosts
|
||||||
|
* reject everything by default
|
||||||
|
* allow ssh protocol from all sources
|
||||||
|
* allow traffic from all the inventory wireguard IPs
|
||||||
|
|
||||||
|
More details and explanation can be found in this blog post: https://jawher.me/wireguard-ansible-systemd-ubuntu/
|
||||||
|
|
||||||
|
## Example
|
||||||
|
|
||||||
|
In this example, we'll create 3 Hetzner cloud CX11 servers (~3€/month) using [Hetzner's cli](https://github.com/hetznercloud/cli),
|
||||||
|
1 in each of their 3 datacenters (Nuremberg, Falkenstein & Helsinki):
|
||||||
|
|
||||||
|
```shell
|
||||||
|
env_id=wireguard-test
|
||||||
|
server_type=cx11
|
||||||
|
image=ubuntu-20.04
|
||||||
|
|
||||||
|
args=()
|
||||||
|
|
||||||
|
for k in $(hcloud ssh-key list -o=noheader -ocolumns=name); do
|
||||||
|
args+=("--ssh-key=$k")
|
||||||
|
done
|
||||||
|
|
||||||
|
for datacenter in nbg1-dc3 fsn1-dc14 hel1-dc2; do
|
||||||
|
hcloud server create "${args[@]}" \
|
||||||
|
--datacenter="${datacenter}" \
|
||||||
|
--type="${server_type}" \
|
||||||
|
--image="${image}" \
|
||||||
|
--label=env="${env_id}" \
|
||||||
|
--name="${env_id}-${datacenter}"
|
||||||
|
done
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
|
### Inventory
|
||||||
|
|
||||||
|
Next you need to prepapre an inventory file with the 3 servers we created in `inventories/inventory.yml`:
|
||||||
|
|
||||||
|
Run `hcloud server list -l env=wireguard-test`:
|
||||||
|
|
||||||
|
```
|
||||||
|
ID NAME STATUS IPV4 IPV6 DATACENTER
|
||||||
|
10889123 wireguard-test-nbg1-dc3 running xxx.xx.xxx.xx 2a01:xxxx:xxxx:xxxx::/64 nbg1-dc3
|
||||||
|
10889126 wireguard-test-fsn1-dc14 running xxx.xx.xxx.xxx 2a01:xxxx:xxxx:xxxx::/64 fsn1-dc14
|
||||||
|
10889127 wireguard-test-hel1-dc2 running xx.xxx.xx.xxx 2a01:xxxx:xxxx:xxxx::/64 hel1-dc2
|
||||||
|
```
|
||||||
|
|
||||||
|
And use the server names and IPv4s to build your inventory:
|
||||||
|
|
||||||
|
```yml
|
||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
|
||||||
|
host1:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host1_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.1
|
||||||
|
|
||||||
|
host2:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host2_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.2
|
||||||
|
|
||||||
|
host3:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host3_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.3
|
||||||
|
|
||||||
|
vars:
|
||||||
|
ansible_become_method: su
|
||||||
|
|
||||||
|
wireguard_mask_bits: 24
|
||||||
|
wireguard_port: 51871
|
||||||
|
```
|
||||||
|
|
||||||
|
### Apply
|
||||||
|
|
||||||
|
Run `make apply`
|
||||||
|
|
||||||
|
### Test connectivity
|
||||||
|
|
||||||
|
Run `make test`, which will perform ping tests between the 3 servers using their wireguard private IPs.
|
||||||
|
|
||||||
|
You could also ssh to each/any host and run `ping` manually if you prefer.
|
33
inventories/inventory.yml
Normal file
33
inventories/inventory.yml
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
all:
|
||||||
|
hosts:
|
||||||
|
|
||||||
|
host1:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host1_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.1
|
||||||
|
|
||||||
|
host2:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host2_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.2
|
||||||
|
|
||||||
|
host3:
|
||||||
|
pipelining: true
|
||||||
|
ansible_ssh_user: root
|
||||||
|
ansible_host: "$host3_public_ip"
|
||||||
|
ansible_ssh_port: 22
|
||||||
|
|
||||||
|
wireguard_ip: 192.168.0.3
|
||||||
|
|
||||||
|
vars:
|
||||||
|
ansible_become_method: su
|
||||||
|
|
||||||
|
wireguard_mask_bits: 24
|
||||||
|
wireguard_port: 51871
|
||||||
|
|
7
ping.yml
Normal file
7
ping.yml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
gather_facts: yes
|
||||||
|
tasks:
|
||||||
|
- name: ping
|
||||||
|
command: "ping -c3 {{ hostvars[item].wireguard_ip }}"
|
||||||
|
with_items: "{{ groups['all'] }}"
|
19
templates/systemd.netdev
Normal file
19
templates/systemd.netdev
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
[NetDev]
|
||||||
|
Name=wg0
|
||||||
|
Kind=wireguard
|
||||||
|
Description=WireGuard tunnel wg0
|
||||||
|
|
||||||
|
[WireGuard]
|
||||||
|
ListenPort={{ wireguard_port }}
|
||||||
|
PrivateKey={{ wireguard_private_key.stdout }}
|
||||||
|
|
||||||
|
{% for peer in groups['all'] %}
|
||||||
|
{% if peer != inventory_hostname %}
|
||||||
|
|
||||||
|
[WireGuardPeer]
|
||||||
|
PublicKey={{ hostvars[peer].wireguard_public_key.stdout }}
|
||||||
|
PresharedKey={{ wireguard_preshared_keys[peer] if inventory_hostname < peer else hostvars[peer].wireguard_preshared_keys[inventory_hostname] }}
|
||||||
|
AllowedIPs={{ hostvars[peer].wireguard_ip }}/32
|
||||||
|
Endpoint={{ hostvars[peer].ansible_host }}:{{ wireguard_port }}
|
||||||
|
{% endif %}
|
||||||
|
{% endfor %}
|
5
templates/systemd.network
Normal file
5
templates/systemd.network
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[Match]
|
||||||
|
Name=wg0
|
||||||
|
|
||||||
|
[Network]
|
||||||
|
Address={{ wireguard_ip }}/{{ wireguard_mask_bits }}
|
114
wireguard.yml
Normal file
114
wireguard.yml
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
---
|
||||||
|
- hosts: all
|
||||||
|
any_errors_fatal: true
|
||||||
|
gather_facts: yes
|
||||||
|
tasks:
|
||||||
|
- name: update packages
|
||||||
|
apt:
|
||||||
|
update_cache: yes
|
||||||
|
cache_valid_time: 3600
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Allow SSH in UFW
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
port: "{{ ansible_ssh_port }}"
|
||||||
|
proto: tcp
|
||||||
|
become: yes
|
||||||
|
when: ufw_enabled
|
||||||
|
|
||||||
|
- name: Set ufw logging
|
||||||
|
ufw:
|
||||||
|
logging: "on"
|
||||||
|
become: yes
|
||||||
|
when: ufw_enabled
|
||||||
|
|
||||||
|
- name: inter-node Wireguard UFW connectivity
|
||||||
|
ufw:
|
||||||
|
rule: allow
|
||||||
|
src: "{{ hostvars[item].wireguard_ip }}"
|
||||||
|
with_items: "{{ groups['all'] }}"
|
||||||
|
become: yes
|
||||||
|
when: ufw_enabled and item != inventory_hostname
|
||||||
|
|
||||||
|
- name: Reject everything and enable UFW
|
||||||
|
ufw:
|
||||||
|
state: enabled
|
||||||
|
policy: reject
|
||||||
|
log: yes
|
||||||
|
become: yes
|
||||||
|
when: ufw_enabled
|
||||||
|
|
||||||
|
- name: Install wireguard
|
||||||
|
apt:
|
||||||
|
name: wireguard
|
||||||
|
state: present
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Generate Wireguard keypair
|
||||||
|
shell: wg genkey | tee /etc/wireguard/privatekey | wg pubkey | tee /etc/wireguard/publickey
|
||||||
|
args:
|
||||||
|
creates: /etc/wireguard/privatekey
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: register private key
|
||||||
|
shell: cat /etc/wireguard/privatekey
|
||||||
|
register: wireguard_private_key
|
||||||
|
changed_when: false
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: register public key
|
||||||
|
shell: cat /etc/wireguard/publickey
|
||||||
|
register: wireguard_public_key
|
||||||
|
changed_when: false
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: generate Preshared keyskeypair
|
||||||
|
shell: "wg genpsk > /etc/wireguard/psk-{{ item }}"
|
||||||
|
args:
|
||||||
|
creates: "/etc/wireguard/psk-{{ item }}"
|
||||||
|
when: inventory_hostname < item
|
||||||
|
with_items: "{{ groups['all'] }}"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: register preshared key
|
||||||
|
shell: "cat /etc/wireguard/psk-{{ item }}"
|
||||||
|
register: wireguard_preshared_key
|
||||||
|
changed_when: false
|
||||||
|
when: inventory_hostname < item
|
||||||
|
with_items: "{{ groups['all'] }}"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: massage preshared keys
|
||||||
|
set_fact: "wireguard_preshared_keys={{ wireguard_preshared_keys|default({}) | combine( {item.item: item.stdout} ) }}"
|
||||||
|
when: item.skipped is not defined
|
||||||
|
with_items: "{{ wireguard_preshared_key.results }}"
|
||||||
|
become: yes
|
||||||
|
|
||||||
|
- name: Setup wg0 device
|
||||||
|
template:
|
||||||
|
src: ./templates/systemd.netdev
|
||||||
|
dest: /etc/systemd/network/99-wg0.netdev
|
||||||
|
owner: root
|
||||||
|
group: systemd-network
|
||||||
|
mode: 0640
|
||||||
|
become: yes
|
||||||
|
notify: systemd network restart
|
||||||
|
|
||||||
|
- name: Setup wg0 network
|
||||||
|
template:
|
||||||
|
src: ./templates/systemd.network
|
||||||
|
dest: /etc/systemd/network/99-wg0.network
|
||||||
|
owner: root
|
||||||
|
group: systemd-network
|
||||||
|
mode: 0640
|
||||||
|
become: yes
|
||||||
|
notify: systemd network restart
|
||||||
|
|
||||||
|
handlers:
|
||||||
|
- name: systemd network restart
|
||||||
|
service:
|
||||||
|
name: systemd-networkd
|
||||||
|
state: restarted
|
||||||
|
enabled: yes
|
||||||
|
become: yes
|
Loading…
x
Reference in New Issue
Block a user