2FA Archives - credativ®

In den vorausgegangenen Artikeln haben wir, um OpenVPN um eine Zwei-Faktor-Authentisierung zu erweitern, stets eine weitere Technologie wie TOTP oder Yubico OTP eingeführt. Diese neuen Technologien erhöhen die Komplexität eines Systems und erfordern von Admins, dass sich diese in die Thematik einarbeiten. Es kann daher durchaus wünschenswert sein auf bereits bestehende Dienste zurückzugreifen.

Moderne Unternehmensnetzwerke, egal ob kabelgebundenes Ethernet oder kabelloses WLAN, erfordern von ihren Clients, dass diese sich beim Verbindungsaufbau authentifizieren. In den meisten Unternehmen kommt hierfür ein RADIUS-Server wie FreeRADIUS zum Einsatz, bei dem Ethernet-Switches oder Wireless-Access-Points die übermittelten Zugangsdaten ihrer Clients überprüfen können, bevor diese ins Netz gelassen werden.

Ist ein solcher RADIUS-Server also ohnehin bereits vorhanden, bietet es sich an, diesen als zweiten Faktor für die Authentisierung von OpenVPN-Verbindungen zu verwenden.

Einrichtung

Das in diesem Artikel beschriebene Setup geht von einem OpenVPN-Server mit der IP-Adresse 192.0.2.10 aus, welcher seine Clients anhand von Zertifikaten authentisiert. Des Weiteren ist ein FreeRADIUS-Server mit der IP-Adresse 192.0.2.11 Teil des Setups. Prinzipiell könnten beide Dienste auch auf dem gleichen System betrieben werden, die Aufteilung auf mehrere Rechner ist aber wahrscheinlicher.

Anders als in den vorausgegangenen Artikeln wird der OpenVPN-Server diesmal nicht über PAM, sondern über ein eigenes Plugin direkt an den RADIUS-Server angebunden – ein weiterer Punkt, der die Komplexität dieses Setups verringert.

RADIUS

Damit der OpenVPN-Server überhaupt mit dem RADIUS-Server sprechen darf, muss zunächst auf dem RADIUS-Server ein weiterer Client in der Konfiguration angelegt werden. Dies geschieht, indem der Datei /etc/freeradius/3.0/clients.conf ein weiterer client–Abschnitt hinzugefügt wird:

client OpenVPN {
        ipaddr          = 192.0.2.10
        secret          = shei5Rahs0ik
}

Der neue client erhält den Identifier OpenVPN. Die Option ipaddr enthält die IP-Adresse, von der aus sich der OpenVPN-Server mit dem RADIUS-Server verbindet, secret das Passwort, mit dem dieser sich authentifiziert.

Mit einem Reload des RADIUS-Dienstes wird die neue Konfiguration übernommen und seine Einrichtung ist abgeschlossen.

systemctl reload freeradius

OpenVPN

Im Gegensatz zu den vorausgegangenen Artikeln übergibt OpenVPN bei diesem Setup die Credentials nicht dem lokalen PAM, welches diese dann vom entsprechenden Dienst überprüfen ließe, sondern übergibt diese über ein Plugin selbst an den RADIUS-Server.

Manche Linux-Distributionen installieren das Plugin zusammen mit OpenVPN, unter Debian GNU/Linux muss das Paket openvpn-auth-radius jedoch separat installiert werden:

apt install openvpn-auth-radius

Damit OpenVPN das Plugin verwendet, wird der Konfigurationsdatei die Zeile

plugin /usr/lib/openvpn/radiusplugin.so /etc/openvpn/radiusplugin.cnf

hinzugefügt. Diese lädt das Plugin radiusplugin.so im Verzeichnis /usr/lib/openvpn mit der Konfigurationsdatei /etc/openvpn/radiusplugin.cnf.

Da die Konfigurationsdatei nicht existiert, muss diese noch angelegt werden:

NAS-Identifier=OpenVPN
NAS-IP-Address=192.0.2.10

