22 Juni 2021

Yubico OTP selbst gehostet

Im vorangegangenen Artikel Zwei-Faktor-Authentisierung mit Yubico OTP haben wir gezeigt, wie schnell man mit Hilfe des PAM-Moduls pam_yubico bestehende Dienste um eine Zwei-Faktor-Authentisierung (2FA) mit Yubico OTP erweitern kann. Der dabei genutzte Validierungs-Service, die YubiCloud, wird von Yubico kostenlos zur Verfügung gestellt.

Die Tatsache, dass man sich dabei an einen externen Dienstleister bindet, gefällt jedoch nicht jedem: Datenschutzbedenken oder Zweifel an der Ausfallsicherheit des Cloud-Services führen zur Frage, ob der Betrieb der benötigten Dienste nicht auch auf eigenen Systemen möglich ist. Auch mag es Szenarien geben, bei welchem man nicht auf externe Dienste nicht zugreifen kann.

Die erfreuliche Antwort ist, dass es auch die Möglichkeit gibt, die Dienste entsprechend selber zu hosten!

Komponenten

Um Yubico OTPs auf einem eigenen System validieren zu können, werden zwei Komponenten benötigt: der YubiKey OTP Validation Server und das YubiKey Key Storage Module. Yubico stellt die benötigte Software sowohl im Quelltext, als auch als fertige Binärpakete in verschiedenen Linux-Distributionen zur Verfügung.

Es ist zu beachten, dass ein Großteil der online verfügbaren Dokumentation noch auf dem alten Key Storage Modul, YK-KSM, basiert. Das YK-KSM ist in PHP5 implementiert und als veraltet anzusehen, denn es benötigt Funktionen und Bibliotheken, welche in aktuellen PHP-Versionen nicht mehr enthalten bzw. verfügbar sind.

Validation Server – VAL

Der Validation Server implementiert die Yubico WSAPI zur Validierung von Yubico OTP, welche auch in der YubiCloud zum Einsatz kommt. Es handelt sich dabei um eine PHP-Anwendung, die für den Betrieb neben dem Apache Webserver ein RDBMS wie PostgreSQL oder MySQL benötigt.

Das in den vergangenen Artikeln behandelte PAM-Modul pam_yubico kann durch Angabe einer URL so konfiguriert werden, dass es statt der YubiCloud einen anderen, in unserem Falle lokalen, Validation Server nutzt.

Sendet ein Client, zum Beispiel das PAM-Modul, über die WSAP ein Yubico OTP an den Validierungsdienst, sendet dieser das OTP an das Key Storage Module weiter, und enthält das OTP entschlüsselt von dort zurück. Anhand der Zählerstände und Zeitstempel, welche mit den letzten, in der Datenbank gespeicherten Werten verglichen werden, kann der VAL dann entscheiden, ob das OTP gültig ist oder nicht.

Key Storage Modul – KSM

Das Key Storage Module dient der sicheren Aufbewahrung der Shared Secrets der verwendeten YubiKeys. Der für die Verschlüsselung verwendete Schlüssel wird dafür entweder auf einem gut 650,– € teuren Hardware-Modul oder aber – wie in diesem Falle – preisgünstig in einer Textdatei gespeichert. Im Gegensatz zum VAL benötigt das KSM keine relationale Datenbank, sondern nutzt stattdessen das Dateisytem, standardmäßig den Ordner /var/cache/yubikey-ksm, und legt dort die Shared Secrets verschlüsselt in sogenannten AEAD-Dateien ab.

Das hier verwendete KSM ist in Python implementiert und läuft als eigenständiger Dienst, welcher standardmäßig auf Port 8002 TCP auf Verbindungen von localhost lauscht und dort ein simples REST-Interface anbietet.

Über dieses REST-Interface kann der Validation Server zu überprüfende OTP an das Key Storage Module senden, welches dann anhand der Public ID das entsprechende Shared Secret aus seinem Speicher ausliest, um damit das OTP zu entschlüsseln und dessen Inhalt an den VAL zurückzuliefern.

