Playbook vpn_server

This commit is contained in:
Fabio Sinibaldi 2026-07-16 19:16:24 +02:00
parent bc05ee7dfc
commit 9afb4b6389
12 changed files with 301 additions and 2 deletions

View File

@ -8,6 +8,7 @@ Implementa la configurazione di base di un nodo per poter essere gestito dagli a
- crea l'utente ansible
- registra le chiavi ssh degli utenti configurati
**Target Hosts : all**
#### Parametri
@ -18,7 +19,6 @@ ansible_authorized_keys:
key: <MY>
```
#### Chiamata
Per lanciare il playbook e' necessario specificare l'utente da utilizzare per connettersi ed esguire il playbook con l'opzione *-e*'.
L'opzione '*-K*' invece permette di chiedere la password dell'utente remoto
@ -27,4 +27,36 @@ L'opzione '*-K*' invece permette di chiedere la password dell'utente remoto
ansible-playbook -i inventories/<INVENTORY>.yaml playbooks/bootstrap.yaml -e 'ansible_user=<SUDO USER>' -K
```
### VPN Server
### VPN Server
Istanzia un server Wireguard abilitando il tunneling del traffico.
**Target Hosts : wireguard_server**
#### Generazione chiavi e configurazioni dei Peer
Genera in */wg_clients/< ANSIBLE_HOSTNAME >/* i file di configurazione per i peer configurati.
**NB**
Il playbook e' a conoscenza della chiave privata del peer solo se e' stato necessario generarla durante l'esecuzione. In caso contrario viene riportata solo la chiave pubblica ed e' compito dell'utente inserire la chiave privata.
Il playbook genera le chiavi nei seguenti casi :
- nessuna chiave pubblica e' stata fornita e il peer non e' gia' configurato sul server
- Force Regeneration = True
#### Parametri
Il playbook si aspetta le seguenti variabili
```
wg_interface: wg0
wg_port: 51820
wg_server_address: 192.168.101.1/32
wg_peers:
- name: <MY LABEL>
# publicKey:
ip: "192.168.101.4/32"
allowedIPs :
- "192.168.101.0/24"
- "10.22.0.0/16"
forceRegeneration: False
```

View File

@ -0,0 +1,5 @@
---
- name: Restart WireGuard
ansible.builtin.systemd:
name: "wg-quick@{{ wg_interface }}"
state: restarted

View File

@ -0,0 +1,31 @@
# wireguard_server.yml - Configure WireGuard VPN server
---
- name: Get Private Key [privatekey => var_privatekey]
shell: cat privatekey
register: wg_server_private_key
args:
chdir: /etc/wireguard
- name: Deploy WireGuard server configuration
ansible.builtin.template:
src: templates/wireguard_server.jinja
dest: "/etc/wireguard/{{ wg_interface }}.conf"
owner: root
group: root
mode: '0600'
notify: Restart WireGuard
- name: Enable and start WireGuard
ansible.builtin.systemd:
name: "wg-quick@{{ wg_interface }}"
state: started
enabled: true
- name: Open WireGuard port in firewall
community.general.ufw:
rule: allow
port: "{{ wg_port }}"
proto: udp
comment: "WireGuard VPN"
ignore_errors: true

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

@ -0,0 +1,67 @@
---
- name: Init generated Keys dict
set_fact:
generated_keys: []
- name : Gather needed key generation
set_fact:
generated_keys: "{{ generated_keys + [{'name': item.name}] }}"
when : item.publicKey is not defined or (item.forceRegeneration is defined and item.forceRegeneration)
loop: "{{ wg_peers }}"
- name : Generate private keys
command : wg genkey
register: privateKeyObjects
loop : "{{ generated_keys }}"
- name : Generate public keys
shell : echo "{{privateKeyObjects.results[ansible_loop.index0].stdout}}" | wg pubkey
register: publicKeyObjects
loop : "{{ generated_keys }}"
loop_control:
extended: true
- name: Registering generated keys
set_fact:
generated_keys: "{{ generated_keys | community.general.lists_mergeby ([{'privateKey' : privateKeyObjects.results[ansible_loop.index0].stdout, 'publicKey' : publicKeyObjects.results[ansible_loop.index0].stdout, 'name':item.name }],'name') }}"
loop: "{{ generated_keys }}"
loop_control:
extended: true
- name: Updating client configs info
set_fact:
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
args:
src: templates/wireguard_client.jinja
dest: "{{ playbook_dir }}/wg_clients/{{ inventory_hostname }}/{{ item.name }}.conf"
vars:
wg_client_public_key: "{{ item.publicKey }}"
wg_client_private_key: "{{ item.privateKey | default('')}}"
wg_client_address: "{{ item.ip }}"
allowed_ips : "{{ item.allowedIPs }}"
wg_server : "{{ inventory_hostname }}"
loop: "{{ wg_peers }}"

View File

@ -0,0 +1,49 @@
# generate_keys.yml - Generate WireGuard key pairs
---
- name: Create WireGuard directory
ansible.builtin.file:
path: /etc/wireguard
state: directory
mode: '0700'
- name: Check if server private key already exists
ansible.builtin.stat:
path: /etc/wireguard/privatekey
register: privatekey_file
- name: Generate server private key
ansible.builtin.command: wg genkey
register: wg_private_key
when: not privatekey_file.stat.exists
changed_when: true
- name: Save server private key
ansible.builtin.copy:
content: "{{ wg_private_key.stdout }}"
dest: /etc/wireguard/privatekey
owner: root
group: root
mode: '0600'
when: not privatekey_file.stat.exists
- name: Read server private key
ansible.builtin.slurp:
src: /etc/wireguard/privatekey
register: private_key_content
- name: Generate server public key from private key
ansible.builtin.shell: echo "{{ private_key_content.content | b64decode | trim }}" | wg pubkey
register: wg_server_public_key
changed_when: false
- name: Save server public key
ansible.builtin.copy:
content: "{{ wg_server_public_key.stdout }}"
dest: /etc/wireguard/publickey
owner: root
group: root
mode: '0644'
- name: Display public key for reference
ansible.builtin.debug:
msg: "Public key for {{ inventory_hostname }}: {{ wg_server_public_key.stdout }}"

View File

@ -0,0 +1,25 @@
# install_wireguard.yml - Install WireGuard on Linux hosts
---
- name: Install WireGuard on Debian/Ubuntu
ansible.builtin.apt:
name:
- wireguard
- wireguard-tools
state: present
update_cache: true
when: ansible_os_family == "Debian"
- name: Install WireGuard on RHEL/CentOS 8+
ansible.builtin.yum:
name:
- wireguard-tools
state: present
when: ansible_os_family == "RedHat"
- name: Enable IP forwarding
ansible.posix.sysctl:
name: net.ipv4.ip_forward
value: '1'
sysctl_set: true
state: present
reload: true

View File

@ -0,0 +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

@ -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

@ -0,0 +1,18 @@
[Interface]
{% if wg_client_private_key is defined and wg_client_private_key != None and wg_client_private_key != ''%}
PrivateKey = {{wg_client_private_key}}
{% else%}
# Public and private keys were pre generated by client
# Insert private key below and uncomment in order to use the present configuration
# PrivateKey =
{% endif %}
Address = {{wg_client_address}}
[Peer]
PublicKey = {{wg_server_public_key.stdout}}
AllowedIPs = {{ allowed_ips | join(', ') }}
Endpoint = {{ wg_server }}:{{ wg_port }}
PersistentKeepalive = 25

View File

@ -0,0 +1,27 @@
# templates/wireguard-server.conf.j2 - WireGuard server configuration
# Managed by Ansible - do not edit manually
[Interface]
Address = {{ wg_server_address }}
ListenPort = {{ wg_port }}
PrivateKey = {{ wg_server_private_key.stdout }}
# IP forwarding
PreUp = sysctl -w net.ipv4.ip_forward=1
# IP masquerading
PreUp = iptables -t mangle -A PREROUTING -i {{wg_interface}} -j MARK --set-mark 0x30
PreUp = iptables -t nat -A POSTROUTING ! -o {{wg_interface}} -m mark --mark 0x30 -j MASQUERADE
PostDown = iptables -t mangle -D PREROUTING -i {{wg_interface}} -j MARK --set-mark 0x30
PostDown = iptables -t nat -D POSTROUTING ! -o {{wg_interface}} -m mark --mark 0x30 -j MASQUERADE
{% for peer in wg_peers %}
# Peer ID : {{ peer.name }}
[Peer]
PublicKey = {{ peer.publicKey }}
AllowedIPs = {{ peer.ip }}
{% if peer.persistent_keepalive is defined %}
PersistentKeepalive = {{ peer.persistent_keepalive }}
{% endif %}
{% endfor %}

View File

@ -0,0 +1,6 @@
---
- name: Configure VPN Server
hosts: wireguard_server
become: true
roles:
- wireguard_server