OpenVPNConfig=/etc/openvpn/server.conf

server
{
        name=192.0.2.11
        authport=1812
        acctport=1813
        sharedsecret=shei5Rahs0ik
}

Die Optionen NAS-Identifier und NAS-IP-Address werden auf die beim Anlegen des Clients auf dem RADIUS-Server gewählten Werte gesetzt, hier also OpenVPN und 192.0.2.10. In der Sektion server wird unter name die IP-Adresse des RADIUS-Servers eingetragen, unter sharedsecret, das beim Anlegen des Clients gewählte secret, hier also shei5Rahs0ik. Unter OpenVPNConfig wird die Konfigurationsdatei des OpenVPN-Servers samt Pfad angegeben. Das Plugin durchsucht diese nach dort gesetzten Optionen und verhält sich diesen entsprechend.

Für ein einfaches Setup wie dieses reichen also schon wenige Konfigurationsoptionen aus. Eine voll kommentierte Beispielkonfiguration befindet sich im Verzeichnis /usr/share/doc/openvpn-auth-radius/examples/ in der Datei radiusplugin.cnf.

Mit einem Neustart des OpenVPN-Services ist auch dessen Konfiguration abgeschlossen.

systemctl restart openvpn

Client

Auch beim Einsatz von RADIUS auf der Serverseite ist der Konfigurationsaufwand auf der Seite des Clients minimal: hier muss der Konfiguration lediglich wieder die Direktive auth-user-pass hinzugefügt werden, sodass der Benutzer beim Verbindungsaufbau nach Benutzername und Passwort gefragt wird – den gleichen Credentials, die er auch für andere Netze des Unternehmens benötigt.

Fazit

Die Kürze dieses Artikels zeigt es bereits: um OpenVPN mit einer Zwei-Faktor-Authentisierung abzusichern bedarf es weder der Einführung neuer Technologien noch aufwändiger Konfiguration. Oft sind geeignete Dienste wie RADIUS bereits im Einsatz und müssen nur noch eingebunden werden.

Zwar handelt es sich bei den über RADIUS abgefragten Credentials in der Regel um Benutzernamen sowie statische Passwörter und nicht um zeitabhängig generierte Einmalpasswörter, ein Sicherheitsgewinn allein durch die Nutzung eines zweiten Faktors ist dennoch nicht von der Hand zu weisen.

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.

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
Eintrag ohne Label in andOTP

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:

Die erzeugte Datei qr-alice.png

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.

Eintrag nach Scan in andOTP
Bearbeiten des Eintrags
Eintrag nach Bearbeitung in andOTP

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.

Die Anmeldung mittels Benutzernamen und Passwort stellt nach wie vor für die meisten Anwendungen die übliche Vorgehensweise dar, um sich an einem Dienst zu authentisieren. Die Nutzung eines zweiten Faktors findet jedoch immer weitere Verbreitung und wird vom BSI, dem Bundesamt für Sicherheit in der Informationstechnik, sogar empfohlen. Wenn auch nicht vorgeschrieben, so bieten verschiedene Webdienste immerhin die Option, Zwei-Faktor-Authentisierung (2FA) für ein Benutzerkonto zu aktivieren.

Doch nicht nur die Sicherheit von Webdiensten kann mittels 2FA erhöht werden, auch klassische Dienste wie SSH erlauben die Nutzung eines zweiten Faktors neben den üblichen Authentisierungsmethoden wie Passwörtern oder Zertifikaten.

Verfahren

Das am weitesten verbreitete Verfahren für Einmalpasswörter als zweiten Faktor stellt vermutlich TOTP, das Time-Based One-Time Password, dar. Das Verfahren ist in RFC6238 standardisiert und ist bisweilen auch unter dem Namen Google Authenticator bekannt.