Installation

Erfreulicherweise existieren sowohl für den Validierungs-Server als auch für das Key Storage Modul fertige Pakete in den meisten Linux-Distributionen. Im Folgenden wird die Installation und Konfiguration der Dienste unter Debian GNU/Linux Buster beschrieben.

Key Storage Modul – KSM

Das KSM kann in Debian einfach mit dem Paket yhsm−yubikey−ksm installiert werden:

# apt-get install yhsm−yubikey−ksm

Bevor es an die Konfiguration des frisch installierten Dienstes geht, muss noch das sogenannte Keyfile, welches den für die Verschlüsselung des Key Storage verwendeten Schlüssel enthält, angelegt werden:

# mkdir -p /etc/yubico/yhsm
# touch /etc/yubico/yhsm/keys.json
# chown yhsm−ksmsrv /etc/yubico/yhsm/keys.json
# chmod 400 /etc/yubico/yhsm/keys.json

Das Keyfile kann nun mit einem beliebigen Editor geöffnet und mit einem Schlüssel gefüllt werden. Wie die Dateiendung andeutet handelt es ich bei dem Keyfile um eine JSON-Datei. Im folgenden Beispiel lautet der Schlüssel, welcher sich in “Slot” 1 befindet, 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f.

{
    "1": "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f"
}

Bei 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f handelt es sich um die hexadezimale Darstellung eines 32 Byte (also 256 Bit) langen Beispielschlüssels. Für den produktiven Einsatz sollte natürlich ein vernünftiger, aus Zufallsdaten erstellter Schlüssel benutzt werden. Hierfür kann das Programm openssl benutzt werden:

$ openssl rand -hex 32

Um das KSM zu konfigurieren, müssen in der Datei /etc/default/yhsm−yubikey−ksm nur wenige Parameter angepasst werden:

YHSM_KSM_ENABLE="true"
YHSM_KSM_DEVICE="/etc/yubico/yhsm/keys.json"
YHSM_KSM_KEYHANDLES="1"

Der Parameter YHSM_KSM_ENABLE="true" sorgt dafür, dass das KSM beim Systemstart automatisch gestartet wird. Dabei wird statt des standardmäßig konfigurierten Hardware-Devices das soeben erstellte Keyfile und daraus der Schlüssel mit der ID 1 verwendet.

Mit systemctl restart yhsm−yubikey−ksm wird das KSM zu guter Letzt mit der geänderten Konfiguration neu gestartet.

Validation Server – VAL

Wie bereits erwähnt handelt es sich beim Validation Server um eine in PHP geschriebene Webanwendung, deren Betrieb einen Webserver und ein RDBMS voraussetzt. Während die Paketabhängigkeiten einen Apache Webserver vorschreiben, hat man bei den Datenbanken die Wahl zwischen MySQL, MariaDB und PostgreSQL. Gemäß der Abhängigkeitsreihenfolge des Pakets würde von apt hier MySQL installiert, um jedoch PostgreSQL den Vorzug zu geben muss dieses explizit aufgeführt werden:

# apt-get install yubikey−val postgresql php−pgsql

Die in /etc/yubico/val/ befindliche Konfiguration des Validation Servers ist standardmäßig auf das lokal auf dem gleichen System laufende Key Storage Modul eingestellt, sodass keine weiteren Eingriffe notwendig sind.

Damit sich das PAM-Modul später bei Anfragen an den Validation Server authentifizieren kann, müssen noch Credentials in Form einer ID sowie eines Schlüssels erstellt werden:

# ykval−gen−clients
2,cOyFHRvltNYDjx74JE9jOBcdPhI=

Dieser Schritt entspricht der im vorausgegangenen Artikel beschriebenen Registrierung in der YubiCloud. Die Ausgabe des Kommandos besteht aus zwei Teilen: der ID, gefolgt von einem Komma und dem Schlüssel in Base64-Kodierung.

