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)
  • FEATURE

    • Unterstützung für Ubuntu 24.04 hinzugefügt
    • Unterstützung für openSUSE 15.6 hinzugefügt
  • MOLECULE

    • Veralteten Proxmox-Code entfernt
    • Vagrant-Box rockylinux/9 durch bento/rockylinux-9 ersetzt
    • Verwenden von ansible.builtin.package für AlmaLinux
    • AlmaLinux 8, Rocky Linux 8 und CentOS 7 entfernt (veraltetes Python macht es schwer, mit Ansible zu testen)

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

http://www.tauceti.blog

Über das Projekt

Installs Wireguard incl. systemd integration

Installieren
ansible-galaxy install githubixx.ansible_role_wireguard
Lizenz
Unknown
Downloads
239.1k
Besitzer
Senior System Engineer - Python, Go, Cloud, Kubernetes, Commodore, Retro, 80's ;-)