Bei TOTP wird aus der aktuellen Uhrzeit sowie dem Shared Secret, einem sowohl dem Dienst als auch dem Benutzer bekannten Geheimnis, ein für einen kurzen Zeitraum, einmalig gültiges, numerisches Einmalpasswort (engl. one-time password, OTP) berechnet.

Üblicherweise – und im Falles des Google Authenticator fest vorgegeben – besteht das Passwort aus 6 Ziffern und hat eine Gültigkeitsdauer von 30 Sekunden. Der Standard sieht jedoch auch andere Längen und Zeiträume vor.

Zur Berechnung des OTP existieren neben CLI-Anwendungen wie oathtool auch solche mit GUI wie zum Beispiel KeePassXC oder Smartphone-Apps wie AndOTP.

Einrichtung

PAM (Pluggable Authentication Modules) ist eine Sammlung von Bibliotheken, die es Anwendungen und Diensten erlaubt die Authentifizierung von Benutzern auszulagern, statt diese selbst implementieren zu müssen. Hierzu werden die Nachrichten der Unterhaltung, die zur Authentifizierung zwischen PAM und Benutzer ausgetauscht werden, durch die Anwendung hindurch an den jeweiligen Empfänger weitergeleitet.

Während dieser Unterhaltung durchläuft PAM die in der Service-Datei der Anwendung konfigurierten Module, in welchen die jeweiligen Authentifizierungsverfahren implementiert sind. Der Anwendung selbst meldet PAM letztlich nur Erfolg oder Misserfolg der Authentifizierung.

Um unter Linux Einmalpasswörter nutzen zu können bietet sich daher die Nutzung des PAM-Moduls pam_oath an. Alle Dienste, die PAM zur Authentifizierung ihrer Benutzer verwenden, können so einfach um die Funktionalität der Zwei-Faktor-Authentisierung erweitert werden. Dazu gehören neben System-Interna wie login, su oder sudo auch über das Netzwerk erreichbare Dienste wie SSH oder OpenVPN.

Je nach verwendeter Distribution befindet sich das PAM-Modul im Paket libpam-oath (Debian etc.) oder pam_oath (CentOS etc.) und kann aus den offiziellen Quellen installiert werden.

PAM

Um TOTP für SSH einzurichten muss die entsprechende PAM-Service-Datei angepasst werden. Diese befindet sich unter /etc/pam.d/sshd.

Diese Datei ist in etwa 50 Zeilen lang und beschreibt unter anderem, wie bei der Anmeldung eines Benutzers über SSH seine Identität überprüft werden kann und welche Umgebung vor dem Aufruf seiner Login-Shell geschaffen wird.

Die genaue Funktion der einzelnen Einträge würde den Rahmen dieses Artikels sprengen. Interessant für die Einrichtung von TOTP ist lediglich die Zeile

@include common-auth

Diese übernimmt das in der Service-Datei /etc/pam.d/common-auth festgelegte Standardverhalten des Systems: mittels des Moduls pam_unix wird das Kennwort des Benutzers mit dem in /etc/shadow verglichen.

Um die Überprüfung eines OTP mittels pam_oath zu erfordern, wird die folgende Zeile, direkt unter der obigen @include-Anweisung hinzugefügt:

auth required pam_oath.so usersfile=/etc/users.oath digits=6 window=2

Der Parameter usersfile verweist dabei auf eine Datei, in der die Shared Secrets der Benutzer gespeichert sind, digits=6 legt die Länge der OTP auf 6 Ziffern fest.

Mittels window=2 wird das Fenster der erlaubten OTP vergrößert. Neben dem aktuell gültigen OTP gelten bei einer Fenstergröße von 2 auch die Passwörter des vorherigen beziehungsweise nächstes Zeitraums. Während eine Fenstergröße von 0 nur das aktuelle OTP erlaubt, wird mit wachsender Zahl jeweils ein zukünftiges und ein vergangenes Passwort mehr erlaubt. Weitere Parameter finden sich in der Dokumentation des Moduls.

