Merge pull request 'wg_auto_clients' (#12) from wg_auto_clients into main

Reviewed-on: #12
This commit is contained in:
Fabio Sinibaldi 2026-07-13 16:43:19 +02:00
commit 5413bb5036
8 changed files with 128 additions and 77 deletions

View File

@ -18,7 +18,8 @@ wg_peers:
allowedIPs :
- "192.168.99.0/24"
- "10.22.0.0/16"
- name: second_missing_key_test
- name: forced_missing_key_test
forceRegeneration: True
ip: "192.168.99.6/32"
allowedIPs :
- "192.168.99.0/24"

View File

@ -0,0 +1,20 @@
---
- name: Check if config already exists
stat:
path: "/etc/wireguard/{{ wg_interface }}.conf"
register: interface_configuration
- name: Parse configuration
ansible.utils.cli_parse:
command: "cat /etc/wireguard/{{ wg_interface }}.conf "
parser:
name: ansible.netcommon.native
template_path: templates/wg_config_template.yaml
set_fact: existing_wg_config
when: interface_configuration.stat.exists
- name: Updating client configs info
set_fact:
wg_peers: "{{ wg_peers | community.general.lists_mergeby([{'name':item.key,'publicKey':item.value.publicKey}] ,'name')}}"
when: item.key in (wg_peers | map(attribute='name'))
loop: "{{ existing_wg_config | ansible.builtin.dict2items }}"

View File

@ -1,12 +1,4 @@
---
- name: Create local configs directory
become: false
local_action : ansible.builtin.file
args:
path: "{{ playbook_dir }}/wg_clients/{{ inventory_hostname }}"
state: directory
mode: '0700'
- name: Init generated Keys dict
set_fact:
generated_keys: []
@ -14,7 +6,7 @@
- name : Gather needed key generation
set_fact:
generated_keys: "{{ generated_keys + [{'name': item.name}] }}"
when : item.publicKey is not defined
when : item.publicKey is not defined or (item.forceRegeneration is defined and item.forceRegeneration)
loop: "{{ wg_peers }}"
- name : Generate private keys
@ -42,6 +34,24 @@
wg_peers: "{{ wg_peers | community.general.lists_mergeby(generated_keys,'name')}}"
- name: Delete local configs directory
become: false
local_action : ansible.builtin.file
args:
path: "{{ playbook_dir }}/wg_clients/{{ inventory_hostname }}"
state: absent
- name: Re-create local configs directory
become: false
local_action : ansible.builtin.file
args:
path: "{{ playbook_dir }}/wg_clients/{{ inventory_hostname }}"
state: directory
mode: '0700'
- name : Generate client config file
become: false
local_action : ansible.builtin.template

View File

@ -1,5 +1,6 @@
---
- include_tasks: install_wireguard.yaml
- include_tasks: gather_current_config.yaml
- include_tasks: generate_server_keys.yaml
- include_tasks: generate_client_configs.yaml
- include_tasks: configure_server.yaml

View File

@ -1,62 +0,0 @@
---
- name: Install Wireguard Server
apt:
pkg:
- wireguard
state: latest
update_cache: true
- name: Create directory for wg keys
ansible.builtin.file:
path: /etc/wireguard/keys
state: directory
mode: '0755'
- name: Creating server privatekey and publickey
shell: wg genkey | tee privatekey | wg pubkey > publickey
args:
chdir: /etc/wireguard/keys
- name: Get Private Key [privatekey => var_privatekey]
shell: cat privatekey
register: var_privatekey
args:
chdir: /etc/wireguard/keys
#- name: Add WireGuard interface
# command: ip link add dev wg0 type wireguard
- name: Updating configuration
template:
src: wireguard_server.jinja
dest: /etc/wireguard/wg0.conf
#- name: Activating link
# command: ip link set up dev wg0
- name: Starting wg service
systemd:
state: started
name: wg-quick@wg0
enabled: yes
- name: Getting public key
shell: cat publickey
register: var_publickey
args:
chdir: /etc/wireguard/keys
- name: Check server public IP
shell: curl https://ipinfo.io/ip
register: var_server_ip
- name: Printing public key
debug:
msg: "Server {{ ansible_hostname }} reachable @{{var_server_ip}}. Public key is {{ var_publickey }}"

View File

@ -0,0 +1,13 @@
---
- example: "# Peer ID : fabio_test"
getval: '# Peer ID : (?P<peer_id>\S+)'
result:
"{{ peer_id }}":
name: "{{ peer_id }}"
shared: true
- example: "PublicKey = 9a3tgXpF5CAOffbHZdW1QBEJgSLFnBDVbD1JaMPgzkM="
getval: 'PublicKey = (?P<publicKey>\S+)'
result:
"{{ peer_id }}":
publicKey: "{{ publicKey }}"

View File

@ -16,7 +16,7 @@ PostDown = iptables -t nat -D POSTROUTING ! -o {{wg_interface}} -m mark --mark 0
{% for peer in wg_peers %}
# {{ peer.name }}
# Peer ID : {{ peer.name }}
[Peer]
PublicKey = {{ peer.publicKey }}
AllowedIPs = {{ peer.ip }}

View File

@ -37,11 +37,15 @@ Calls role nextcloud_aio, dependent on docker role.
- Downloads SSE-Lab Repo
- Runs compose up (using ansible plugins)
E.g. `ansible-playbook -i inventories/ -l nextrup_copy_test playbooks/nextcloud.yaml`
E.g.
```ansible-playbook -i inventories/ -l nextrup_copy_test playbooks/nextcloud.yaml```
### Bootstrap ###
Creates sudoer user ansible, necessitates of sudoer user.
Use `ansible-playbook -i inventories playbooks/bootstrap.yml -l [TARGET_HOST] -e 'ansible_user=[REMOTE_USER]' -K`
Use
```ansible-playbook -i inventories playbooks/bootstrap.yml -l [TARGET_HOST] -e 'ansible_user=[REMOTE_USER]' -K```
### NameServer ###
@ -56,8 +60,72 @@ Configures a OPNSense edge node features :
- Wireguard VPN
NB runs locally so python intepreter needs to be specified
E.g. `ansible-playbook -i inventories/sifi.yaml playbooks/opnsense.yaml --extra-vars="ansible_python_interpreter=$(which python)"
`
E.g.
```ansible-playbook -i inventories/sifi.yaml playbooks/opnsense.yaml --extra-vars="ansible_python_interpreter=$(which python)"
```
### VPN Server ###
Configures a VPN Server (only wireguard supported at the moment) for the specified 'wg_peers'.
The server acts as a gateway into a site, tunneling each connection and allowing only traffic into allowed subnets.
Needed parameters and configuration example :
```
wg_interface: wg0
wg_port: 51820
wg_server_address: 192.168.99.1/32
wg_peers:
- name: fabio_test
publicKey: "9a3tgXpF5CAOffbHZdW1QBEJgSLFnBDVbD1JaMPgzkM="
ip: "192.168.99.4/32"
allowedIPs :
- "192.168.99.0/24"
- "10.22.0.0/16"
- name: missing_key_test
ip: "192.168.99.5/32"
allowedIPs :
- "192.168.99.0/24"
- "10.22.0.0/16"
- name: forced_missing_key_test
forceRegeneration: True
ip: "192.168.99.6/32"
allowedIPs :
- "192.168.99.0/24"
- "10.22.0.0/16"
```
#### Wg-peers items ####
Each item represents a client [**Peer**] with :
- *name* [**Mandatory**] : a unique label for the client configuration
- *publicKey*: public key used by the client. If missing, the playbook generates both public and private keys, if needed.
- *ip* [**Mandatory**]: reserved ip for the client
- *allowedIPs* [**Mandatory**]: subnets to which the server allows traffic to for the present client
- *forceRegeneration*: force regeneration of public / private keys pair.
#### Client configurations ####
The playbook generates client configurations at the following path
> "{{ playbook_dir }}/wg_clients/{{ inventory_hostname }}/{{ item.name }}.conf"
**NB** Client configurations are ready to be imported in wireguard client if the playbook generated both public and private keys. Otherwise only the client's public key is reported and the user is expected to fill the configuration properly with their private key.
#### Key pair generation policy ####
In order to configure peers to connect to the server, public/private key pairs are needed.
The playbook evalutes the need for key generation as following :
- If *forceRegeneration* is set to *True*, keys are generated
- If *publicKey* is declared, that key is used
- If a public Key is already configured on the server for that Peer's name, that key is used
- If no public key is declared nor found, a new private / public key pair is generated and reported in client's configuration
## Inventories