In den bisherigen Artikeln zu Yubico OTP haben wir Benutzerkonten und YubiKeys über ein sogenanntes authfile aufeinander abgebildet (Mapping). Dies ist beim Einsatz auf wenigen Systemen oder bei nur wenigen YubiKeys sicherlich ausreichend, stellt sich bei größeren Installationen jedoch schnell als zu wartungsintensiv heraus.
Das Yubico OTP PAM-Modul bietet daher die Möglichkeit die Public ID eines YubiKey als Attribut eines Benutzerobjektes in einem bei großen Installationen vermutlich ohnehin vorhandenen LDAP-Verzeichnisserver abzulegen und zum Mapping heranzuziehen.
Dieser Artikel zeigt als kleiner Exkurs anhand von OpenLDAP, wie ein solches LDAP-gestütztes Mapping eingerichtet werden kann. Ob dabei die YubiCloud oder ein selbst gehosteter Validierungs-Service zum Einsatz kommt spielt keine Rolle: beide Setups können um eine LDAP-Anbindung erweitert werden.
Download
Die für die Einrichtung benötigten Schema-Dateien werden wider Erwarten nicht zusammen mit dem Yubico PAM-Modul ausgeliefert. Yubico selbst verweist dazu auf das von Michael Ludvig entwickelte und auf Github zur Verfügung gestellte Projekt yubikey-ldap, welches Schema-Dateien für verschiedene LDAP-Server enthält.
Neben den Schema-Dateien enthält das Projekt außerdem das namensgebende Python-Script yubikey-ldap
, mit dem Benutzerobjekten eine YubiKey ID hinzugefügt oder wieder von diesen entfernt werden kann. Das Script erlaubt außerdem die Auflistung aller Benutzer, denen eine YubiKey ID zugewiesen wurde. Das Script ist noch in Python 2 geschrieben und benötigt das Modul ldap
, welches unter Debian mit dem Paket python-ldap
nachinstalliert werden kann.
Ob das Projekt mit git
geklont oder als ZIP-Archiv heruntergeladen und entpackt wird spielt letztlich keine Rolle. Hauptsache, die Dateien des Projekts befinden sich letzten Endes auf dem Rechner:
$ git clone https://github.com/mludvig/yubikey-ldap.git $ wget https://github.com/mludvig/yubikey-ldap/archive/refs/heads/master.zip $ unzip master.zip
Installation
Die Dateien, welche für die Schema-Installation bei OpenLDAP benötigt werden, befinden sich im Unterordner ldap-schema
. Die eigentliche Installationsschritt unterscheidet sich darin, ob die OpenLDAP-Installation bereits OLC (auch bekannt als cn=config) unterstützt.
Wird bereits OLC eingesetzt muss lediglich per ldapadd
die Datei yubikey.ldif
dem Verzeichnis hinzugefügt werden:
$ ldapadd -W -x -D cn=admin,dc=example,dc=org -f yubikey.ldif adding new entry "cn=yubikey,cn=schema,cn=config"
Natürlich muss dem Argument -D
der RootDN der lokalen Installation übergeben werden. Mit der Meldung adding new entry… ist die Installation bereits abgeschlossen und im Verzeichnis /etc/ldap/slapd.d/cn=config/cn=schema/
sollte sich nun eine Datei mit der Endung yubikey.ldif befinden.
Wird stattdessen die veraltete slapd.conf
-Methode eingesetzt, muss die Datei yubikey.schema
in den Ordner /etc/ldap/schema/
kopiert und der Konfigurationsdatei slapd.conf
die folgende Zeile hinzugefügt werden:
include /etc/ldap/schema/yubikey.schema
Nach einem Neustart des OpenLDAP-Servers steht das Schema dann zur Verfügung.
Konfiguration
Die im Folgenden beschriebene Konfiguration geht von einer bereits erfolgreichen Einrichtung basierend auf den vorangegangen Artikeln zum Thema 2FA und Yubico OTP aus. Dabei spielt es keine Rolle, ob das Setup zur Verifikation die YubiCloud nutzt oder die benötigten Dienste selbst gehostet werden.
PAM
Bei der Konfiguration des PAM-Moduls zur Benutzung eines LDAP-Verzeichnisdienstes entfällt naturgemäß der Parameter authfile
, da dieses durch die LDAP-Anbindung ersetzt wird. Stattdessen kommen nun mehrere LDAP-Spezifische Parameter hinzu, welche gemäß der bestehenden LDAP-Installation angepasst werden müssen. Die im folgenden Listing benutzten Backslashes (\
) dienen wie üblich dazu, die Parameter auf mehrere Zeilen verteilen zu können. Sie stehen stets als letztes Zeichen auf einer Zeile und müssen entfernt werden, wenn alle Parameter in einer Zeile geschrieben werden.
auth sufficient pam_yubico.so id=xxxxx key=xxxxxxxxxxxxxxxx urllist=http://localhost/wsapi/2.0/verify \ ldap_uri=ldap://localhost ldapdn=ou=people,dc=example,dc=org ldap_bind_as_user ldap_cacertfile=/etc/ssl/ca.crt \ ldap_filter=uid=%u user_attr=uid yubi_attr=yubiKeyId account required pam_permit.so
Der Parameter ldap_uri
gibt die für den Verbindungsaufbau zum LDAP-Server verwendete URI an, ldap_certificate
das bei der TLS-Aushandlung verwendete CA-Zertifikat. Bei der Suche nach Benutzerobjekten sucht das Modul unterhalb von dem in ldapdn
angegebenen Knoten nach Objekten, welche das in user_attr
angegebene Attribut besitzen und schaut dort in dem gegebenenfalls vorhandenen mit yubi_attr
angegebenen Attribut nach der ID des YubiKey.
LDAP
Um einem LDAP-Benutzer nun eine YubiKey ID zuweisen zu können, wird schlicht die Liste der objectClass
-Attribute des Benutzerobjekts um die Klasse yubiKeyUser
erweitert und ein neues Attribut yubiKeyId
hinzugefügt, welches als Wert die Public ID des YubiKey erhält.
dn: uid=user,ou=people,dc=example,dc=org objectClass: inetOrgPerson objectClass: posixAccount objectClass: yubiKeyUser objectClass: top cn: user sn: user gidNumber: 4711 homeDirectory: /home/user uid: user uidNumber: 4711 loginShell: /bin/bash userPassword: user yubiKeyId: credtivccccc
Dies kann mit jedem beliebigen Tool erledigt werden, welches das Bearbeiten von LDAP-Objekten erlaubt: sei es low-level mit ldapmodify
oder ldapvi
, etwas bequemer mit dem oben erwähnten yubikey-ldap
oder gar grafisch mit dem JXplorer und dem Apache Directory Studio.
Fazit
Mit der Erweiterung der Benutzerobjekte ist die Einrichtung der LDAP-Anbindung abgeschlossen. Clientseitig ändert sich weder aus Benutzer- noch aus Admin-Sicht etwas. Statt des authfile wird nun das LDAP-Verzeichnis zum Mapping herangezogen.
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.
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.
Zeitbasierte Einmalpasswörter, sogenannte TOTP, finden mittlerweile eine weite Verbreitung. In früheren Artikeln haben wir bereits beschrieben, wie diese zur Absicherung von PAM-fähigen Diensten eingesetzt und bequem verteilt werden können.
Durch den Einsatz von Passwort-Managern oder Generator-Apps können jederzeit problemlos aktuelle TOTP erstellt werden. Diese werden dann per Copy & Paste oder von Hand beim Login eingegeben.
Die hierfür verwendeten Shared Secrets werden von der Anwendung in einem besonders abgesicherten Speicherbereich abgelegt, in dem diese vor dem Zugriff anderer Anwendungen geschützt sein sollen. Die meisten Anwendungen bieten ihren Benutzern jedoch die Möglichkeit den Speicherbereich auch im Nachhinein auszulesen – ein unbefugter Benutzer könnte so unbemerkt das Shared Secret erlangen.
Abhilfe versprechen USB-Sticks wie Nitrokeys oder Yubikeys als sicherer Ablageort für TOTP Secrets. Einmal auf dem Stick abgelegte Secrets können nicht mehr ausgelesen, sondern höchstens überschrieben werden. Einzig der in dem Stick befindliche Generator hat lesenden Zugriff auf den Speicherbereich, um ein TOTP erstellen zu können. Das erstellte TOTP wird von einer eigens hierfür vorgesehenen Anwendung über die USB-Schnittstelle angefordert und ausgelesen; per Copy & Paste können diese dann zur Authentisierung verwendet werden.
Yubikeys sind vielen vor allem dadurch bekannt, dass sie erzeugte Token auf Knopfdruck “wie von Geisterhand” in ein Formular eintragen können. Hierzu meldet sich der Yubikey beim Einstecken in einen USB-Port als Tastatur beim Rechner an. Wird der Knopf am Yubikey gedrückt, gibt dieser dann beispielsweise das angeforderte Token selbsttätig an der aktuellen Cursorposition ein.
Da ein Yubikey jedoch nicht über eine eingebaute Echtzeituhr verfügt, können TOTP, welche auf der aktuellen Uhrzeit basieren, nicht auf dem Stick selbst erzeugt und auf diese Art und Weise an das System übertragen werden. Die oben erwähnte Anwendung auf dem Rechner ist für die Erstellung von TOTP also unumgänglich.
Yubico OTP
Neben Speicherplätzen für TOTP-Secrets unterstützen Yubikeys jedoch auch das Verfahren “Yubico OTP”, eine offen dokumentierte Eigenentwicklung von Yubico, welche durch die Verwendung von Zeitstempeln und Zählern mit einem zeitbasierten Verfahren wie TOTP vergleichbar ist. Die Token können direkt auf dem Stick erzeugt und per Knopfdruck als Tastatureingabe an den Computer übertragen werden.
Im Gegensatz zu TOTP erfolgt die Überprüfung von Yubico OTP Token jedoch nicht direkt auf dem Rechner, an dem der Login stattfindet, sondern über einen Validation Service. Dieser Dienst wird von Yubico in seiner YubiCloud nach einmaliger Registrierung kostenfrei zur Verfügung gestellt, kann aber auch on premise selbst betrieben werden.
Auch bei Yubico OTP muss beiden Seiten ein Shared Secret bekannt sein. Der Validierungsdienst überprüft, ob die übermittelten Daten mit dem zur Seriennummer des Yubikey gehörigen Secret verschlüsselt wurden und diese Daten gültig sind.
Yubikeys sind bei der Auslieferung bereits mit einem der Yubico Cloud bekannten Shared Secret konfiguriert, sodass Admins, welche Yubicos cloudbasierte Validierung verwenden, lokal lediglich einem Benutzerkonto die Seriennummer des Yubikey zuweisen müssen.
Vorarbeiten
Wie für TOTP existiert auch für den Einsatz von Yubico OTP ein PAM-Modul, welches in den offiziellen Paketquellen vorhanden ist. Vor dem Einrichtung müssen jedoch noch einige Vorbereitungen getroffen werden.
Yubikey ID
Neue Yubikey sind werksseitig so programmiert, dass sie bei Tastendruck ein Yubico OTP ausgeben. Das hierfür verwendete Shared Secret ist Yubico bekannt, sodass Dienste wie YubiCloud die erzeugten OTP verifizieren können.
Ein Yubico OTP ist eine 44 Zeichen lange Zeichenkette, welche aus einem öffentlichen, 12 Zeichen langen Teil – der Yubikey ID, und einem verschlüsselten, 32 Zeichen langen Teil besteht. Der genaue Aufbau ist in der Entwicklerdokumentation beschrieben. Interessantes Detail: Durch die Verwendung von Modhex werden für Token nur Zeichen verwendet, welche auf den gängigsten Tastaturbelegungen (QWERTY, QWERTZ, AZERTY) an gleicher Stelle vorhanden sind, sodass die Eingabe unabhängig von der Belegung erfolgen kann.
Mittels der Yubikey ID kann der Yubikey später einem Benutzer zugeordnet werden. Werkseitig besteht diese ID aus der Zeichenkette cccccc
sowie der Seriennummer des Yubikey in Modhex. Die Seriennummer des Yubikey befindet sich auf der Rückseite der Kontakte des USB-Anschlusses, kann aber auch einfach aus einem erzeugten Yubico OTP oder mithilfe der Yubikey Personalization GUI ab- bzw. ausgelesen werden.
Wurde die Konfiguration des Yubikey zwischenzeitlich verändert oder überschrieben, kann mit Hilfe der Yubikey Personalization GUI eine neue Konfiguration erzeugt und das Shared Secret an Yubico übermittelt werden.
Auf der Yubico Demo Website kann überprüft werden, ob eine Validierung der erzeugten OTP mittels der YubiCloud erfolgreich ist.
Registrierung
Um den Validierungs-Service YubiCloud für eigene Dienste nutzen zu können, ist eine vorherige Registrierung notwendig.
Unter https://upgrade.yubico.com/getapikey/ trägt man hierfür seine E-Mail-Adresse ein und bestätigt die Registrierung mit einem Yubikey OTP. Hierfür wird der Yubikey in einen USB-Port gesteckt, sodass dieser bei Knopfdruck das Feld Yubikey OTP ausfüllen kann.
Auf der folgenden Seite erhält man dann seine Client ID sowie den zugehörigen Secret key. Diese werden bei der Einrichtung des PAM-Moduls benötigt.
Einrichtung
Das Yubico PAM-Modul ist in den offiziellen Quellen der gängigen Distributionen enthalten und kann somit bequem aus diesen installiert werden. Unter Debian lautet der Paketname libpam-yubico
.
Leider enthält das aktuelle Paket einen Bug, durch den PAM das Modul nicht finden kann. In der Logdatei /var/log/auth.log
findet sich dann nach einer fehlgeschlagenen Authentisierung dann der folgende Eintrag:
PAM unable to dlopen(pam_yubico.so): /lib/x86_64-linux-gnu/security/pam_yubico.so: cannot open shared object file: No such file or directory
Obwohl PAM das Modul pam_yubico.so
im Ordner /lib/x86_64-linux-gnu/security/
erwartet liegt es tatsächlich im Ordner /lib/security/
. Das Problem kann durch das Anlegen eines symbolischen Links (Symlink) behoben werden:
# ln -s /lib/security/pam_yubico.so /lib/x86_64-linux-gnu/security/pam_yubico.so
PAM
Um das PAM-Modul zur Authentisierung nutzen zu können, müssen die Service-Definitionen der entsprechenden Dienste angepasst werden. Zur Vorgehensweise sei auf den früheren Artikel Zwei-Faktor-Authentisierung für OpenSSH und OpenVPN verwiesen.
Statt des Moduls pam_oath.so
, muss in diesem Fall jedoch das Modul pam_yubico.so
konfiguriert werden:
auth require pam_yubico.so id=00000 key=xxxxxxxxxxxxxxxxxxxxxxxxxxxx authfile=/etc/yubikey_mappings
Für die Parameter id
und key
werden hier die bei der Registrierung erhaltene Client ID respektive der Secret key eingetragen. Der Parameter authfile
verweist auf eine noch zu erstellende Textdatei, welche Yubikey IDs auf Benutzerkonten abbildet.
Mapping
Um Yubikey IDs und Benutzerkonten aufeinander abbilden (mappen) zu können reicht in den meisten Fällen eine einfache Textdatei aus. Diese Datei enthält pro Zeile einen Benutzernamen und beliebig viele Yubikey IDs, getrennt durch Doppelpunkte.
Hat Alice den Yubikey mit der ID ccccccredtiv
erhalten, lautet das entsprechende Mapping:
alice:ccccccredtiv
Diese Datei wird entsprechend der obigen Konfiguration des PAM-Moduls als /etc/yubikey_mappings
gespeichert. Verbindet und authentifiziert sich ein Benutzer mit einem konfigurierten Dienst, validiert pam_yubico
nicht nur das übermittelte OTP, sondern überprüft außerdem die Zugehörigkeit des Yubikeys zum entsprechenden Benutzernamen.
Ein solches Mapping kann bei einer größeren Anzahl von Benutzern auch bequem über ein LDAP-Verzeichnis erfolgen. Die entsprechenden Parameter finden sich in der Dokumentation, benötigte Schemata werden von Michael Ludvig zur Verfügung gestellt.
Betrieb eines eigenen Dienstes
Yubico bieten mit ihren vorprogrammierten Yubikeys und der YubiCloud eine schnelle und einfache Lösung bestehende Dienste um eine Zwei-Faktor-Authentisierung mit Yubico OTP zu erweitern. Wer jedoch nicht von einem externen Dienstleister abhängig sein oder vielleicht aus Datenschutz gründen seine Metadaten für sich behalten möchte, kann seinen eigenen Validierungs-Service betreiben.
Hierzu müssen zwei Dienste, ein Validation Server sowie ein Key Storage Module, eingerichtet werden.
Der Validation Server implementiert die Yubico API zur Validierung von Yubico OTP, welche auch in der YubiCloud zum Einsatz kommt. Das PAM-Modul pam_yubico
kann durch Angabe einer URL so konfiguriert werden, dass es statt der YubiCloud einen anderen Validation Server nutzt.
Das Key Storage Module dient der sicheren Aufbewahrung der Shared Secrets der eingesetzten YubiKeys sowie der Entschlüsselung von OTP für eine Überprüfung durch den Validation Server.
Die Installation und Einrichtung dieser Dienste würden den Rahmen dieses grundlegenden Artikels deutlich sprengen. Dieser Thematik wird sich zeitnah ein gesonderter Artikel annehmen.
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.
Im Artikel Zwei-Faktor-Authentisierung für OpenSSH und OpenVPN wurde ein einfacher Weg vorgestellt, die Sicherheit PAM-fähiger Dienste durch eine Zwei-Faktor-Authentisierung zu erhöhen. Bei dem verwendeten TOTP-Verfahren wird auf Grundlage eines Shared Secret ein zeitlich begrenzt gültiges Einmalpasswort erzeugt.
Je nach Verfahren und Kodierung besteht das Shared Secret aus 32 oder gar 40 Zeichen, die dem Benutzer mitgeteilt werden müssen. Als bequeme und fehlertolerante Lösung haben sich hierzu QR-Codes etabliert, die mit geeigneten Apps eingelesen werden können. Diese QR-Codes enthalten jedoch häufig noch weitere, überflüssige Informationen, die Rückschlüsse auf den Account zulassen.
Dieser Artikel wirft einen Blick auf den Aufbau des Inhalts solcher QR-Codes und wie diese dennoch sicher eingesetzt werden können.
Fallstricke
In seinem Artikel Why you shouldn’t scan two-factor authentication QR codes konstruiert Sam Aiken interessante Szenarien und rät von der unbedachten Nutzung von QR-Codes zur Übermittlung des Shared Secret bei 2FA ab.
Neben dem Shared Secret enthalten die meisten QR-Codes auch Informationen zum Dienstbetreiber, dem Dienst selbst und Benutzernamen. Gelangt ein Angreifer an diese Informationen – sei es durch den QR-Code selbst oder weil die verwendete App ihre Daten ungesichert lokal oder in der Cloud abspeichert oder diese anderweitig verliert – muss er nur noch das Passwort des Accounts herausbekommen, um den Dienst unter falschem Namen nutzen zu können.
Dem Benutzer steht es natürlich frei diese Zusatzinformationen zu löschen oder abzuändern, laut Aiken sei dies jedoch nicht in allen Apps möglich: einige Apps erlaubten keine Veränderungen, andere Apps böten zwar die Möglichkeit Änderungen vorzunehmen, merken sich jedoch die ursprünglich eingelesenen Werte, sodass auch hier unnötig Informationen preisgegeben werden könnten. Aiken bemängelt außerdem, dass viele Dienste lediglich QR-Codes anzeigten, nicht jedoch das Shared Secret als Zeichenfolge, was dem Benutzer selbst die volle Kontrolle über die Daten gäbe, die in eine App eingetragen werden.
Neben dem Einsatz einer in dieser Hinsicht empfehlenswerten App wie andOTP, deren Verwendung Admins zwar beeinflussen, jedoch nicht immer vorschreiben können, wäre es daher wünschenswert, wenn QR-Codes von vornherein ohnehin nur die essentiellen Informationen enthielten.
URI-Schema
Der Inhalt eines solchen QR-Codes entspricht letztendlich einer URI, wie Google sie beispielsweise für seine Authenticator-App auf Github definiert hat:
otpauth://TYPE/LABEL?PARAMETERS
Der Platzhalter TYPE gibt dabei an, ob es sich bei dem verwendeten Verfahren um HOTP oder wie in unserem Fall um TOTP handelt, LABEL soll laut Spezifikation Informationen zum Aussteller und Benutzerkonto enthalten, PARAMETERS kann neben dem erforderlichen secret noch weitere Informationen enthalten.
Parameter | Beschreibung | Default |
---|---|---|
secret | Shared Secret in Base32-Kodierung | – |
counter | Zählerstand bei HOTP | – |
issuer | Herausgeber | – |
algorithm | Verwendeter Hash-Algorithmus | SHA1 |
digits | Länge des erzeugten OTP | 6 |
period | Gültigkeitszeitraum für TOTP | 30 |
Von allen aufgeführten Optionen werden laut Spezifikation für TOTP lediglich TYPE, LABEL und der PARAMETER secret benötigt.
Mit diesen Informationen ist es uns nun möglich eine URI für das im letzten Artikel für die Benutzerin Alice erzeugte Shared Secret zu erstellen. Aus Datensparsamkeit wird hier beim Label lediglich der Dienst angegeben. Sollte Alice weitere Informationen zum Dienst benötigen, so können Ihr diese auch auf anderem Wege mitgeteilt werden.
otpauth://totp/OpenVPN?secret=4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75
Die in dieser URI enthaltenen Informationen erlauben keinen Rückschluss auf den Betreiber, die Adresse oder den verwendeten Benutzernamen des angegebenen Dienstes. Dies sollte für die meisten Anwendungsfälle ausreichend sicher sein.
Versuche mit andOTP ergaben darüber hinaus, dass der Abschnitt LABEL einer URI auch komplett leer gelassen und dennoch problemlos eingelesen werden kann:
otpauth://totp/?secret=4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75
QR-Code erzeugen
Um die soeben erzeugte URI in einen QR-Code umzuwandeln, bietet sich das Kommandozeilentool qrencode an. Die Codes können in eine Bilddatei geschrieben oder aber auch direkt als ASCII-Art auf der Kommandozeile angezeigt werden:
$ qrencode -t ANSI 'otpauth://totp/OpenVPN?secret=4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75'
Streng genommen wird hier durch das Argument -t ANSI
ANSI-Art erzeugt, da bei der Ausgabe sogenannte Rahmenzeichen verwendet werden, die im originalen ASCII-Zeichensatz nicht vorkommen. Obwohl mittels -t ASCII
eine Ausgabe in echtem ASCII-Art erzeugt werden kann, besteht die Grafik lediglich aus #
und Leerzeichen, was deutlich schlechter erkennbar ist und dadurch das Einlesen mit einem Smartphone unnötig erschwert.
Soll stattdessen eine Grafikdatei erzeugt werden, wird mit -t PNG
das Ausgabeformat auf PNG gesetzt und mittels -o qr-alice.png
der Name der Ausgabedatei angegeben:
$ qrencode -t PNG -o qr-alice.png -s 10 'otpauth://totp/OpenVPN?secret=4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75'
Das Argument -s 10
ist hierbei optional und dient einzig dazu die Größe eines Punkts in der Ausgabedatei von drei auf zehn Pixel zu erhöhen:
Eintrag bearbeiten
Sollte Alice weitere Informationen zu ihrem OTP festhalten wollen, kann sie diese nun selbst von Hand in ihrer App eintragen oder anderweitig festhalten. Auch hierbei muss nicht auf Datensparsamkeit verzichtet werden: um beispielsweise zwei VPN-Einträge auseinanderzuhalten reicht es aus, ihnen verschiedene Issuer, beispielsweise Arbeit und Verein zuzuweisen. Im Falle von andOTP verändert sich hierdurch auch das Icon, welches nun den Anfangsbuchstaben des Herausgebers verwendet.
Fazit
Für die Übermittlung der Shared Secrets an Endbenutzer eignen sich QR-Codes nach wie vor am besten. Bevor man jedoch blind die Gepflogenheiten Anderer kopiert, lohnt es sich, einmal hinter die Kulissen der verwendeten Standards zu schauen und zu überlegen, welche Informationen wirklich übertragen werden müssen und Datensparsamkeit zu praktizieren, wenn eigene QR-Codes erstellt werden.
Durch die Verwendung eines flexiblen Kommandozeilentools wie qrencode ließe sich die Erstellung eigener QR-Codes bei einer größeren Anzahl von Benutzern sogar recht einfach automatisieren.
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.