Der Aufbau des Usersfile folgt der *NIX-Tradition: jede Zeile stellt einen Eintrag dar, welcher mehrere Felder enthält, die durch ein oder mehrere Leerzeichen getrennt werden. Während ein Eintrag bis zu neun Felder enthalten kann, spielen bei der Einrichtung eines neuen Benutzers nur die ersten vier eine Rolle. Sie beinhalten, der Reihe nach: das verwendete Verfahren, den Benutzernamen, eine optionale PIN sowie im letzten Feld das Shared Secret.

Als Shared Secret empfiehlt das RFC eine 160 Bit (also 20 Byte) große Zufallszahl. Diese kann leicht mit Hilfe des Programms openssl erstellt werden:

$ openssl rand -hex 20

Als Ausgabe erhält man die 40 Zeichen lange, Base16-kodierte Repräsentation der zufällig erzeugten Zeichenkette, beispielsweise e2e36e1f3010bba83fed4118244f85be1cbb23fd.

Um einen Eintrag für den Benutzer alice und dem Verfahren TOTP mit einem Gültigkeitsbereich von 30 Sekunden an das Usersfile anzuhängen kann einfach folgende Befehlszeile benutzt werden. Der in $() enthaltene Aufruf von openssl wird dabei durch seine Ausgabe, dem 20 Byte langen Shared Secret ersetzt.

$ echo "HOTP/T30 alice - $(openssl rand -hex 20)" | tee -a /etc/users.oath

Das Programm tee gibt den erzeugten Eintrag samt Shared Secret einerseits auf der Kommandozeile aus und hängt ihn außerdem als weitere Zeile an das Usersfile /etc/users.oath an:

$ echo "HOTP/T30 alice - $(openssl rand -hex 20)" | tee -a /etc/users.oath
HOTP/T30 alice - e2e36e1f3010bba83fed4118244f85be1cbb23fd

SSH

Ein in der Standardkonfiguration eingerichtetes OpenSSH authentisiert Benutzer mittels der eingebauten PasswordAuthentication. Um PAM verwenden zu können muss diese ausgeschaltet und stattdessen die ChallengeResponseAuthentication eingeschaltet werden. Die Authentisierung über PAM wird dann über den Parameter UsePAM aktiviert.

Die Konfigurationsdatei /etc/ssh/sshd_config muss also die folgenden Zeilen enthalten:

PasswordAuthentication no
ChallengeResponseAuthentication yes
UsePAM yes

Demo

Durch die Veränderungen an der Konfiguration von OpenSSH hat sich der Prompt, welcher beim Verbindungsaufbau zur Eingabe des Passworts auffordert verändert.

Die in OpenSSH eingebaute PasswordAuthentication zeigte im Prompt den für die Verbindung verwendeten Benutzer- sowie Hostnamen an.

alice@local$ ssh alice@192.0.2.1
alice@192.0.2.1's password:
alice@remote$

Nach der Umstellung auf PAM unter Verwendung der ChallengeResponseAuthentication wird hingegen die Eingabeaufforderung des jeweiligen PAM-Moduls angezeigt: zuerst pam_unix, dann pam_oath.