Soll der Validation Service von mehreren Maschinen aus genutzt werden, empfiehlt es sich für jede Maschine eigene Credentials zu erstellen. Um mehrere ID-Schlüssel-Paare erstellen zu lassen, wird ykval-gen-clients einfach mit der gewünschten Anzahl aufgerufen:

# ykval−gen−clients 5
3,6WP1q1ohy92G/BNLMNjpHpVeL1Q=
4,InVj6Nbqc9FQN1EgtbsedtuYT9I=
5,p/R/hHx6E3Kf3Qc+671O46laNec=
6,/FRX6YqioHSap+zoM+LkWp88TFU=
7,XxEp4zoHSi9zTDSngvxnGiD4V1A=

Um den Überblick nicht zu verlieren, sollte festgehalten werden, für welchen Rechner welche Credentials benutzt wurden. Alternativ erlaubt ykval-gen-clients mit dem Schalter --notes das Anlegen einer Notiz:

# ykval-gen-clients --notes=OpenVPN
8,rZKpqc5WcU4OB4Nv551+U3lj2tk=

Das Programm ykval-export-clients gibt alle in der Datenbank gespeicherten Credentials samt Notizen auf der Standardausgabe aus:

# ykval-export-clients
1,1,1619686861,ua//VH5rvFoxrFHGhLZBz/RO3m0=,,,
…
8,1,1619687606,pkodRX1F77Ck7bvS9MzpXE5IfxA=,,OpenVPN,

Hier ist zu erkennen, dass während der Installation des Pakets schon Credentials mit der ID 1 erstellt wurden. Selbstverständlich kann man, statt eine eigene ID anzulegen, auch diese aus der Datenbank auslesen und zur Einrichtung des PAM-Moduls benutzen.

PAM

Als letzte Änderung am System muss das PAM-Modul pam_yubico installiert und in die entsprechende Dienstkonfiguration eingetragen werden.

# apt-get install libpam−yubico

Wie auch schon in den vorherigen Artikeln soll auch hier wieder OpenVPN in den Genuss einer 2FA mit Yubico OTP kommen. Hierzu wird die Datei /etc/pam.d/openvpn angelegt bzw. angepasst:

auth sufficient pam_yubico.so id=2 key=cOyFHRvltNYDjx74JE9jOBcdPhI= urllist=http://localhost/wsapi/2.0/verify authfile=/etc/yubikey_mappings
account required pam_permit.so

Als Werte für id und key werden jeweils die Werte angegeben, welche beim obigen Aufruf von ykval-gen-clients bzw. ykval-export-clients ausgegeben wurden. Der Parameter urllist erhält die URL der WSAPI des Validierungsdienstes, der in diesem Fall auf dem gleichen Rechner läuft.

Wie auch beim Einsatz der YubiCloud muss auch diesmal wieder ein authfile angegeben werden – eine Datei, welche die Mappings von Benutzernamen auf Public IDs enthält. Diese wird später, nach der Erzeugung der Schlüssel, angelegt.

Die Konfiguration des OpenVPN-Dienstes erfolgt wie im Artikel Zwei-Faktor-Authentisierung für OpenSSH und OpenVPN beschrieben. Serverseitig muss dafür das mitgelieferte OpenVPN-PAM-Plugin in der Konfiguration geladen werden:

plugin /usr/lib/openvpn/openvpn-plugin-auth-pam.so openvpn

Clientseitig wird der bestehenden Konfiguration lediglich die Option auth-user-pass hinzugefügt, sodass der Benutzer beim Verbindungsaufbau nach Benutzernamen und Passwort (hier: OTP) gefragt wird.

Schlüsselverwaltung

Damit YubiKeys mit einem eigenen Validierungsdienst genutzt werden können, müssen diese mit einem neuen Schlüssel, dem Shared Secret, programmiert werden. Diese Schlüssel werden im KSM erstellt, aus diesem ausgelesen und dann auf den YubiKey geschrieben.

