OpenVPN-Clientnamen in dnsmasq: Skript oder statische Einträge?
Client-Adressen ändern sich, Dienstnamen nicht. Erzeugen Sie Clientnamen aus der VPN-Sitzung, pinnen Sie Dienstnamen in eine Drop-in-Datei und bringen Sie die Clients dann dazu, sie zu nutzen.
Auf fast jedem kleinen OpenVPN-Gateway treten zwei Namensprobleme auf. Ein verbundenes Notebook ist nicht über den Namen in seinem Zertifikat erreichbar, und die Dienste hinter dem Tunnel haben überhaupt keine Namen. Beide wirken wie ein Problem und brauchen doch entgegengesetzte Behandlung, denn die eine Adresse wandert mit jeder Sitzung, die andere nicht. Entscheiden Sie vor jeder Änderung, welche Art von Namen Sie hinzufügen.
Pro Name entscheiden, nicht pro Gateway
Der Test ist einfach: Ändert sich diese Adresse, wenn ein Client sich neu verbindet? Wenn ja, muss der Name aus der VPN-Sitzung erzeugt werden. Wenn nein, gehört er in einen statischen Eintrag, den Sie lesen und prüfen können.
| Name kind | Source of truth | Where it lives |
|---|---|---|
| Connected client | The address OpenVPN just assigned | Generated hosts file, rewritten per session |
| Service behind the tunnel | A fixed address you chose | Static address= drop-in |
| Anything with a certificate name | The certificate, not the pool | Either, but the name must match the certificate |
Beides zu vermischen ist der übliche Fehler. Ein in die erzeugte Datei gepinnter Dienst verschwindet beim ersten Neuschreiben durch das Skript, und ein in einen statischen Eintrag geschriebener Client zeigt auf denjenigen, der diese Adresse zuletzt hatte. Beide Fehler bleiben unsichtbar, bis ein Name auf die falsche Maschine auflöst. Dann nimmt die fehlersuchende Person an, DNS sei kaputt, nicht die Datei.
Der dynamische Weg: learn-address und der Pool
OpenVPN kennt die Zuweisung, also lassen Sie es Ihnen sagen. Diese Serveroptionen machen die Zuweisung dauerhaft und skriptbar:
client-config-dir /etc/openvpn/ccd
ifconfig-pool-persist /etc/openvpn/ip-pool 60
script-security 2
learn-address /etc/openvpn/learn-address.sh
learn-address führt Ihr Skript aus, sobald eine Adresse hinzugefügt, aktualisiert oder gelöscht wird, und übergibt die Operation, die Adresse und den Common Name. Ein minimales Skript hängt eine Zeile pro Client an und entfernt sie beim Löschen:
#!/bin/sh
HOSTS=/etc/openvpn/hosts.lan
case "$1" in
add|update) echo "$2 $3" >> "$HOSTS" ;;
delete) sed -i "/^$2 /d" "$HOSTS" ;;
esac
kill -HUP $(cat /var/run/dnsmasq.pid)
Auf einem tun-Gerät ist das zweite Argument die Tunneladresse des Clients, die Zeile ist also direkt brauchbar. Auf einem tap-Gerät übergibt OpenVPN stattdessen die MAC-Adresse des Clients, weil ein tap-Segment auch andere Protokolle als IPv4 tragen kann, und dann müssen Sie die Adresse vor dem Schreiben über den Common Name in der Pool-Datei nachschlagen.
Seien Sie klar darüber, was die erzeugte Datei ist: eine Momentaufnahme dessen, wer gerade verbunden ist. Namen verschwinden beim Trennen, was genau das ist, was Sie für Notebooks wollen, die zwischen Netzen wechseln, und genau das, was Sie für einen Server nicht wollen, der die ganze Nacht läuft.
Der statische Weg: address= und Domain-Expansion
Richten Sie dnsmasq auf die erzeugte Datei statt auf die hosts-Datei des Systems, und geben Sie ihr eine Domain, damit kurze Namen zu vollqualifizierten expandieren:
domain=corp.example
no-hosts
addn-hosts=/etc/openvpn/hosts.lan
listen-address=127.0.0.1,10.8.0.1
bind-interfaces
Mit gesetztem domain antwortet eine Zeile wie 10.8.0.6 alice sowohl für alice als auch für alice.corp.example. Beschränken Sie listen-address auf das Tunnel-Gateway und Loopback, denn ein versehentlich auf dem LAN-Interface veröffentlichter Resolver ist ein Dienst, den Sie nicht anbieten wollten.
Dienste, die nie aus dem Pool kommen, bekommen eigene Einträge. Legen Sie sie in eine separate Drop-in-Datei im Konfigurationsverzeichnis der Distribution, damit ein Paket-Upgrade sie nicht überschreiben kann:
address=/files.corp.example/10.8.0.20
address=/db.corp.example/10.9.0.5
Geben Sie den Resolver weiter, sonst passiert nichts
Ein Resolver, den niemand abfragt, ändert nichts. Der Server muss ihn ankündigen:
push "dhcp-option DNS 10.8.0.1"
push "dhcp-option DOMAIN corp.example"
Windows-Clients wenden beide Optionen selbst an. Die meisten Linux-Clients nicht: Sie brauchen eine unterstützte Resolver-Integration wie den update-resolv-conf-Hook der Distribution oder die DNS-Behandlung von NetworkManager, oder eine manuelle Suchdomain und einen Nameserver. Prüfen Sie den tatsächlichen Resolver des Clients, statt anzunehmen, dass der Push befolgt wurde, denn ein ignorierter Push sieht genauso aus wie ein Server, der nicht antwortet.
Auf drei Ebenen prüfen
Fragen Sie zuerst den Server direkt, dann einen Client, dann die Anwendung:
dig +short @10.8.0.1 alice.corp.example
getent hosts files.corp.example
Wenn direkte Abfragen antworten und die Anwendung nicht, liegt der Fehler in der Übergabe an den Client und nicht in der Zone. Wenn der Name auflöst und die Verbindung trotzdem scheitert, ist der Name in Ordnung, und als Nächstes sind Route oder Firewall dran.
Schreiben Sie die beiden Kategorien neben die Konfiguration: welche Namen erzeugt werden, welche gepinnt sind und mit welchem Zertifikat jedes übereinstimmen muss. Die nächste Person, die einen Server hinzufügt, kopiert das Muster, das sie zuerst findet.