githubixx.ansible_role_wireguard
ansible-role-wireguard
Diese Ansible-Rolle wird in meiner Blogreihe Kubernetes the not so hard way with Ansible verwendet, kann jedoch auch eigenständig genutzt werden. Ich verwende WireGuard und diese Ansible-Rolle, um ein vollständig vernetztes VPN zwischen allen Knoten meines kleinen Kubernetes-Clusters einzurichten.
Im Allgemeinen ist WireGuard ein Netzwerk-Tunnel (VPN) für IPv4 und IPv6, der UDP verwendet. Wenn Sie weitere Informationen über WireGuard benötigen, finden Sie hier eine gute Einführung: Installing WireGuard, the Modern VPN.
Linux
Diese Rolle sollte mit den folgenden Systemen funktionieren:
- Ubuntu 20.04 (Focal Fossa)
- Ubuntu 22.04 (Jammy Jellyfish)
- Ubuntu 24.04 (Noble Numbat)
- Archlinux
- Debian 11 (Bullseye)
- Debian 12 (Bookworm)
- Fedora 39
- AlmaLinux 9
- Rocky Linux 9
- openSUSE Leap 15.5
- openSUSE Leap 15.6
- Oracle Linux 9
Best effort
- AlmaLinux 8
- Rocky Linux 8
- elementary OS 6
- CentOS 7 (Ende der Lebensdauer seit Ende Juni 2024)
Molecule-Tests sind verfügbar (siehe weiter unten). Es sollte auch mit Raspbian Buster
funktionieren, aber dafür gibt es keinen Test. MacOS (siehe unten) sollte ebenfalls teilweise funktionieren, wird jedoch nur als Best Effort behandelt.
MacOS
Während dieses Playbook auf Linux einen systemd
-Dienst konfiguriert, aktiviert und startet, installiert es auf macOS die benötigten Pakete und generiert nur die korrekte wg0.conf
-Datei, die dann im angegebenen wireguard_remote_directory
(/opt/local/etc/wireguard
standardmäßig) platziert wird. Um das VPN auszuführen, müssen Sie dann:
sudo wg-quick up wg0
und um es zu deaktivieren:
sudo wg-quick down wg0
Alternativ können Sie die offizielle App installieren und die wg0.conf
-Datei importieren.
Versionen
Ich tagge jede Veröffentlichung und versuche, semantische Versionsverwaltung einzuhalten. Wenn Sie die Rolle verwenden möchten, empfehle ich, das neueste Tag zu überprüfen. Der Hauptbranch ist im Grunde Entwicklungsumgebung, während die Tags stabile Releases kennzeichnen. Insgesamt versuche ich auch, den Hauptbranch in gutem Zustand zu halten.
Anforderungen
Standardmäßig sollte der Port 51820
(Protokoll UDP) von außen zugänglich sein. Sie können den Port jedoch anpassen, indem Sie die Variable wireguard_port
ändern. Außerdem muss IP-Forwarding aktiviert sein, z.B. über echo 1 > /proc/sys/net/ipv4/ip_forward
. Ich habe mich entschieden, diese Aufgabe nicht in dieser Ansible-Rolle zu implementieren. Meiner Meinung nach sollte das anderswo erledigt werden. Sie können beispielsweise meine ansible-role-harden-linux verwenden. Neben der Änderung von Sysctl-Einträgen (die Sie benötigen, um das IP-Forwarding zu aktivieren) verwaltet sie auch die Firewall-Einstellungen unter anderem. Nichtsdestotrotz können die PreUp
, PreDown
, PostUp
und PostDown
Hooks ein guter Ort sein, um einige netzwerkbezogene Aufgaben auszuführen, bevor eine WireGuard-Schnittstelle aktiviert oder deaktiviert wird.
Änderungsprotokoll
Änderungshistorie:
Siehe vollständiges CHANGELOG.md
Aktuelle Änderungen:
17.0.0
BREAKING
- Unterstützung für
openSUSE 15.4
entfernt (Ende der Lebensdauer erreicht)
- Unterstützung für
FEATURE
- Unterstützung für
Ubuntu 24.04
hinzugefügt - Unterstützung für
openSUSE 15.6
hinzugefügt
- Unterstützung für
MOLECULE
- Veralteten
Proxmox
-Code entfernt - Vagrant-Box
rockylinux/9
durchbento/rockylinux-9
ersetzt - Verwenden von
ansible.builtin.package
für AlmaLinux AlmaLinux 8
,Rocky Linux 8
undCentOS 7
entfernt (veraltetes Python macht es schwer, mit Ansible zu testen)
- Veralteten
Installation
Direktes Herunterladen von GitHub (wechseln Sie vor dem Klonen in das Verzeichnis der Ansible-Rolle):
git clone https://github.com/githubixx/ansible-role-wireguard.git githubixx.ansible_role_wireguard
Über den Befehl
ansible-galaxy
und direkt von Ansible Galaxy herunterladen:ansible-galaxy role install githubixx.ansible_role_wireguard
Erstellen Sie eine
requirements.yml
-Datei mit folgendem Inhalt (dies wird die Rolle von GitHub herunterladen) und installieren Sie sie mit:ansible-galaxy role install -r requirements.yml
:
---
roles:
- name: githubixx.ansible_role_wireguard
src: https://github.com/githubixx/ansible-role-wireguard.git
version: 17.0.0
Rolleneigenschaften
Diese Variablen können in group_vars/
geändert werden, z.B.:
# Verzeichnis zur Speicherung der WireGuard-Konfiguration auf den Remote-Hosts
wireguard_remote_directory: "/etc/wireguard" # Unter Linux
# wireguard_remote_directory: "/opt/local/etc/wireguard" # Unter MacOS
# Der Standardport, auf dem WireGuard lauscht, wenn nicht anders angegeben.
wireguard_port: "51820"
# Der Standardname der Schnittstelle, den WireGuard verwenden soll, wenn nicht anders angegeben.
wireguard_interface: "wg0"
# Der Standardbesitzer der wg.conf-Datei
wireguard_conf_owner: root
# Die Standardgruppe der wg.conf-Datei
wireguard_conf_group: "{{ 'root' if not ansible_os_family == 'Darwin' else 'wheel' }}"
# Der Standardmodus der wg.conf-Datei
wireguard_conf_mode: 0600
# Ob Änderungen an der wg.conf-Datei gesichert werden sollen
wireguard_conf_backup: false
# Der Standardzustand des WireGuard-Dienstes
wireguard_service_enabled: "yes"
wireguard_service_state: "started"
# Standardmäßig wird "wg syncconf" verwendet, um die Einstellungen der WireGuard-Schnittstelle anzuwenden, wenn sie sich geändert haben.
# Ältere WireGuard-Tools bieten diese Option nicht. In diesem Fall wird als Fallback die WireGuard-Schnittstelle neu gestartet.
# Dies verursacht eine kurze Unterbrechung der Netzwerkverbindungen.
#
# Auch wenn "false" der Standard ist, erkennt die Rolle, ob die "syncconf"-Option des "wg"-Dienstprogramms verfügbar ist und fällt, wenn nicht, auf "true" zurück.
#
# Mögliche Optionen:
# - false (Standard)
# - true
#
# Beide Optionen haben ihre Vor- und Nachteile. Die Standardoption "false" (Schnittstelle nicht neu starten)
# - erfordert keinen Neustart der WireGuard-Schnittstelle, um Änderungen anzuwenden
# - verursacht keine kurze Unterbrechung der VPN-Verbindung, wenn Änderungen angewendet werden
# - könnte dazu führen, dass Netzwerkrouten nicht ordnungsgemäß neu geladen werden
#
# Das Setzen der Option auf "true" wird
# - die WireGuard-Schnittstelle neu starten, wie der Name schon sagt, falls Änderungen vorliegen
# - führt zu einer kurzen Unterbrechung der VPN-Verbindung, wenn Änderungen angewendet werden
# - stellt sicher, dass Netzwerkrouten ordnungsgemäß neu geladen werden
#
# Es hängt also ein wenig von Ihrer Einrichtung ab, welche Option am besten funktioniert. Wenn Sie
# kein übermäßig komplexes Routing haben, das sich sehr oft oder gar nicht ändert,
# ist die Verwendung von "false" hier wahrscheinlich gut genug für Sie.
#
# Wenn Sie ein dynamischeres Routing-Setup haben, könnte es sicherer sein, diese Option auf "true" zu setzen.
# Wenn Sie die Möglichkeit vermeiden möchten, schwer zu erkennende Nebenwirkungen zu erzeugen, sollte diese Option in Betracht gezogen werden.
wireguard_interface_restart: false
# Normalerweise erstellt die Rolle beim ersten Mal automatisch einen privaten Schlüssel,
# wenn noch keine WireGuard-Konfiguration vorhanden ist. Diese Option ermöglicht es jedoch,
# Ihren eigenen WireGuard-Privatschlüssel bereitzustellen, falls erforderlich. Da dies natürlich ein sehr sensibler Wert ist,
# sollten Sie in Betracht ziehen, ein Tool wie Ansible Vault zu verwenden, um es verschlüsselt zu speichern.
# wireguard_private_key:
# Auf "false" setzen, wenn der Paket-Cache nicht aktualisiert werden soll (nur relevant, wenn
# der betreffende Paketmanager diese Option unterstützt)
wireguard_update_cache: "true"
# Normalerweise installiert und aktiviert die Rolle das WireGuard-Kernelmodul, wo es angebracht ist.
# In einigen Fällen sind wir möglicherweise nicht in der Lage, Kernelmodule zu laden, wie z.B. bei
# unprivilegierten LXC-Gästen. Wenn Sie dies auf false setzen, müssen Sie sicherstellen,
# dass das WireGuard-Modul im Kernel verfügbar ist!
wireguard_install_kernel_module: true
Es gibt auch einige distributionsspezifische Einstellungen für Linux:
#######################################
# Einstellungen nur relevant für:
# - Ubuntu
# - elementary OS
#######################################
# DEPRECATED: Bitte verwenden Sie stattdessen "wireguard_update_cache".
# Auf "false" setzen, wenn der Paket-Cache nicht aktualisiert werden soll.
wireguard_ubuntu_update_cache: "{{ wireguard_update_cache }}"
# Den Paket-Cache gültig machen
wireguard_ubuntu_cache_valid_time: "3600"
#######################################
# Einstellungen nur relevant für CentOS 7
#######################################
# Setzen Sie wireguard_centos7_installation_method auf "kernel-plus",
# um den Kernel-plus-Kernel zu verwenden, der ein integriertes,
# signiertes WireGuard-Modul enthält.
#
# Der Standard "standard" verwendet den Standardkernel und
# das ELRepo-Modul für WireGuard.
wireguard_centos7_installation_method: "standard"
# Den Host neu starten, wenn nötig, wenn der "kernel-plus"-Kernel verwendet wird
wireguard_centos7_kernel_plus_reboot: true
# Die Standardanzahl von Sekunden, die auf die Maschine gewartet werden soll, um neu zu starten und zu reagieren,
# wenn "kernel-plus" verwendet wird. Ist nur relevant, wenn
# "wireguard_centos7_kernel_plus_reboot" auf "true" gesetzt ist.
wireguard_centos7_kernel_plus_reboot_timeout: "600"
# Den Host neu starten, wenn nötig, wenn der Standardkernel verwendet wird
wireguard_centos7_standard_reboot: true
# Die Standardanzahl von Sekunden, die auf die Maschine gewartet werden soll, um neu zu starten und zu reagieren,
# wenn der Standardkernel verwendet wird. Ist nur relevant, wenn
# "wireguard_centos7_standard_reboot" auf "true" gesetzt ist.
wireguard_centos7_standard_reboot_timeout: "600"
#########################################
# Einstellungen nur relevant für RockyLinux 8
#########################################
# Setzen Sie wireguard_rockylinux8_installation_method auf "dkms",
# um das WireGuard-Modul aus dem Quellcode mit wireguard-dkms zu erstellen.
# Dies ist erforderlich, wenn Sie einen benutzerdefinierten Kernel verwenden und/oder Ihre Architektur
# nicht x86_64 ist.
#
# Der Standard "standard" installiert das Kernelmodul
# mit kmod-wireguard von ELRepo.
wireguard_rockylinux8_installation_method: "standard"
Jeder Host in host_vars/
sollte mindestens eine Adresse über wireguard_address
oder wireguard_addresses
konfigurieren. Die wireguard_address
kann nur eine IPv4 enthalten, daher ist es ratsam, die Variable wireguard_addresses
zu verwenden, die ein Array von sowohl IPv4 als auch IPv6-Adressen enthalten kann.
wireguard_addresses:
- "10.8.0.101/24"
Natürlich sollten alle IPs im selbenSubnetz sein, wie /24
, das wir im obigen Beispiel sehen. Wenn wireguard_allowed_ips
nicht gesetzt ist, sind die Standardwerte die IPs, die in wireguard_address
und wireguard_addresses
definiert sind, aber ohne den CIDR, sondern stattdessen mit /32
(IPv4) oder /128
(IPv6), was im Grunde genommen eine Hostroute ist (sehen Sie sich templates/wg.conf.j2
an). Sehen wir uns dieses Beispiel an und nehmen wir an, Sie setzen wireguard_allowed_ips
nicht explizit:
[Interface]
Address = 10.8.0.2/24
PrivateKey = ....
ListenPort = 51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.101/32
Endpoint = controller01.p.domain.tld:51820
Dies ist ein Teil der WireGuard-Config von meiner Workstation. Sie hat die VPN-IP 10.8.0.2
, und wir haben ein /24
-Subnetz, in dem sich alle meine WireGuard-Hosts befinden. Sie können auch sehen, dass wir hier einen Peer haben, der den Endpunkt controller01.p.domain.tld:51820
hat. Wenn wireguard_allowed_ips
nicht explizit gesetzt ist, fügt die Ansible-Vorlage einen AllowedIPs
-Eintrag mit der IP dieses Hosts plus /32
oder /128
hinzu. In WireGuard gibt dies im Grunde genommen die Routinganweisung an. Die Konfiguration oben sagt: Auf meiner Workstation mit der IP 10.8.0.2
möchte ich, dass der gesamte Traffic zu 10.8.0.101/32
an den Endpunkt controller01.p.domain.tld:51820
gesendet wird. Angenommen, wir setzen wireguard_allowed_ips: "0.0.0.0/0"
, dann sieht die resultierende Konfiguration so aus.
[Interface]
Address = 10.8.0.2/24
PrivateKey = ....
ListenPort = 51820
[Peer]
PublicKey = ....
AllowedIPs = 0.0.0.0/0
Endpoint = controller01.p.domain.tld:51820
Das ist im Grunde das Gleiche wie oben, ABER jetzt besagt die Konfiguration: Ich möchte den gesamtenTraffic von meiner Workstation zum Endpunkt controller01.p.domain.tld:51820
leiten. Ob dieser Endpunkt den Traffic verarbeiten kann, ist natürlich eine andere Sache und es liegt an Ihnen, wie Sie das Routing für den Endpunkt konfigurieren.
Sie können zusätzlich weitere optionale Einstellungen angeben (die keinen Standardwert haben und nicht gesetzt werden, wenn nicht angegeben, außer wireguard_allowed_ips
, wie bereits erwähnt) auch pro Host in host_vars/
(oder in Ihrer Ansible-Hosts-Datei, wenn Sie möchten). Die Werte für die folgenden Variablen sind nur Beispiele und keine Standards (für weitere Informationen und Beispiele siehe wg-quick.8):
wireguard_allowed_ips: ""
wireguard_endpoint: "host1.domain.tld"
wireguard_persistent_keepalive: "30"
wireguard_dns: "1.1.1.1"
wireguard_fwmark: "1234"
wireguard_mtu: "1492"
wireguard_table: "5000"
wireguard_preup:
- ...
wireguard_predown:
- ...
wireguard_postup:
- ...
wireguard_postdown:
- ...
wireguard_save_config: "true"
wireguard_(preup|predown|postup|postdown)
werden als Listen angegeben. Hier sind zwei Beispiele:
wireguard_postup:
- iptables -t nat -A POSTROUTING -o ens12 -j MASQUERADE
- iptables -A FORWARD -i %i -j ACCEPT
- iptables -A FORWARD -o %i -j ACCEPT
wireguard_preup:
- echo 1 > /proc/sys/net/ipv4/ip_forward
- ufw allow 51820/udp
Die Befehle werden in der angegebenen Reihenfolge ausgeführt, wie in wg-quick.8 beschrieben.
Zusätzlich können "unmanaged" Peers hinzugefügt werden. Diese Peers werden nicht von Ansible verwaltet und sind nicht Teil der Ansible-Hostgruppe vpn
, z.B.:
wireguard_unmanaged_peers:
client.example.com:
public_key: 5zsSBeZZ8P9pQaaJvY9RbELQulcwC5VBXaZ93egzOlI=
# preshared_key: ... z.B. aus ansible-vault?
allowed_ips: 10.0.0.3/32
endpoint: client.example.com:51820
persistent_keepalive: 0
Eine der wireguard_address
(veraltet) oder wireguard_addresses
(empfohlen) ist wie bereits erwähnt erforderlich. Es sind die IPs des Schnittstellennamens, der mit der Variable wireguard_interface
definiert ist (standardmäßig wg0
). Jeder Host benötigt natürlich mindestens eine eindeutige VPN-IP. Wenn Sie wireguard_endpoint
nicht festgelegt haben, wird das Playbook den Hostnamen verwenden, der in der Hostgruppe vpn
definiert ist (den Ansible-Inventar-Hostnamen). Wenn Sie wireguard_endpoint
auf ""
(leerer String) setzen, wird dieser Peer keinen Endpunkt haben. Das bedeutet, dass dieser Host nur auf Hosts zugreifen kann, die einen wireguard_endpoint
haben. Dies ist nützlich für Clients, die keine Dienste im VPN bereitstellen und nur auf Dienste auf anderen Hosts zugreifen möchten. Wenn Sie also nur einen Host definieren, dessen wireguard_endpoint
festgelegt ist und alle anderen Hosts wireguard_endpoint
auf ""
(leerer String) gesetzt haben, bedeutet das im Grunde, dass Sie nur Clients haben, abgesehen von einem, der in diesem Fall der WireGuard-Server ist. Die dritte Möglichkeit besteht darin, wireguard_endpoint
auf einen bestimmten Hostnamen zu setzen. Zum Beispiel, wenn Sie unterschiedliche Hostnamen für die private und öffentliche DNS dieses Hosts haben und unterschiedliche DNS-Einträge für diesen Fall benötigen, wird das Setzen von wireguard_endpoint
nützlich. Nehmen wir als Beispiel die oben genannte IP: wireguard_address: "10.8.0.101"
. Dies ist eine private IP, und ich habe einen DNS-Eintrag für diese private IP erstellt, wie host01.i.domain.tld
(i
für intern in diesem Fall). Für die öffentliche IP habe ich einen DNS-Eintrag erstellt wie host01.p.domain.tld
(p
für öffentlich). Das wireguard_endpoint
muss eine Schnittstelle sein, mit der die anderen Mitglieder in der vpn
-Gruppe eine Verbindung herstellen können. In diesem Fall würde ich also wireguard_endpoint
auf host01.p.domain.tld
setzen, da WireGuard normalerweise eine Verbindung zur öffentlichen IP der anderen Hosts herstellen muss.
Hier ist ein kleines Beispiel, wofür ich das Playbook verwende: Ich verwende WireGuard, um ein vollständig vernetztes VPN einzurichten (jeder Host kann direkt mit jedem anderen Host verbinden) und betreibe meinen Kubernetes (K8s)-Cluster in der Hetzner Cloud (aber Sie sollten jeden beliebigen Anbieter verwenden können). Die wichtigen Komponenten wie die K8s-Controller- und Workerknoten (zu denen auch die Pods gehören) kommunizieren nur über das verschlüsselte WireGuard-VPN. Auch (wie bereits erwähnt) habe ich zwei Clients. Beide haben kubectl
installiert und können über das WireGuard-VPN mit dem internen Kubernetes-API-Server kommunizieren. Einer der beiden Clients bietet außerdem einen WireGuard-Endpunkt, da der Postfix-Mailserver in der Cloud und mein interner Postfix miteinander kommunizieren müssen. Ich denke, das ist vielleicht ein etwas unüblicher Anwendungsfall für WireGuard :D Aber es zeigt, was möglich ist. Lassen Sie mich das Setup erklären, was Ihnen helfen könnte, diese Ansible-Rolle zu nutzen.
Zuerst, hier ist ein Teil meiner Ansible hosts
-Datei:
[vpn]
controller0[1:3].i.domain.tld
worker0[1:2].i.domain.tld
server.at.home.i.domain.tld
workstation.i.domain.tld
[k8s_controller]
controller0[1:3].i.domain.tld
[k8s_worker]
worker0[1:2].i.domain.tld
Wie Sie sehen können, habe ich hier drei Gruppen: vpn
(alle Hosts, auf denen WireGuard installiert wird), k8s_controller
(die Kubernetes-Controller-Knoten) und k8s_worker
(die Kubernetes-Worker-Knoten). Das i
im Domänennamen steht für intern
. Alle DNS-Einträge i.domain.tld
haben einen A
-Eintrag, der auf die WireGuard-IP zeigt, die wir gleich für jeden Host definieren, z.B.: controller01.i.domain.tld. IN A 10.8.0.101
. Der Grund dafür ist, dass alle Kubernetes-Komponenten in meinem Setup nur an der WireGuard-Schnittstelle gebunden sind und darauf hören. Und da ich diese internen IPs für all meine Kubernetes-Komponenten benötige, gebe ich die internen DNS-Einträge in meiner Ansible hosts
-Datei an. Auf diese Weise kann ich die Ansible-Inventar-Hostnamen und Variablen sehr einfach in den Playbooks und Vorlagen verwenden.
Für die Kubernetes-Controller-Knoten habe ich die folgenden Hostvariablen definiert:
Ansible-Hostdatei: host_vars/controller01.i.domain.tld
---
wireguard_addresses:
- "10.8.0.101/24"
wireguard_endpoint: "controller01.p.domain.tld"
ansible_host: "controller01.p.domain.tld"
ansible_python_interpreter: /usr/bin/python3
Ansible-Hostdatei: host_vars/controller02.i.domain.tld
:
---
wireguard_addresses:
- "10.8.0.102/24"
wireguard_endpoint: "controller02.p.domain.tld"
ansible_host: "controller02.p.domain.tld"
ansible_python_interpreter: /usr/bin/python3
Ansible-Hostdatei: host_vars/controller03.i.domain.tld
:
---
wireguard_addresses:
- "10.8.0.103/24"
wireguard_endpoint: "controller03.p.domain.tld"
ansible_host: "controller03.p.domain.tld"
ansible_python_interpreter: /usr/bin/python3
Ich habe hier ansible_python_interpreter
für jeden Knoten angegeben, da die Controller-Knoten Ubuntu 18.04 verwenden, das standardmäßig Python 3 installiert hat. ansible_host
ist auf die öffentliche DNS dieses Hosts gesetzt. Ansible verwendet diesen Hostnamen, um sich über SSH mit dem Host zu verbinden. Ich verwende denselben Wert auch für wireguard_endpoint
, aus demselben Grund. Die WireGuard-Peers müssen über eine öffentliche IP mit den anderen Peers kommunizieren (nun ja, zumindest mit einer IP, mit der die WireGuard-Hosts eine Verbindung herstellen können - das könnte natürlich auch eine interne IP sein, wenn das für Sie funktioniert). IPs, die durch wireguard_address
oder wireguard_addresses
angegeben sind, müssen natürlich für jeden Host eindeutig sein.
Für die Kubernetes-Worker habe ich die folgenden Variablen definiert:
Ansible-Hostdatei: host_vars/worker01.i.domain.tld
---
wireguard_addresses:
- "10.8.0.111/24"
wireguard_endpoint: "worker01.p.domain.tld"
wireguard_persistent_keepalive: "30"
ansible_host: "worker01.p.domain.tld"
ansible_python_interpreter: /usr/bin/python3
Ansible-Hostdatei: host_vars/worker02.i.domain.tld
:
---
wireguard_addresses:
- "10.8.0.112/24"
wireguard_endpoint: "worker02.p.domain.tld"
wireguard_persistent_keepalive: "30"
ansible_host: "worker02.p.domain.tld"
ansible_python_interpreter: /usr/bin/python3
Wie Sie sehen können, sind die Variablen im Grunde genommen dieselben wie die der Controller-Knoten, mit einer Ausnahme: wireguard_persistent_keepalive: "30"
. Meine Workernodes (in der Hetzner Cloud) und mein interner Server (mein Server zu Hause) sind verbunden, weil ich Postfix auf meinen Cloud-Knoten ausführe und der externe Postfix-Server die empfangenen E-Mails an meinen internen Server weiterleitet (und umgekehrt). Ich benötigte die Keepalive-Einstellung, da von Zeit zu Zeit die Cloud-Instanzen und der interne Server die Verbindung verloren und diese Einstellung das Problem gelöst hat. Der Grund dafür ist natürlich, dass mein interner Server hinter NAT steht und der NAT/Firewall-Traffic gültig bleiben muss (NAT und Firewall Traversal Persistence).
Für meinen internen Server zu Hause (verbunden über DSL-Router mit dem Internet) haben wir diese Konfiguration:
---
wireguard_addresses:
- "10.8.0.1/24"
wireguard_endpoint: "server.at.home.p.domain.tld"
wireguard_persistent_keepalive: "30"
ansible_host: 192.168.2.254
ansible_port: 22
Standardmäßig hört der SSH-Daemon an einem anderen Port als 22 auf all meinen öffentlichen Knoten, aber intern verwende ich 22
, und das ist der Grund, diesen Wert hier zu setzen: ansible_port: 22
. Auch ansible_host
ist natürlich eine interne IP für diesen Host. Der Wert von wireguard_endpoint
ist ein dynamischer DNS-Eintrag. Da meine IP zu Hause nicht statisch ist, muss ich alle 60 Sekunden ein Skript auf meinem Heimserver ausführen, das überprüft, ob sich die IP geändert hat, und falls ja, meinen DNS-Eintrag anpasst. Ich benutze dafür die DynHost-Funktion von OVH, aber Sie können jeden DynDNS-Anbieter verwenden, den Sie möchten. Ich habe auch den eingehenden Verkehr auf den Port 51820/UDP
an meinen internen Server weitergeleitet, um eingehenden WireGuard-Verkehr zuzulassen. IPs aus wireguard_address
und wireguard_addresses
müssen natürlich Teil unseres WireGuard-Subnetzes sein.
Und schließlich für meine Workstation (auf der ich alle ansible-playbook
-Befehle ausführe):
wireguard_addresses:
- "10.8.0.2/24"
wireguard_endpoint: ""
ansible_connection: local
ansible_become: false
Wie Sie sehen können, ist wireguard_endpoint: ""
hier ein leerer String. Das bedeutet, dass die Ansible-Rolle keinen Endpunkt für meine Workstation setzen wird. Da es keinen Bedarf gibt, dass die anderen Hosts mit meiner Workstation verbinden, macht es keinen Sinn, einen Endpunkt zu definieren. In diesem Fall kann ich von meiner Workstation auf alle in der Ansible-Gruppe vpn
definierten Hosts zugreifen, jedoch nicht umgekehrt. Die resulting WireGuard-Konfiguration für meine Workstation sieht folgendermaßen aus:
[Interface]
Address = 10.8.0.2/24
PrivateKey = ....
ListenPort = 51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.101/32
Endpoint = controller01.p.domain.tld:51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.102/32
Endpoint = controller02.p.domain.tld:51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.103/32
Endpoint = controller03.p.domain.tld:51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.111/32
PersistentKeepalive = 30
Endpoint = worker01.p.domain.tld:51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.112/32
PersistentKeepalive = 30
Endpoint = worker02.p.domain.tld:51820
[Peer]
PublicKey = ....
AllowedIPs = 10.8.0.1/32
PersistentKeepalive = 30
Endpoint = server.at.home.p.domain.tld:51820
Die anderen WireGuard-Konfigurationsdateien (wg0.conf
standardmäßig) sehen ähnlich aus, aber natürlich enthält [Interface]
die Konfiguration dieses bestimmten Hosts und die [Peer]
-Einträge listen die Konfiguration der anderen Hosts auf.
Beispiel-Playbooks
- hosts: vpn
roles:
- githubixx.ansible_role_wireguard
hosts: vpn
roles:
-
role: githubixx.ansible_role_wireguard
tags: role-wireguard
Beispiel-Inventar mit zwei verschiedenen WireGuard-Schnittstellen auf dem Host "multi"
Dies ist ein komplexes Beispiel unter Verwendung des YAML-Inventarformats:
vpn1:
hosts:
multi:
wireguard_addresses:
- "10.9.0.1/32"
wireguard_allowed_ips: "10.9.0.1/32, 192.168.2.0/24"
wireguard_endpoint: multi.example.com
nated:
wireguard_addresses:
- "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.example.com
wireguard_postup:
- iptables -t nat -A POSTROUTING -o ens12 -j MASQUERADE
- iptables -A FORWARD -i %i -j ACCEPT
- iptables -A FORWARD -o %i -j ACCEPT
wireguard_postdown:
- iptables -t nat -D POSTROUTING -o ens12 -j MASQUERADE
- iptables -D FORWARD -i %i -j ACCEPT
- iptables -D FORWARD -o %i -j ACCEPT
vpn2:
hosts:
# Verwenden Sie einen anderen Namen und definieren Sie ansible_host, um ein Mischen von Variablen zu vermeiden, ohne
# die Variablen mit dem Schnittstellennamen vorauszusetzen.
multi-wg1:
ansible_host: multi
wireguard_interface: wg1
# Wenn mehrere Schnittstellen auf einem Host verwendet werden, müssen unterschiedliche Ports verwendet werden
wireguard_port: 51821
wireguard_addresses:
- "10.9.1.1/32"
wireguard_endpoint: multi.example.com
another:
wireguard_address:
- "10.9.1.2/32"
wireguard_endpoint: another.example.com
Beispiel-Playbooks für das obige Beispiel:
- hosts: vpn1
roles:
- githubixx.ansible_role_wireguard
- hosts: vpn2
roles:
- githubixx.ansible_role_wireguard
Tests
Diese Rolle hat ein kleines Testsetup, das mithilfe von Molecule, libvirt (vagrant-libvirt) und QEMU/KVM erstellt wurde. Bitte sehen Sie meinen Blogbeitrag Testing Ansible roles with Molecule, libvirt (vagrant-libvirt) and QEMU/KVM an, wie Sie das Setup durchführen. Die Testkonfiguration ist hier.
Danach kann Molecule ausgeführt werden:
molecule converge
Damit werden einige virtuelle Maschinen (VMs) mit verschiedenen unterstützten Linux-Betriebssystemen eingerichtet. Um einige Tests durchzuführen:
molecule verify
Um aufzuräumen, führen Sie aus:
molecule destroy
Es gibt auch ein kleines Molecule-Setup, das einen zentralen WireGuard-Server mit einigen Clients nachahmt:
molecule converge -s single-server
Lizenz
GNU General Public License v3.0 oder später
Autoreninformationen
Installs Wireguard incl. systemd integration
ansible-galaxy install githubixx.ansible_role_wireguard