Da das werksseitig auf dem YubiKey programmierte Shared Secret nicht ausgelesen werden kann, ist dieses nicht für einen selbst gehosteten Validierungsdienst zu gebrauchen.

Erzeugung im KSM

Um eine Reihe von Schlüsseln im Key Storage Module zu erzeugen, wird der Befehl yhsm-generate-keys verwendet:

# yhsm-generate-keys -D /etc/yubico/yhsm/keys.json --key-handle 1 --start-public-id credtivccccc -c 10
output dir              : /var/cache/yubikey-ksm/aeads
keys to generate        : 10
key handles             : {1: '1'}
start public_id         : 13412510728192 (0xc32d7f00000)
YHSM device             : /etc/yubico/yhsm/keys.json

Generating 10 keys

Done

Der obige Befehl erstellt 10 (-c) Schlüssel, beginnend mit der ID credtivccccc (--start-public-id) und nutzt für die Verschlüsselung den Key mit der ID 1 (--key-handle), welcher in der Datei /etc/yubico/yhsm/keys.json (-D) gespeichert ist. Die Schlüssel werden wie oben beschrieben unter /var/cache/yubikey-ksm/aeads abgelegt.

Die Ausgabe gibt einen kurzen Überblick über die verwendeten Parameter, das schlichte Done zeigt die erfolgreiche Erstellung und Speicherung der Credentials an.

Vorsicht: wird der obige Befehl mehrfach aufgerufen, werden bereits existierende Schlüssel mit der gleichen ID ohne Rückfrage überschrieben!

Mit Hilfe des Befehls yhsm-decrypt-aead können die soeben erstellten Schlüssel nun aus dem KSM ausgelesen werden:

# yhsm-decrypt-aead --aes-key 000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f --format yubikey-csv /var/cache/yubikey-ksm/aeads/
1,credtivccccf,47072c411963,1feff43b2d2b529c697d9db0849c9594,000000000000,,,,,,
2,credtivccccc,512a73c09e98,d6e07a6def46cee722be21b7c2f35aec,000000000000,,,,,,
3,credtivcccce,b491988426de,a72669341ab2a7d2acecec91c2fa0efb,000000000000,,,,,,
4,credtivcccci,fccc5e1dcfcf,b0b14a2454c6d2a54bd2351f09d19d6e,000000000000,,,,,,
5,credtivccccb,8a0b3916582f,a031f201920f6204a38b239836486bbf,000000000000,,,,,,
6,credtivccccj,b9dd85895291,e04d79d45ff80438c744f2a8deec4a15,000000000000,,,,,,
7,credtivccccg,a5213cab8e9c,f20acb5646de4282f21ef12b65c6a082,000000000000,,,,,,
8,credtivcccch,73e9c1fa06b9,4c9d121e432a2fbd14b4a5d96f3b9d8f,000000000000,,,,,,
9,credtivccccd,0695db026eb8,90779c79b363b7dbe54a9c3012e688e5,000000000000,,,,,,
10,credtivcccck,ddd42451acb3,f5803057ea519149041be830509b7b2a,000000000000,,,,,,

Als --aes-key wird hier der bei der Einrichtung des KSM erzeugte AES-Schlüssel angegeben; das Argument --format yubikey-csv sorgt dafür, dass die Credentials als Komma-separierte Werte statt im Rohformat ausgegeben werden. Als letztes Argument wird der Speicherort der AEAD im Dateisystem angegeben.

Programmieren des YubiKey

Eine Zeile in der obigen Ausgabe des Befehls yhsm-decrypt-aead enthält in mehreren, durch Kommata getrennten Feldern, die Credentials für einen YubiKey: neben der Seriennummer (Feld 1) sind das die Public ID (Feld 2), die Private ID (Feld 3) sowie der eigentliche AES-Schlüssel (Feld 4). Alle weiteren Felder finden in unserem Fall keine Anwendung.