alice@local$ ssh alice@192.0.2.1
Password:
One-time password (OATH) for `alice':
alice@remote$

OpenVPN

OpenVPN authentifiziert Benutzer klassischerweise über Zertifikate, die von einer vertrauenswürdigen, nicht selten lokalen, CA beglaubigt wurden. Im Laufe des Verbindungsaufbaus ist es jedoch außerdem möglich einen Benutzernamen sowie das dazugehörige Passwort clientseitig abzufragen und serverseitig zu überprüfen.

Um einer bestehenden OpenVPN-Installation eine 2FA hinzuzufügen, bedarf es nur weniger Änderungen an den Konfigurationsdateien.

Damit der OpenVPN die Authentifizierung des Benutzernamens und des Passworts an PAM übergeben kann, wird das in der Standardinstallation mitgelieferte PAM-Plugin in der OpenVPN-Konfiguration des Servers eingetragen:

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

Der Parameter openvpn entspricht dabei dem Namen der PAM-Service-Datei in /etc/pam.d/, welche noch neu angelegt werden muss:

auth required pam_oath.so usersfile=/etc/users.oath digits=6 window=2
@include common-account

Befinden sich auf dem Rechner, auf dem der OpenVPN-Dienst läuft, keine Benutzeraccounts, kann deren Existenzüberprüfung mit einer abgewandelten Service-Datei übersprungen werden:

auth required pam_oath.so usersfile=/etc/users.oath digits=6 window=2
account required pam_permit.so

Das Modul pam_permit liefert stets Erfolg zurück. Da es das einzige angegebene Modul des Typs auth ist, wird nur sein Ergebnis ausgewertet.

Clientseitig muss der Konfiguration lediglich folgende Zeile hinzugefügt werden, damit der Benutzer während des Verbindungsaufbau nach seinem Benutzernamen und (Einmal-)Passwort gefragt wird:

auth-user-pass

Wird die Verbindung clientseitig über eine GUI wie den NetworkManager konfiguriert, ist unter Verbindungsart statt der üblichen Einstellung Zertifikate (TLS) der Eintrag Passwort mit Zertifikaten (TLS) auszuwählen. Unter Benutzername ist der zu verwendende Benutzername einzugeben, das Feld Passwort bleibt jedoch frei, dort muss die Option Jedes Mal nach diesem Passwort fragen gewählt werden.

Demo

Nach Anpassung der Konfiguration auf dem Client wird der Benutzer während der TLS-Verhandlungen des Verbindungsaufbaus direkt nach Überprüfung der Zertifikate aufgefordert einen Benutzernamen und das zugehörige OTP einzugeben.

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

Auch bei Verwendung des NetworkManagers wird der Benutzer beim Verbindungsaufbau nach dem aktuellen Einmalpasswort gefragt.

IMG Abfrage des OTP bei Verbindungsaufbau
Abfrage des OTP bei Verbindungsaufbau

OTP berechnen

Das Shared Secret, oder auch gemeinsame Geheimnis, muss – wie der Name sagt – beiden Seiten bekannt sein. Auf der Serverseite befindet es sich im Usersfile, auf Clientseite gibt es für den Benutzer verschiedene Wege das Shared Secret aufzubewahren, um damit ein OTP zu berechnen.

Das zur Berechnung benötigte Shared Secret wurde mit dem oben aufgeführten openssl-Aufruf erzeugt und in Hexadezimal-Darstellung bzw. Base16-kodiert ausgegeben. Neben Base16 ist auch die Darstellung in Base32 verbreitet, es muss also darauf geachtet werden, welche Kodierung ein Programm bei der Eingabe des Shared Secrets erwartet. Beide genannten Verfahren sind in RFC 4648 beschrieben und standardisiert.

Während sich für Base32 und Base64 bereits die Tools base32 respektive base64 im Paket coreutils befinden, muss für die Umwandlung von Base16 ein weiteres Tool, beispielsweise basez installiert werden. Neben der Hauptanwendung basez werden hierbei auch einige symbolische Links hierauf eingerichtet, darunter base16, welches sich wie base32 und base64 bedienen lässt.

Um das oben erzeugte Shared Secret für alice von Base16 in Base32 umzuwandeln reicht der folgende Aufruf. Die Option -d beim Aufruf von base16 steht dabei für decode, da die Umwandlung aus Base16 heraus erfolgt.

$ echo e2e36e1f3010bba83fed4118244f85be1cbb23fd | base16 -d | base32
4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75

In Base32-Kodierung lautet das Shared Secret also 4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75.

Wie zu erwarten finden sich auch online etliche webbasierte Tools zur Umwandlung zwischen den verschiedenen Kodierungen. Die Übermittlung an Webseiten ist jedoch nicht zu empfehlen: auch ein geteiltes Geheimnis ist ein Geheimnis und sollte nicht an Dritte weitergegeben werden!

Ähnlich verhält es sich bei der Verwendung von QR-Codes, der sich ein gesonderter Artikel widmen wird. Obwohl weit verbreitet ist ihre Benutzung nicht ohne Risiken, die vorher analysiert und minimiert werden sollten.

CLI

Das Programm oathtool ermöglicht die Berechnung von OTP auf der Kommandozeile. Um TOTP zu berechnen wird ihm beim Aufruf das Argument --totp sowie das Shared Secret in Base16-Kodierung übergeben:

$ oathtool --totp e2e36e1f3010bba83fed4118244f85be1cbb23fd

oathtool geht dabei von einer OTP-Länge von 6 Ziffern und einem Fenster von 0 aus. Diese Annahmen können mit den Argumenten -d (Digits) sowie -w (Window) angepasst werden.

Liegt das Shared Secret Base32-kodiert vor, muss ihm das Argument -b vorangestellt werden:

$ oathtool --totp -b 4LRW4HZQCC52QP7NIEMCIT4FXYOLWI75

GUI

Neben der sicheren Speicherung von statischen Passwörtern bietet KeepassXC auch die Möglichkeit Einmalpasswörter nach TOTP zu generieren. Hierzu wird das Shared Secret als Attribut eines Eintrags gespeichert.

Einem bestehenden Eintrag kann mittels Rechtsklick über Zeitbasiertes Einmal-Passwort (TOTP) > TOTP einrichten… das Shared Secret als Schlüssel hinzugefügt werden. RFC 6238-Token-Standardeinstellungen geht dabei von Länge von 6 Ziffern und einer Gültigkeit von 30 Sekunden aus. Als Schlüssel wird das Base16-Kodierte Shared Secret erwartet.

Aufruf: TOTP einrichten
Aufruf: TOTP einrichten
Dialog: TOTP einrichten
Dialog: TOTP einrichten

Mittels Rechtsklick auf den Eintrag kann das aktuelle Einmalpasswort über Zeitbasiertes Einmal-Passwort (TOTP) > TOTP anzeigen angezeigt, beziehungsweise über TOTP kopieren in die Zwischenablage kopiert werden.

Aufruf: TOTP anzeigen
Aufruf: TOTP anzeigen
Dialog: TOTP anzeigen
Dialog: TOTP anzeigen

Smartphone-App

Um ein TOTP auf dem Smartphone berechnen zu lassen bietet sich andOTP an. Die App ist Freie Software, steht unter der MIT-Lizenz und kann einfach über F-Droid oder aus dem Google Play Store installiert werden.

Über den Plus-Button in der unteren rechten Bildschirmecke kann ein neuer Eintrag angelegt werden. Neben der Möglichkeit einen QR-Code einzuscannen, kann über den Menüpunkt Details eingeben neben einigen Einstellungen wie Zeitraum, Länge oder Hash-Algorithmus das Shared Secret von Hand eingegeben werden.

Eingabe der Details in andOTP
Eingabe der Details in andOTP
Anzeige des aktuellen TOTP in andOTP
Anzeige des aktuellen TOTP in andOTP

Der Möglichkeit, das Shared Secret und Einstellungen zur Berechnung eines TOTP mittels eines QR-Codes einzulesen, widmet sich ein kommender Artikel.

Fazit

Die aufgeführten Beispiele zeigen wie einfach es ist auch bereits bestehende Dienste, um eine Zwei-Faktor-Authentisierung mit TOTP zu erweitern. Es muss lediglich in der entsprechenden Service-Datei die Anbindung an PAM und die Verwendung des Moduls pam_oath konfiguriert werden.

Das gezeigte Vorgehen eignet sich vornehmlich für einzelne Systeme mit einigen wenigen abzusichernden Benutzerkonten. Komplexere Installationen und andere Verfahren für Einmalpasswörter sind auch möglich.

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.