Merge stateless idea with no local storage of public and private keys, support multiple interface per hosts using several groups (#29)
* merge stateless with no storage of local priv key * Delete locally stored private key * add reload module on update config file * privatekey template is not used anymore * remove all local keys priv and public * use ansible_play_hosts instead of hardcoded vpn grp should use the group in the play calling the role. works fine when hosts bellong to several groups * Clean tasks names * add tag, and cleanup * fix private key creation * Support for mutliple wireguard vpn on same host add inventory exemple in readme * fix typo, add some comment on inventory * add wg-config tag to Check config: allow run with -t - wg-config * Update tasks/main.yml Co-Authored-By: Robert Wimmer <2039811+githubixx@users.noreply.github.com> * remove trailing whitespace * Update templates/wg.conf.j2 Co-Authored-By: Robert Wimmer <2039811+githubixx@users.noreply.github.com> * Update templates/wg.conf.j2 Co-Authored-By: Robert Wimmer <2039811+githubixx@users.noreply.github.com> * changes after githubixx code review * readd new line to separate peers in config
This commit is contained in:
parent
9a0e70ee25
commit
a357e5fab1
|
@ -1,6 +1,13 @@
|
|||
Changelog
|
||||
---------
|
||||
|
||||
**4.0.0**
|
||||
|
||||
- While the changes introduced are backwards compatible in general if you stay with your current settings some variables are no longer needed. So this is partly a breaking change and therefore justifies a new major version.
|
||||
- Support multiple Wireguard interfaces. See README for examples (contribution by fbourqui)
|
||||
- Make role stateless: In the previous versions the private and public keys of the Wireguard hosts were stored locally in the directory defined with the `wireguard_cert_directory` variable. This is no longer the case. The variables `wireguard_cert_directory`, `wireguard_cert_owner` and `wireguard_cert_group` are no longer needed and were removed. If you used this role before this release it's safe to remove them from your settings. The directory that was defined with the `wireguard_cert_directory` variable will be kept. While not tested it may enable you to go back to an older version of this role and it should still work (contribution by fbourqui)
|
||||
- Reminder: `wireguard_cert_directory` default was `~/wireguard/certs`. Public and Private keys where stored on the host running ansible playbook. As a security best practice private keys of all your WireGuard endpoints should not be kept locally.
|
||||
|
||||
**3.2.2**
|
||||
|
||||
- remove unneeded `with_inventory_hostnames` loops (thanks to pierreozoux for initial PR)
|
||||
|
|
65
README.md
65
README.md
|
@ -27,28 +27,16 @@ see [CHANGELOG.md](https://github.com/githubixx/ansible-role-wireguard/blob/mast
|
|||
Role Variables
|
||||
--------------
|
||||
|
||||
This variables can be changed in `group_vars/`:
|
||||
Those variables can be changed in `group_vars/`:
|
||||
|
||||
```
|
||||
# The LOCAL directory where the WireGuard certificates are stored after they
|
||||
# were generated. By default this will expand to user's LOCAL ${HOME}
|
||||
# (the user that run's "ansible-playbook" command) plus
|
||||
# "/wireguard/certs". That means if the user's ${HOME} directory is e.g.
|
||||
# "/home/da_user" then "wireguard_cert_directory" will have a value of
|
||||
# "/home/da_user/wireguard/certs". If you change this make sure that
|
||||
# the parent directory is writable by the user that runs "ansible-playbook"
|
||||
# command.
|
||||
wireguard_cert_directory: "{{ '~/wireguard/certs' | expanduser }}"
|
||||
wireguard_cert_owner: "root"
|
||||
wireguard_cert_group: "root"
|
||||
|
||||
# Directory to store WireGuard configuration on the remote hosts
|
||||
wireguard_remote_directory: "/etc/wireguard"
|
||||
|
||||
# The port WireGuard will listen on.
|
||||
# The default port WireGuard will listen if not specified otherwise.
|
||||
wireguard_port: "51820"
|
||||
|
||||
# The interface name that wireguard should use.
|
||||
# The default interface name that wireguard should use if not specified otherwise.
|
||||
wireguard_interface: "wg0"
|
||||
```
|
||||
|
||||
|
@ -252,6 +240,53 @@ Example Playbook
|
|||
- wireguard
|
||||
```
|
||||
|
||||
Example Inventory using 2 different WireGuard interfaces on host multi
|
||||
----------------------------------------------------------------------
|
||||
|
||||
This is a complex example using yaml inventory format
|
||||
|
||||
```
|
||||
vpn1:
|
||||
hosts:
|
||||
multi:
|
||||
wireguard_address: 10.9.0.1/32
|
||||
wireguard_allowed_ips: "10.9.0.1/32, 192.168.2.0/24"
|
||||
wireguard_endpoint: multi.exemple.com
|
||||
nated:
|
||||
wireguard_address: 10.9.0.2/32
|
||||
wireguard_allowed_ips: "10.9.0.2/32, 192.168.3.0/24"
|
||||
wireguard_persistent_keepalive: 15
|
||||
wireguard_endpoint: nated.exemple.com
|
||||
wireguard_postup: "iptables -t nat -A POSTROUTING -o ens12 -j MASQUERADE"
|
||||
wireguard_postdown: "iptables -t nat -D POSTROUTING -o ens12 -j MASQUERADE"
|
||||
vpn2:
|
||||
hosts:
|
||||
multi-wg1: # use a different name, and define ansible_host, to avoid mixing of vars without needing to prefix vars with interface name
|
||||
ansible_host: multi
|
||||
wireguard_interface: wg1
|
||||
wireguard_port: 51821 # when using several interface on one host, we must use different ports
|
||||
wireguard_address: 10.9.1.1/32
|
||||
wireguard_endpoint: multi.exemple.com
|
||||
another:
|
||||
wireguard_address: 10.9.1.2/32
|
||||
wireguard_endpoint: another.exemple.com
|
||||
```
|
||||
|
||||
Playbooks
|
||||
---------
|
||||
|
||||
```
|
||||
- hosts: vpn1
|
||||
roles:
|
||||
- wireguard
|
||||
```
|
||||
|
||||
```
|
||||
- hosts: vpn2
|
||||
roles:
|
||||
- wireguard
|
||||
```
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
|
|
@ -1,21 +1,9 @@
|
|||
---
|
||||
# The LOCAL directory where the WireGuard certificates are stored after they
|
||||
# were generated. By default this will expand to user's LOCAL ${HOME}
|
||||
# (the user that run's "ansible-playbook" command) plus
|
||||
# "/wireguard/certs". That means if the user's ${HOME} directory is e.g.
|
||||
# "/home/da_user" then "wireguard_cert_directory" will have a value of
|
||||
# "/home/da_user/wireguard/certs". If you change this make sure that
|
||||
# the parent directory is writable by the user that runs "ansible-playbook"
|
||||
# command.
|
||||
wireguard_cert_directory: "{{ '~/wireguard/certs' | expanduser }}"
|
||||
wireguard_cert_owner: "root"
|
||||
wireguard_cert_group: "root"
|
||||
|
||||
# Directory to store WireGuard configuration on the remote hosts
|
||||
wireguard_remote_directory: "/etc/wireguard"
|
||||
|
||||
# The port WireGuard will listen on.
|
||||
# The default port WireGuard will listen if not specified otherwise.
|
||||
wireguard_port: "51820"
|
||||
|
||||
# The interface name that wireguard should use.
|
||||
# The default interface name that wireguard should use if not specified otherwise.
|
||||
wireguard_interface: "wg0"
|
||||
|
|
137
tasks/main.yml
137
tasks/main.yml
|
@ -14,7 +14,6 @@
|
|||
- wireguard-tools
|
||||
tags:
|
||||
- wg-install
|
||||
- skip_ansible_lint
|
||||
|
||||
- name: Enable WireGuard kernel module
|
||||
modprobe:
|
||||
|
@ -28,106 +27,59 @@
|
|||
tags:
|
||||
- wg-install
|
||||
|
||||
- name: Create WireGuard certificates directory
|
||||
file:
|
||||
dest: "{{ wireguard_cert_directory }}"
|
||||
state: directory
|
||||
owner: "{{ wireguard_cert_owner }}"
|
||||
group: "{{ wireguard_cert_group }}"
|
||||
mode: 0700
|
||||
run_once: true
|
||||
delegate_to: localhost
|
||||
tags:
|
||||
wg-generate-keys
|
||||
|
||||
- name: Set WireGuard IP (without mask)
|
||||
set_fact:
|
||||
wireguard_ip: "{{ wireguard_address.split('/')[0] }}"
|
||||
|
||||
- name: Set path to private key file
|
||||
set_fact:
|
||||
private_key_file_path: "{{ wireguard_cert_directory }}/{{ inventory_hostname }}.private.key"
|
||||
tags:
|
||||
wg-generate-keys
|
||||
|
||||
- name: Set path to public key file
|
||||
set_fact:
|
||||
public_key_file_path: "{{ wireguard_cert_directory }}/{{ inventory_hostname }}.public.key"
|
||||
tags:
|
||||
wg-generate-keys
|
||||
|
||||
- name: Register if private key already exists
|
||||
- name: Register if config/private key already exists on target host
|
||||
stat:
|
||||
path: "{{ private_key_file_path }}"
|
||||
register: private_key_file_stat
|
||||
delegate_to: localhost
|
||||
path: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf"
|
||||
register: config_file_stat
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
- wg-config
|
||||
|
||||
- name: Generate WireGuard private key
|
||||
shell: "wg genkey"
|
||||
register: wg_private_key_result
|
||||
when: not private_key_file_stat.stat.exists
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
- skip_ansible_lint
|
||||
- block:
|
||||
- name: Generate WireGuard private key
|
||||
shell: "wg genkey"
|
||||
register: wg_private_key_result
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
|
||||
- name: Set private key fact
|
||||
set_fact:
|
||||
wg_private_key: "{{ wg_private_key_result.stdout }}"
|
||||
when: not private_key_file_stat.stat.exists
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
- name: Set private key fact
|
||||
set_fact:
|
||||
private_key: "{{ wg_private_key_result.stdout }}"
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
when: not config_file_stat.stat.exists
|
||||
|
||||
- name: Generate WireGuard public key
|
||||
shell: "echo '{{ wg_private_key }}' | wg pubkey"
|
||||
- block:
|
||||
- name: Read WireGuard config file
|
||||
slurp:
|
||||
src: "{{ wireguard_remote_directory }}/{{ wireguard_interface }}.conf"
|
||||
register: wg_config
|
||||
tags:
|
||||
- wg-config
|
||||
|
||||
- name: Set private key fact
|
||||
set_fact:
|
||||
private_key: "{{ wg_config['content'] | b64decode | regex_findall('PrivateKey = (.*)') | first }}"
|
||||
tags:
|
||||
- wg-config
|
||||
when: config_file_stat.stat.exists
|
||||
|
||||
- name: Derive WireGuard public key
|
||||
shell: "echo '{{ private_key }}' | wg pubkey" # noqa 306
|
||||
register: wg_public_key_result
|
||||
when: not private_key_file_stat.stat.exists
|
||||
changed_when: false
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
- wg-config
|
||||
|
||||
- name: Set public key fact
|
||||
set_fact:
|
||||
wg_public_key: "{{ wg_public_key_result.stdout }}"
|
||||
when: not private_key_file_stat.stat.exists
|
||||
public_key: "{{ wg_public_key_result.stdout }}"
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
|
||||
- name: Store hosts private key locally
|
||||
template:
|
||||
src: "wg-privatekey.j2"
|
||||
dest: "{{ private_key_file_path }}"
|
||||
owner: "{{ wireguard_cert_owner }}"
|
||||
group: "{{ wireguard_cert_group }}"
|
||||
mode: 0644
|
||||
when: not private_key_file_stat.stat.exists
|
||||
delegate_to: localhost
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
|
||||
- name: Store hosts public key locally
|
||||
template:
|
||||
src: "wg-publickey.j2"
|
||||
dest: "{{ public_key_file_path }}"
|
||||
owner: "{{ wireguard_cert_owner }}"
|
||||
group: "{{ wireguard_cert_group }}"
|
||||
mode: 0644
|
||||
when: not private_key_file_stat.stat.exists
|
||||
delegate_to: localhost
|
||||
tags:
|
||||
- wg-generate-keys
|
||||
|
||||
- name: Read private key
|
||||
set_fact:
|
||||
private_key: "{{ lookup('file', private_key_file_path) }}"
|
||||
tags:
|
||||
wg-config
|
||||
|
||||
- name: Read public key
|
||||
set_fact:
|
||||
public_key: "{{ lookup('file', public_key_file_path) }}"
|
||||
tags:
|
||||
wg-config
|
||||
- wg-config
|
||||
|
||||
- name: Create WireGuard configuration directory
|
||||
file:
|
||||
|
@ -149,6 +101,21 @@
|
|||
notify:
|
||||
- restart wireguard
|
||||
|
||||
- name: Check if reload-module-on-update is set
|
||||
stat:
|
||||
path: "{{ wireguard_remote_directory }}/.reload-module-on-update"
|
||||
register: reload_module_on_update
|
||||
tags:
|
||||
- wg-config
|
||||
|
||||
- name: Set WireGuard reload-module-on-update
|
||||
file:
|
||||
dest: "{{ wireguard_remote_directory }}/.reload-module-on-update"
|
||||
state: touch
|
||||
when: not reload_module_on_update.stat.exists
|
||||
tags:
|
||||
- wg-config
|
||||
|
||||
- name: Start and enable WireGuard service
|
||||
service:
|
||||
name: "wg-quick@{{ wireguard_interface }}"
|
||||
|
|
|
@ -1 +0,0 @@
|
|||
{{hostvars[inventory_hostname]['wg_private_key']}}
|
|
@ -1 +0,0 @@
|
|||
{{hostvars[inventory_hostname]['wg_public_key']}}
|
|
@ -15,9 +15,9 @@ PostDown = {{hostvars[inventory_hostname].wireguard_postdown}}
|
|||
{% if hostvars[inventory_hostname].wireguard_save_config is defined %}
|
||||
SaveConfig = true
|
||||
{% endif %}
|
||||
|
||||
{% for host in groups["vpn"] %}
|
||||
{% for host in ansible_play_hosts %}
|
||||
{% if host != inventory_hostname %}
|
||||
|
||||
[Peer]
|
||||
PublicKey = {{hostvars[host].public_key}}
|
||||
{% if hostvars[host].wireguard_allowed_ips is defined %}
|
||||
|
@ -28,11 +28,18 @@ SaveConfig = true
|
|||
{% if hostvars[host].wireguard_persistent_keepalive is defined %}
|
||||
PersistentKeepalive = {{hostvars[host].wireguard_persistent_keepalive}}
|
||||
{% endif %}
|
||||
{% if hostvars[host].wireguard_endpoint is not defined %}
|
||||
Endpoint = {{host}}:{{wireguard_port}}
|
||||
{% elif hostvars[host].wireguard_endpoint != "" %}
|
||||
{% if hostvars[host].wireguard_port is defined and hostvars[host].wireguard_port is number %}
|
||||
{% if hostvars[host].wireguard_endpoint is defined and hostvars[host].wireguard_endpoint != "" %}
|
||||
Endpoint = {{hostvars[host].wireguard_endpoint}}:{{hostvars[host].wireguard_port}}
|
||||
{% else %}
|
||||
Endpoint = {{host}}:{{hostvars[host].wireguard_port}}
|
||||
{% endif %}
|
||||
{% elif hostvars[host].wireguard_endpoint is defined and hostvars[host].wireguard_endpoint != "" %}
|
||||
Endpoint = {{hostvars[host].wireguard_endpoint}}:{{wireguard_port}}
|
||||
{% elif hostvars[host].wireguard_endpoint == "" %}
|
||||
# No endpoint defined
|
||||
{% else %}
|
||||
Endpoint = {{host}}:{{wireguard_port}}
|
||||
{% endif %}
|
||||
|
||||
{% endif %}
|
||||
{% endfor %}
|
||||
|
|
Reference in a new issue