Der Eintrag in Zeile 1 enthält also die Public ID credtivccccf mit der Private UID 47072c411963 und dem AES-Schlüssel 1feff43b2d2b529c697d9db0849c9594.

Diese Credentials können nun auf einen YubiKey geschrieben werden. Das Programm ykpersonalize ist ein mächtiges Kommandozeilentool zur Konfiguration von YubiKeys und befindet sich bei Debian im Paket yubikey-personalization.

Befindet sich in Slot 1 (-1) des Yubikey bereits eine Konfiguration, welche nicht überschrieben werden soll, kann mittels -2 stattdessen in Slot 2 geschrieben werden. Mit dem Aufruf ykpersonalize -x werden die Inhalte von Slot 1 und Slot 2 eines YubiKey getauscht.

Leider verwendet das Tool ykpersonalize andere Begriffe für die Bestandteile eines Credentials: so wird aus der Public ID der fixed part und aus der Private UID wird die uid. Folgender Aufruf schreibt die obigen Credentials in den Slot 1 eines eingesteckten YubiKeys.

$ ykpersonalize -1 -o fixed=credtivccccf -o uid=47072c411963 -a 1feff43b2d2b529c697d9db0849c9594
Firmware version 5.1.2 Touch level 1287 Program sequence 3

Configuration data to be written to key configuration 1:

fixed: m:credtivccccf
uid: 47072c411963
key: h:1feff43b2d2b529c697d9db0849c9594
acc_code: h:000000000000
ticket_flags: APPEND_CR
config_flags:
extended_flags:

Commit? (y/n) [n]:

Hierbei ist zu beachten, dass fixed part und uid als KV-Paar mittels -o übergeben werden, während der AES-Schlüssel direkt mittels -a übergeben wird.

Bei positiver Antwort auf die Abfrage Commit? wird die angezeigte Konfiguration auf den Yubikey geschrieben und dieser gibt von nun an bei Knopfdruck ein mit den neuen Credentials erstelltes Yubico OTP aus.

Möchte man mehrere YubiKeys programmieren, werden in weiteren Aufrufen von ykpersonalize einfach entsprechend das jeweils nächste der erzeugten Credentials benutzt. Alle verwendeten Befehle und Tools verwenden Dateien im CSV-Format oder benutzen stdin/stdout; wiederkehrende Abläufe lassen sich somit hervorragend durch ein Bash-Script oder ähnliches automatisieren.

Alternativ zu der hier beschriebenen Herangehensweise bietet das YubiKey Personalization Tool aus dem Paket yubikey-personalization-gui die Möglichkeit gleich mehrere YubiKeys hintereinander zu programmieren. Hierfür aktiviert man in der GUI unter Yubico OTP → Advanced die Option Program Multiple YubiKeys. Um die Credentials der so programmierten YubiKeys im KSM abzulegen, muss die nach der Programmierung zum Speichern angebotene Logdatei configuration_log_hmac.csv zunächst angepasst werden, bevor die darin enthaltenen Credentials mit dem Programm yhsm-import-keys in das KSM importiert werden können.

Laut Manpage erwartet yhsm-import-keys eine CSV-Datei mit folgendem Aufbau:

# ykksm 1
seqno, public id, private uid, AES key,,,,
…

Die Logdatei des YubiKey Personalization Tool enthält die Felder public id, private uid und AES key bereits in der richtigen Reihenfolge als Felder 4-6. Das folgende awk-Script log2ksm.awk extrahiert diese Felder aus der Datei, setzt ihre Zeilennummer als sequence number davor und gibt die Einträge nach dem obligatorischen Header # ykksm 1 Zeile für Zeile aus:

#!/usr/bin/awk -f

BEGIN {
    FS=","
    printf("# ykksm 1\n")
}

/^Yubico OTP/ {
    printf("%d,%s,%s,%s,,,,\n", NR, $4, $5, $6)
}

Der Aufruf, um die Datei configuration_log_hmac.csv umzuwandeln und das Ergebnis als yubikey_secrets.csv zu speichern lautet:

$ ./log2ksm.awk configuration_log_hmac.csv > yubikey_secrets.csv

Die erzeugte Datei kann dann auf den Rechner, auf der das KSM läuft, kopiert und deren Einträge mit folgendem Befehl in dieses importiert werden:

# yhsm-import-keys -D /etc/yubico/yhsm/keys.json --key-handle 1 < yubikey_secrets.csv
output dir              : /var/cache/yubikey-ksm/aeads
key handles             : {1: '1'}
YHSM device             : /etc/yubico/yhsm/keys.json


Done

Auch hier zeigt Done, dass die Credentials erfolgreich importiert wurden.

PAM

Damit PAM während der Authentisierung empfangene Public IDs auf Benutzerkonten abbilden (mappen) kann, muss noch das oben konfigurierte authfile unter /etc/yubikey_mappings angelegt werden. Dieses enthält pro Zeile einen Benutzernamen und dessen zugeteilte YubiKey IDs, getrennt durch Doppelpunkte. Soll der soeben erstellte YubiKey mit der Public ID credtivccccf vom Benutzer bob verwendet werden, muss das authfile folgende Zeile enthalten:

bob:credtivccccf

Mappings für weitere Benutzerkonten werden entsprechend in eigenen Zeilen konfiguriert.

Alternativ zum Einsatz eines authfile können die Mappings auch mithilfe eines LDAP-Verzeichnisdienstes vorgenommen werden. Dieser Variante wird sich ein separater Artikel widmen.

Demo

Wurden bis hierhin alle Schritte erfolgreich durchgeführt, fragt der OpenVPN-Client beim Verbindungsaufbau nach Benutzernamen und Passwort beziehungsweise dem OTP. Während der Benutzername nach wie vor von Hand eingegeben werden muss, reicht zur Eingabe des OTP ein Knopfdruck auf dem YubiKey, sodass die Verbindung hergestellt werden kann. Statt der einzelnen Zeichen des OTP werden auch hier diesmal lediglich Sterne angezeigt.

# openvpn client.conf
...
Enter Auth Username: bob
Enter Auth Password: ********************************************
...

Fazit

Die Installation und der Betrieb eines eigenen Validierungsdienstes und Key Storage Moduls ist recht komplex und mit einigem Aufwand verbunden. Die Interaktion der Komponenten untereinander ist schwer nachzuverfolgen (was die Fehlersuche erschwert), die verfügbaren Tools sind teils wenig intuitiv oder gar inkonsistent (was das Verständnis erschwert).

Wer den Aufwand jedoch nicht scheut und bereit ist sich tiefer mit der Thematik auseinanderzusetzen kann letztlich den vollen Komfort von Yubico OTP genießen und dabei trotzdem die Kontrolle über alle Komponenten behalten.

Unterstützung

Falls Sie Unterstützung bei der Konfiguration oder dem Einsatz von Zwei-Faktor-Authentisierung wünschen, steht Ihnen unser Open Source Support Center gerne zur Verfügung – falls gewünscht auch 24 Stunden am Tag, an 365 Tagen im Jahr.

Kategorien: HowTos
Tags: 2FA Debian OpenSSH OpenVPN OTP Yubico OTP Yubikey

über den Autor

Jan Bolle

zur Person

Jan arbeitet seit 2020 als Werkstudent an Projekten des Support–Teams und der Internen IT, nachdem er bereits sein Praktikum im Rahmen seines Informatikstudiums bei credativ absolvierte und auch seine Bachelorarbeit zum Thema Einmalpasswörter, Zwei–Faktor–Authentisierung und OpenVPN bei credativ schrieb. Bereits zu Schulzeiten interessierte er sich für Freie Software, Netzwerke und Telekommunikation und richtete zusammen mit Mitschülern ein Internetcafé ein, auf dessen Server und Clients Debian GNU/Linux seinen Dienst verrichtete.

Beiträge ansehen


Beitrag teilen: