Nächste Überarbeitung | Vorhergehende Überarbeitung |
linux:ssh:tofu_und_cert [30.11.2023 09:14. ] – angelegt django | linux:ssh:tofu_und_cert [28.04.2025 09:20. ] (aktuell) – Haeder angepasst django |
---|
====== TOFU - Trust On First Use - SSH Zertifikate ====== | ====== TOFU - Trust On First Use - SSH Zertifikate ====== |
===== Ausgangssituation ===== | ===== Ausgangssituation ===== |
O.K.,worum geht es hier eigentlich? | O.K., worum geht es hier eigentlich? |
| |
Verbinden wir uns das erste mal mit einem neuen System, sehen wir in aller Regel erst einmal sowas in der Art: | Verbinden wir uns das erste mal mit einem neuen System, sehen wir in aller Regel erst einmal so was in der Art: |
$ ssh -Y vml172042 | $ ssh -Y vml172042 |
<code>The authenticity of host 'vml172042 (172.17.2.42)' can't be established. | <code>The authenticity of host 'vml172042 (172.17.2.42)' can't be established. |
Are you sure you want to continue connecting (yes/no/[fingerprint])?</code> | Are you sure you want to continue connecting (yes/no/[fingerprint])?</code> |
| |
So und nun mal Hand aufs Herz was machen wir hier? Klar wir nun jeder sagen, bzw. was bekommen wir als Antworten wenn wir da mal etwas genauer nachfragen? Mögliche Antworten können nun sein: | So und nun mal Hand aufs Herz was machen wir hier? Klar wird nun jeder sagen, bzw. was bekommen wir als Antworten wenn wir da mal etwas genauer nachfragen? Mögliche Antworten können nun sein: |
<WRAP center round important 80%> | <WRAP center round important 80%> |
- Woot? Mir egal, ich antworte hier mit **''yes''** weil mit **''no''** komme ich nicht weiter und so habe ich Ruhe, die Meldung kommt nicht wieder! Und ganz ehrlich ich weiß nicht was das soll.\\ \\ | - Woot? Mir egal, ich antworte hier mit **''yes''** weil mit **''no''** komme ich nicht weiter und so habe ich Ruhe, die Meldung kommt nicht wieder! Und ganz ehrlich ich weiß nicht was das soll.\\ \\ |
Im obigen Abschnitt **[[#ausgangssituation|Ausgangssituation]]** haben wir schon gesehen, dass beim ersten Verbindungsaufbau uns mitgeteilt wird, dass der erkannte Fingerprint des ssh_host_ed25519_key unbekannt ist und daher dem System erst einmal nicht vertraut wird. Üblich ist nun hier, den Fingerprint zu akzeptieren wenn man sich das erste Mal mit einem Host verbindet. Die präsentierte Warnung wird also einfach als notwendiges Übel abgetan. Und genau hier sind wir nun mittendrin beim Thema **TOFU**! Was sollen, nein was werden wir nun tun? Ganz einfach, wir nehmen diese SSH-Warnung ernst und tun sie nicht ab also lästiges vernachlässigbares Übel! | Im obigen Abschnitt **[[#ausgangssituation|Ausgangssituation]]** haben wir schon gesehen, dass beim ersten Verbindungsaufbau uns mitgeteilt wird, dass der erkannte Fingerprint des ssh_host_ed25519_key unbekannt ist und daher dem System erst einmal nicht vertraut wird. Üblich ist nun hier, den Fingerprint zu akzeptieren wenn man sich das erste Mal mit einem Host verbindet. Die präsentierte Warnung wird also einfach als notwendiges Übel abgetan. Und genau hier sind wir nun mittendrin beim Thema **TOFU**! Was sollen, nein was werden wir nun tun? Ganz einfach, wir nehmen diese SSH-Warnung ernst und tun sie nicht ab also lästiges vernachlässigbares Übel! |
| |
Ja, eine Verbindung ist später dann verschlüsselt dank des SSH-Schlüsselmaterials von Client und Server von dessen Public-Key die jeweiligen Endstellen Kenntnis haben. Tatsache ist aber auch dass SSH die Authentizität des Hosts nicht überprüfen kann und das ist ein ernstes Problem! Verschlüsselte Kommunukation ist sehr gut aber ist sie denn auch vertrauenswürdig, sprich haben wir uns wirklich mit dem Zielsystem verbunden, oder ist da ein kompromittiertes System als **MITM**((**M**an**I**n**T**he**M**iddle)) im Einsatz? Was das bei Passwort gestützten SSH-Verbindungen bedeutet, ist wohl jedem glasklar - ja genau daher kommt bei uns auch auch nur Schlüsselbasierter Zugriff zum Einsatz! | Ja, eine Verbindung ist später dann verschlüsselt dank des SSH-Schlüssel Materials von Client und Server von dessen Public-Key die jeweiligen Endstellen Kenntnis haben. Tatsache ist aber auch dass SSH die Authentizität des Hosts nicht überprüfen kann und das ist ein ernstes Problem! Verschlüsselte Kommunikation ist sehr gut aber ist sie denn auch vertrauenswürdig, sprich haben wir uns wirklich mit dem Zielsystem verbunden, oder ist da ein kompromittiertes System als **MITM**((**M**an**I**n**T**he**M**iddle)) im Einsatz? Was das bei Passwort gestützten SSH-Verbindungen bedeutet, ist wohl jedem glasklar - ja genau daher kommt bei uns auch auch nur Schlüssel basierter Zugriff zum Einsatz! |
| |
Beim ersten Verbindungsaufbau werden wir also nun in unserem Beispiel hier eben darauf hingewiesen, dass wir dem System noch nicht vertrauen und wir das Vertrauen entweder bestätigen oder vielleicht auch auf andere Weise anderweitig herstellen wollen. Doch hierzu später mehr im Abschnitt **[[#loesung_smoeglichkeit|Lösung(smöglichkeit)]]**. | Beim ersten Verbindungsaufbau werden wir also nun in unserem Beispiel hier eben darauf hingewiesen, dass wir dem System noch nicht vertrauen und wir das Vertrauen entweder bestätigen oder vielleicht auch auf andere Weise anderweitig herstellen wollen. Doch hierzu später mehr im Abschnitt **[[#loesung_smoeglichkeit|Lösung(smöglichkeit)]]**. |
| |
Bestätigen wir nun das Vertrauen bei der ersten Verbindungsaufbau/-verwendung (**TOFU**((**T**rust**O**f**F**irst**U**se))) beim Initialen Verbindungsaufbau wir uns in unserer **''~/.ssh/authorized_keys''** ein entsprechender Eintrag hinzugefügt, welcher später dann als Anker dient und wir ohne TOFU-Meldung uns sofort mit den Zielsystem verbinden. Das bedeutet natürlich dass bei entsprechend vielen Zielsystemen entsprechend viele Zeilen dort sich ansammeln und sind dann auch noch wechselnde IP-Adressen im Spiel,das Ganze noch schneller anschwillt. | Bestätigen wir nun das Vertrauen bei der ersten Verbindungsaufbau/-verwendung (**[[https://en.wikipedia.org/wiki/Trust_on_first_use|TOFU]]**((**T**rust**O**f**F**irst**U**se))) beim Initialen Verbindungsaufbau wir uns in unserer **''~/.ssh/authorized_keys''** ein entsprechender Eintrag hinzugefügt, welcher später dann als Anker dient und wir ohne TOFU-Meldung uns sofort mit den Zielsystem verbinden. Das bedeutet natürlich dass bei entsprechend vielen Zielsystemen entsprechend viele Zeilen dort sich ansammeln und sind dann auch noch wechselnde IP-Adressen im Spiel,das Ganze noch schneller anschwillt. |
| |
Ändern sich dann auch noch **''ssh_host_ed25519_key''** von Zielsystemen, da z.B. bei Virtualisierungsumgebungen Virtuelle Maschinen getauscht oder erneuert werden, sind wir wiederum sehr schnell bei TOFU-Meldungen. Nach dem Hinzufügen von Verbindungen sind diese dauerhaft aktiv und die Daten in der **''~/.ssh/authorized_keys''** gepflegt werden. | Ändern sich dann auch noch **''ssh_host_ed25519_key''** von Zielsystemen, da z.B. bei Virtualisierungsumgebungen Virtuelle Maschinen getauscht oder erneuert werden, sind wir wiederum sehr schnell bei TOFU-Meldungen. Nach dem Hinzufügen von Verbindungen sind diese dauerhaft aktiv und die Daten in der **''~/.ssh/authorized_keys''** gepflegt werden. |
Die SSH implementiert das Protokoll zur Authentifizierung mit öffentlichem Schlüssel automatisch, wobei einer der Algorithmen DSA, ECDSA, Ed25519 oder RSA verwendet wird. | Die SSH implementiert das Protokoll zur Authentifizierung mit öffentlichem Schlüssel automatisch, wobei einer der Algorithmen DSA, ECDSA, Ed25519 oder RSA verwendet wird. |
| |
Die Datei **''~/.ssh/authorized_keys''** listet die öffentlichen Schlüssel auf, die für das Einloggen erlaubt sind. Wenn sich der Benutzer anmeldet, teilt das ssh-Programm dem Server mit, welches Schlüsselpaar es für die Authentifizierung verwenden möchte. Der Client weist nach, dass er Zugriff auf den privaten Schlüssel hat, und der Server prüft, ob der entsprechende öffentliche Schlüssel berechtigt ist, das Konto zu akzeptieren. | Die Datei **''~/.ssh/authorized_keys''** listet die öffentlichen Schlüssel auf, die für das Einloggen erlaubt sind. Wenn sich der Benutzer anmeldet, teilt das SSH-Programm dem Server mit, welches Schlüsselpaar es für die Authentifizierung verwenden möchte. Der Client weist nach, dass er Zugriff auf den privaten Schlüssel hat, und der Server prüft, ob der entsprechende öffentliche Schlüssel berechtigt ist, das Konto zu akzeptieren. |
| |
Der Server kann den Client über Fehler informieren, die den Erfolg der Authentifizierung mit dem öffentlichen Schlüssel verhindert haben, nachdem die Authentifizierung mit einer anderen Methode abgeschlossen wurde. Diese können angezeigt werden, indem der LogLevel auf DEBUG oder höher erhöht wird (z. B. durch Verwendung der Option -v). | Der Server kann den Client über Fehler informieren, die den Erfolg der Authentifizierung mit dem öffentlichen Schlüssel verhindert haben, nachdem die Authentifizierung mit einer anderen Methode abgeschlossen wurde. Diese können angezeigt werden, indem der LogLevel auf DEBUG oder höher erhöht wird (z. B. durch Verwendung der Option -v). |
256 SHA256:syMNF0jPr8b7hgqoCLgUZpSZhMulGeoGKFU/FWm3UKY vml172042 (ED25519)</code> | 256 SHA256:syMNF0jPr8b7hgqoCLgUZpSZhMulGeoGKFU/FWm3UKY vml172042 (ED25519)</code> |
| |
O.K., wir haben zwar den Fingerprint des Server-Keys, aber wir haben diesen mit Hilfe des Programms **''ssh-keysan''** ermittelt der ja on-the-fly eine Verbindung zum Zielhost aufbaut und dessen präsentierten Schlüssel auswertet. Wenn das aber nun das kompromittierte MITM-System wäre, würden wir uns ja dessen Fingerprint für später merken. | O.K., wir haben zwar den Fingerprint des Server-Keys, aber wir haben diesen mit Hilfe des Programms **''ssh-keyscan''** ermittelt der ja on-the-fly eine Verbindung zum Zielhost aufbaut und dessen präsentierten Schlüssel auswertet. Wenn das aber nun das kompromittierte MITM-System wäre, würden wir uns ja dessen Fingerprint für später merken. |
| |
<WRAP center round important 80%> | <WRAP center round important 80%> |
| |
==== signierte SSH-Keys - SSH-Zertifikate ====== | ==== signierte SSH-Keys - SSH-Zertifikate ====== |
Die OpenSSH-Implementierung von SSH, bei der Benutzer SSH-Hosts und umgekehrt Hosts SSH-Benutzern vertrauen, unterstützt einen zertifikatsbasierten Mechanismus, der zur Reduktion von Komplexität und Verminderungen von Administrationsaufwänden genutzt werden kann. Anstelle eines Satzes von öffentlichen/privaten Schlüsseln werden signierte Zertifikate verwendet. Dies hat den Vorteil, dass eine einzige vertrauenswürdige Zertifizierungsstelle anstelle vieler öffentlicher/privater Schlüssel verwendet werden kann. | Die OpenSSH-Implementierung von SSH, bei der Benutzer SSH-Hosts und umgekehrt Hosts SSH-Benutzern vertrauen, unterstützt einen Zertifikat basierten Mechanismus, der zur Reduktion von Komplexität und Verminderungen von Administrationsaufwänden genutzt werden kann. Anstelle eines Satzes von öffentlichen/privaten Schlüsseln werden signierte Zertifikate verwendet. Dies hat den Vorteil, dass eine einzige vertrauenswürdige Zertifizierungsstelle anstelle vieler öffentlicher/privater Schlüssel verwendet werden kann. |
| |
Im Abschnitt **AUTHENTICATION** der Manual-Page von **''ssh''** und im Abschnitt **CERTIFICATES** der Manual-Page von **''ssh-keygen''** finden sich, etwas versteckt nicht auf den ersten Blick jedem sofort ersichtlich, hierzu tiefer gehende Erklärungen und Beispiele. | Im Abschnitt **AUTHENTICATION** der Manual-Page von **''ssh''** und im Abschnitt **CERTIFICATES** der Manual-Page von **''ssh-keygen''** finden sich, etwas versteckt nicht auf den ersten Blick jedem sofort ersichtlich, hierzu tiefer gehende Erklärungen und Beispiele. |
* **''-s /etc/ssh/ssh_ca/ssh_ca_host_key''** : CA-Schlüssel (private key) mit dem wir den öffentlichen Schlüssel des Zielhosts signieren und dadurch beglaubigen. | * **''-s /etc/ssh/ssh_ca/ssh_ca_host_key''** : CA-Schlüssel (private key) mit dem wir den öffentlichen Schlüssel des Zielhosts signieren und dadurch beglaubigen. |
* **''-z 1000''** : Gibt eine Seriennummer an, die in das Zertifikat eingebettet wird, um es von anderen Zertifikaten der derselben CA zu unterscheiden. Diese Seriennummer ist später z.B. sehr hilfreich, wenn es darum geht gezielt ein Zertifikat als ungültig zu deklarieren, sprich zu revoken. Sofern wir der serial_number ein '+'-Zeichen voranstellen, wird die Seriennummer für jedes jedes in einer einzigen Befehlszeile signierte Zertifikat erhöht. Die Standard-Seriennummer ist hier Null "0". | * **''-z 1000''** : Gibt eine Seriennummer an, die in das Zertifikat eingebettet wird, um es von anderen Zertifikaten der derselben CA zu unterscheiden. Diese Seriennummer ist später z.B. sehr hilfreich, wenn es darum geht gezielt ein Zertifikat als ungültig zu deklarieren, sprich zu revoken. Sofern wir der serial_number ein '+'-Zeichen voranstellen, wird die Seriennummer für jedes jedes in einer einzigen Befehlszeile signierte Zertifikat erhöht. Die Standard-Seriennummer ist hier Null "0". |
* **''-V +521d''** : Definiert die Zeit die das Zertifikat gültig sein soll, die also beim Signieren des Host-Schlüssels verwendet wird. Das Gültigkeitsintervall kann aus einem einzigen Zeitpunkt bestehen, der angibt, dass das Zertifikat ab jetzt gültig ist und zu diesem Zeitpunkt abläuft, oder es kann aus zwei Zeitpunkten bestehen, die durch einen Doppelpunkt durch einen Doppelpunkt getrennt sein, um ein explizites Zeitintervall anzugeben. In unserem Konfigurationsbeispiel also 52 Wochen und ein Tag zusätzlich → also in einem Jahr. | * **''-V +52w1d''** : Definiert die Zeit die das Zertifikat gültig sein soll, die also beim Signieren des Host-Schlüssels verwendet wird. Das Gültigkeitsintervall kann aus einem einzigen Zeitpunkt bestehen, der angibt, dass das Zertifikat ab jetzt gültig ist und zu diesem Zeitpunkt abläuft, oder es kann aus zwei Zeitpunkten bestehen, die durch einen Doppelpunkt durch einen Doppelpunkt getrennt sein, um ein explizites Zeitintervall anzugeben. In unserem Konfigurationsbeispiel also 52 Wochen und ein Tag zusätzlich → also in einem Jahr. |
* **''-I kvm''** : Der Key-Identifier ein "Schlüsselbezeichner", der vom Server protokolliert wird, wird herangezogen sobald das Zertifikat zur Authentifizierung verwendet wird. Wir verwenden hier also unseren beautyfied short-Hostname **''kvm''** für den Host **''pml010002.intra.nausch.org''**. | * **''-I kvm''** : Der Key-Identifier ein "Schlüsselbezeichner", der vom Server protokolliert wird, wird herangezogen sobald das Zertifikat zur Authentifizierung verwendet wird. Wir verwenden hier also unseren beautyfied short-Hostname **''kvm''** für den Host **''pml010002.intra.nausch.org''**. |
* **''-n kvm,kvm.intra.nausch.org,pml010002,pml010002.intra.nausch.org''** : Gibt einen oder mehrere Principals (Benutzer- oder Hostnamen) an, die beim Signieren eines Schlüssels in ein Zertifikat aufgenommen werden. Es können mehrere Principals angegeben werden, die durch Kommas getrennt sind. in unserem Fall also die **''hostname''**s und zusätzlich noch der **''fqdn''**s. | * **''-n kvm,kvm.intra.nausch.org,pml010002,pml010002.intra.nausch.org''** : Gibt einen oder mehrere Principals (Benutzer- oder Hostnamen) an, die beim Signieren eines Schlüssels in ein Zertifikat aufgenommen werden. Es können mehrere Principals angegeben werden, die durch Kommas getrennt sind. in unserem Fall also die **''hostname''**s und zusätzlich noch der **''fqdn''**s. |
ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4. | ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4. |
This key is not known by any other names | This key is not known by any other names |
Are you sure you want to continue connecting (yes/no/[fingerprint])?</code> \\ Wird jedoch ein gültiges Zertifikat und ein gültiger SSH HOST CA verwendet und sind ferner die Hostnamen im DNS gepflegt wird ein Verbindungsaufbau zum Zielhost anstandslos klappen. Wir entfernen aber noch mit Hilfe des Befehls **'' ssh-keygen -f ~/.ssh/known_hosts -R <hostname>''** den bisher genutzten Eintrag für unseren Host, damikt auch wirklich ausgeschlossen werden kann dass uns ein alter Eintrag hier "in die Suppe spucken könnte". In unserem Beispiel entfernen wir den Eintrtag für den Host **kvm**. <code>$ ssh-keygen -f ~/.ssh/known_hosts -R kvm.intra.nausch.org</code><code># Host kvm.intra.nausch.org found: line 1408 | Are you sure you want to continue connecting (yes/no/[fingerprint])?</code> \\ Wird jedoch ein gültiges Zertifikat und ein gültiger SSH HOST CA verwendet und sind ferner die Hostnamen im DNS gepflegt wird ein Verbindungsaufbau zum Zielhost anstandslos klappen. Wir entfernen aber noch mit Hilfe des Befehls **'' ssh-keygen -f ~/.ssh/known_hosts -R <hostname>''** den bisher genutzten Eintrag für unseren Host, damit auch wirklich ausgeschlossen werden kann dass uns ein alter Eintrag hier "in die Suppe spucken könnte". In unserem Beispiel entfernen wir den Eintrag für den Host **kvm**. <code>$ ssh-keygen -f ~/.ssh/known_hosts -R kvm.intra.nausch.org</code><code># Host kvm.intra.nausch.org found: line 1408 |
/home/django/.ssh/known_hosts updated. | /home/django/.ssh/known_hosts updated. |
Original contents retained as /home/django/.ssh/known_hosts.old</code>Nun starten wir eine SSH-Session zu unserem Zielhost.<code> $ ssh kvm.intra.nausch.org -v</code><code>... | Original contents retained as /home/django/.ssh/known_hosts.old</code>Nun starten wir eine SSH-Session zu unserem Zielhost.<code> $ ssh kvm.intra.nausch.org -v</code><code>... |
* **''-s /etc/ssh/ssh_ca/ssh_ca_user_key''** : Zertifizieren (signieren) eines öffentlichen User-Keys mit dem angegebenen CA-Schlüssel (private key). | * **''-s /etc/ssh/ssh_ca/ssh_ca_user_key''** : Zertifizieren (signieren) eines öffentlichen User-Keys mit dem angegebenen CA-Schlüssel (private key). |
* **''-z 1''** : Gibt eine Seriennummer an, die in das Zertifikat eingebettet wird, um es von anderen Zertifikaten der derselben CA zu unterscheiden. Sofern wir der serial_number ein '+'-Zeichen voranstellen, wird die Seriennummer für jedes jedes in einer einzigen Befehlszeile signierte Zertifikat erhöht. Die Standard-Seriennummer ist hier Null "0". | * **''-z 1''** : Gibt eine Seriennummer an, die in das Zertifikat eingebettet wird, um es von anderen Zertifikaten der derselben CA zu unterscheiden. Sofern wir der serial_number ein '+'-Zeichen voranstellen, wird die Seriennummer für jedes jedes in einer einzigen Befehlszeile signierte Zertifikat erhöht. Die Standard-Seriennummer ist hier Null "0". |
* **''-V +521d''** : Definiert die Zeit die das Zertifikat gültig sein soll, die also beim Signieren des Host-Schlüssels verwendet wird. Das Gültigkeitsintervall kann aus einem einzigen Zeitpunkt bestehen, der angibt, dass das Zertifikat ab jetzt gültig ist und zu diesem Zeitpunkt abläuft, oder es kann aus zwei Zeitpunkten bestehen, die durch einen Doppelpunkt durch einen Doppelpunkt getrennt sein, um ein explizites Zeitintervall anzugeben. In unserem Konfigurationsbeispiel also 52 Wochen und ein Tag zusätzlich → also in einem Jahr. | * **''-V +52w1d''** : Definiert die Zeit die das Zertifikat gültig sein soll, die also beim Signieren des Host-Schlüssels verwendet wird. Das Gültigkeitsintervall kann aus einem einzigen Zeitpunkt bestehen, der angibt, dass das Zertifikat ab jetzt gültig ist und zu diesem Zeitpunkt abläuft, oder es kann aus zwei Zeitpunkten bestehen, die durch einen Doppelpunkt durch einen Doppelpunkt getrennt sein, um ein explizites Zeitintervall anzugeben. In unserem Konfigurationsbeispiel also 52 Wochen und ein Tag zusätzlich → also in einem Jahr. |
* **''-I django''** : Der Key-Identifier ein "Schlüsselbezeichner", der vom Server protokolliert wird, wird herangezogen sobald das Zertifikat zur Authentifizierung verwendet wird. Wir verwenden hier also den Namen unseres Admin-Users von dem wir den public-key erhalten hatten. | * **''-I django''** : Der Key-Identifier ein "Schlüsselbezeichner", der vom Server protokolliert wird, wird herangezogen sobald das Zertifikat zur Authentifizierung verwendet wird. Wir verwenden hier also den Namen unseres Admin-Users von dem wir den public-key erhalten hatten. |
* Definiert den beim Signieren eines öffentlichen Server-Schlüssels die Schlüsselidentität der CA. | * Definiert den beim Signieren eines öffentlichen Server-Schlüssels die Schlüsselidentität der CA. |
TrustedUserCAKeys /etc/ssh/ssh_ca_user_key.pub | TrustedUserCAKeys /etc/ssh/ssh_ca_user_key.pub |
| |
...</code> Das Neustarten des Daemons verschieben wir noch etwas, da wir noch eine weitere Anpassung vornehmen werden. \\ Damit nun nicht jeder Admin sich auf jedem System mit Hilfe seines User-Zertifikates anmelden kann, bietet uns SSH die Option **''AuthorizedPrincipalsFile''** an. Hiermit kann festgelegt werden, ob sich der Admin, der gerade sein Zertifikat präsentiert, auch wirklich autorisiert ist sich anzumelden. Es könnte ja sein, dass unterschiedliche Admins sich nur auf eine begrenzte Anzahl von Maschinen verbinden darf, andere Admins unterliegen __nicht__ dieser Beschränkung. Bevor man nun auf die Idee kommt hierzu viele User CAs hierfür anzulegen, nutzen wir doch lieber Prüfung des principals, den wir beim Erstellen des User-Zertifikates angegeben hatten. Werfen wirdazu kurz einen Blick in das Zertifikat. <code> $ ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub</code><code>/home/django/.ssh/id_ed25519-cert.pub: | ...</code> Das Neustarten des Daemons verschieben wir noch etwas, da wir noch eine weitere Anpassung vornehmen werden. \\ Damit nun nicht jeder Admin sich auf jedem System mit Hilfe seines User-Zertifikates anmelden kann, bietet uns SSH die Option **''AuthorizedPrincipalsFile''** an. Hiermit kann festgelegt werden, ob sich der Admin, der gerade sein Zertifikat präsentiert, auch wirklich autorisiert ist sich anzumelden. Es könnte ja sein, dass unterschiedliche Admins sich nur auf eine begrenzte Anzahl von Maschinen verbinden darf, andere Admins unterliegen __nicht__ dieser Beschränkung. Bevor man nun auf die Idee kommt hierzu viele User CAs hierfür anzulegen, nutzen wir doch lieber Prüfung des principals, den wir beim Erstellen des User-Zertifikates angegeben hatten. Werfen wir dazu kurz einen Blick in das Zertifikat. <code> $ ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub</code><code>/home/django/.ssh/id_ed25519-cert.pub: |
Type: ssh-ed25519-cert-v01@openssh.com user certificate | Type: ssh-ed25519-cert-v01@openssh.com user certificate |
Public key: ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 | Public key: ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 |
permit-user-rc</code>Hier haben wir also bei den **''Principals''** den Wert **''django''**. In der Datei **''/etc/ssh/ssh_auth_principals''** wird nun definiert welche Admins/User sich anmelden darf, sprich wer ist in dieser Datei gelistet und wer nicht. Wir hinterlegen als den **''Principal''**-Namen aus dem Zertifikat in dieser Liste. <code> # vim /etc/ssh/ssh_auth_principals</code><file bash /etc/ssh/ssh_auth_principals># Liste aller Administratoren, die berechtigt sind sich hier mit Hilfe der SSH zu verbinden. | permit-user-rc</code>Hier haben wir also bei den **''Principals''** den Wert **''django''**. In der Datei **''/etc/ssh/ssh_auth_principals''** wird nun definiert welche Admins/User sich anmelden darf, sprich wer ist in dieser Datei gelistet und wer nicht. Wir hinterlegen als den **''Principal''**-Namen aus dem Zertifikat in dieser Liste. <code> # vim /etc/ssh/ssh_auth_principals</code><file bash /etc/ssh/ssh_auth_principals># Liste aller Administratoren, die berechtigt sind sich hier mit Hilfe der SSH zu verbinden. |
django | django |
michael</file> In diesem Beispiel wären das die User **michael** und **django**, der User **christoph** könnte sich nicht anmelden, selnst wenn er ein gültiges User-Zertifikat der gleichen User CA hätte, wie der User **michael**. Damit der SSH-Daemon diese Liste auch verwerten kann, muss er natürlich wissen dass es sie gibt und wo er sie findet; hierzu ergänzen wir die **''/etc/ssh/sshd_config''** um folgenden Abschnitt.<code> # vim /etc/ssh/sshd_config</code><code>... | michael</file> In diesem Beispiel wären das die User **michael** und **django**, der User **christoph** könnte sich nicht anmelden, selbst wenn er ein gültiges User-Zertifikat der gleichen User CA hätte, wie der User **michael**. Damit der SSH-Daemon diese Liste auch verwerten kann, muss er natürlich wissen dass es sie gibt und wo er sie findet; hierzu ergänzen wir die **''/etc/ssh/sshd_config''** um folgenden Abschnitt.<code> # vim /etc/ssh/sshd_config</code><code>... |
| |
# Specifies a file that lists principal names that are accepted for certifi- | # Specifies a file that lists principal names that are accepted for certifi- |
Obwohl OpenSSH keinen Mechanismus zum Verteilen der Sperrliste bereitstellt, ist es immer noch einfacher, die Sperrliste zu erstellen und sie auf anderem Wege z.B. Orchestrierung mit Hilfe von Ansible zu verteilen, als die CA-Schlüssel und alle zuvor erstellten und verteilten Host- und Benutzerzertifikate zu ändern. Diese Sperrliste **''ssh_ca_krl''** haben wir bereits beim Anlegen unserer CAs im Abschnitt **[[#zertifizierungsstellen_host_und_user_ca|Zertifizierungsstellen HOST und USER CA]]** angelegt. Diese befindet sich im CA-Verzeichnis auf unserem CA-Host unter **''/etc/ssh/ssh_ca''**. Diese Datei kopieren wir nun regelmässig auf unsere Maschinen und legen diese im Verzeichnis **''/etc/ssh/''** ab. | Obwohl OpenSSH keinen Mechanismus zum Verteilen der Sperrliste bereitstellt, ist es immer noch einfacher, die Sperrliste zu erstellen und sie auf anderem Wege z.B. Orchestrierung mit Hilfe von Ansible zu verteilen, als die CA-Schlüssel und alle zuvor erstellten und verteilten Host- und Benutzerzertifikate zu ändern. Diese Sperrliste **''ssh_ca_krl''** haben wir bereits beim Anlegen unserer CAs im Abschnitt **[[#zertifizierungsstellen_host_und_user_ca|Zertifizierungsstellen HOST und USER CA]]** angelegt. Diese befindet sich im CA-Verzeichnis auf unserem CA-Host unter **''/etc/ssh/ssh_ca''**. Diese Datei kopieren wir nun regelmässig auf unsere Maschinen und legen diese im Verzeichnis **''/etc/ssh/''** ab. |
| |
Damit der SSH-Daemon dieseSperrliste auch berücksichtigen kann, muss dieser natürlich wissen, dass es diese gibt ond wo diese zu finden ist. Wir ergänzen also unsere SSH-Daemon-Konfiguration noch einmal. | Damit der SSH-Daemon diese Sperrliste auch berücksichtigen kann, muss dieser natürlich wissen, dass es diese gibt und wo diese zu finden ist. Wir ergänzen also unsere SSH-Daemon-Konfiguration noch einmal. |
# vim /etc/ssh/sshd_config | # vim /etc/ssh/sshd_config |
<code>... | <code>... |
permit-user-rc</code>Wir sehen also hier die **''Serial: 4''** (Serien-Nummer) und den **''Principals: django''**. O.K. das haben wir geprüft, es ist genau das Zertifikat, welches wir vom Nutzer **django** auf die Sperrliste setzen sollen. | permit-user-rc</code>Wir sehen also hier die **''Serial: 4''** (Serien-Nummer) und den **''Principals: django''**. O.K. das haben wir geprüft, es ist genau das Zertifikat, welches wir vom Nutzer **django** auf die Sperrliste setzen sollen. |
- **Prüfen des Aktuellen Zertifikatsstatus** \\ Eine Vorabprüfung, ob das Zertifikat aktuell noch nicht revoked wurde, sehen wir hier:<code> ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub</code><code>/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): ok</code> Das Zertifikat ist aktuell also noch gültig! | - **Prüfen des Aktuellen Zertifikatsstatus** \\ Eine Vorabprüfung, ob das Zertifikat aktuell noch nicht revoked wurde, sehen wir hier:<code> ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub</code><code>/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): ok</code> Das Zertifikat ist aktuell also noch gültig! |
- **Revoken des Zertifikates** \\ Zum Rückrufen des Zertifikates mit der Seriennummer **''4''** müssen wir nun die beiden Optionen **''-k''** zusammen mit der Option **''-u''** angeben, da wir einen Update der Sperrlistendatei vornehmen wollen. Mit der Option **''-f''** definieren wir die SPerrlistendatei selbst. Wichtigste Option ist nun die Seriennummer die wir mit der Option **''-z 4''** angeben. Würden wir diese Option weglassen, würden wir **__ALLE__** Zertifikate des Benutzers revoken!<code> # ssh-keygen -u -k -f /etc/ssh/ssh_ca/ssh_ca_krl -z 4 /etc/ssh/ssh_ca/id_ed25519_test-cert.pub</code><code>Revoking from /etc/ssh/ssh_ca/id_ed25519_test-cert.pub</code>Die Rückmeldung war entsprechend positiv, das Zertifikat kann ab sofort nicht mehr benutzt werden um sich an einem Host anzumelden. | - **Revoken des Zertifikates** \\ Zum Rückrufen des Zertifikates mit der Seriennummer **''4''** müssen wir nun die beiden Optionen **''-k''** zusammen mit der Option **''-u''** angeben, da wir einen Update der Sperrlistendatei vornehmen wollen. Mit der Option **''-f''** definieren wir die Sperrlistendatei selbst. Wichtigste Option ist nun die Seriennummer die wir mit der Option **''-z 4''** angeben. Würden wir diese Option weglassen, würden wir **__ALLE__** Zertifikate des Benutzers revoken!<code> # ssh-keygen -u -k -f /etc/ssh/ssh_ca/ssh_ca_krl -z 4 /etc/ssh/ssh_ca/id_ed25519_test-cert.pub</code><code>Revoking from /etc/ssh/ssh_ca/id_ed25519_test-cert.pub</code>Die Rückmeldung war entsprechend positiv, das Zertifikat kann ab sofort nicht mehr benutzt werden um sich an einem Host anzumelden. |
- **Prüfen des Aktuellen Zertifikatsstatus** \\ Eine erneute Prüfung, wie nun der aktuelle Status des Zertifikats ist, sehen wir hier:<code> ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub</code><code>/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): REVOKED</code> Das Zertifikat ist also definitiv gesperrt/zurückgerufen! | - **Prüfen des Aktuellen Zertifikatsstatus** \\ Eine erneute Prüfung, wie nun der aktuelle Status des Zertifikats ist, sehen wir hier:<code> ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub</code><code>/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): REVOKED</code> Das Zertifikat ist also definitiv gesperrt/zurückgerufen! |
| |
===== Fazit und Ausblick ===== | ===== Fazit und Ausblick ===== |
<WRAP center round tip 80%> | <WRAP center round tip 80%> |
Möchte man das Thema **TOFU** sauber lösen ist die Verwendung von Host Zertifikaten sicherlich ein sehr guter Weg, den man beim **sicheren IT Betrieb** aufgreifen sollte. Denn theoretische Sicherheit ist toll, aber was helfen alle theoretischen Vorüberlegungen, wenn der Admin bei der initialen Kontaktaufnahme sich überrumpeln oder ablenken lässt. Der Zugewinn an Sicherheit ist hier definitiv ein Punkt der für die Verwendung von Host-Zertifikaten spricht. | Möchte man das Thema **TOFU** sauber lösen, ist die Verwendung von Host Zertifikaten sicherlich ein sehr guter Weg, den man beim **sicheren IT Betrieb** aufgreifen sollte. Denn theoretische Sicherheit ist toll, aber was helfen alle theoretischen Vorüberlegungen, wenn der Admin bei der initialen Kontaktaufnahme sich überrumpeln oder ablenken lässt. Der Zugewinn an Sicherheit ist hier definitiv ein Punkt der für die Verwendung von Host-Zertifikaten spricht! |
| |
Ob man sich auch auf das Thema User-Zertifikate einlassen möchte, ist da schon mehr einer genauen Aufwands-Nutzenabwägung zu unterziehen. Wie werden z.B. die User-Zertifikate sicher verwahrt und abgesichert. Das Thema KRL ist dann sicher noch ein ganz besonderes Thema das Betrachtet werden muss. Diese beiden Themen manuell durch einen oder gar mehrere handelnde Personen erledigen zu lassen, wird aller Voraussicht nach lediglich die Administrationsaufwände signifikant erhöhen. Im schlimmsten Fall schafft man bei der manuellen Verwendung mehr Probleme und Risiken. | Ob man sich auch auf das Thema User-Zertifikate einlassen möchte, ist da schon mehr einer genauen Aufwands-Nutzenabwägung zu unterziehen. Wie werden z.B. die User-Zertifikate sicher verwahrt und abgesichert. Das Thema KRL ist dann sicher noch ein ganz besonderes Thema das Betrachtet werden muss. Diese beiden Themen __manuell__ durch einen oder gar mehrere handelnde Personen erledigen zu lassen, wird aller Voraussicht nach lediglich die Administrationsaufwände signifikant erhöhen. Im schlimmsten Fall schafft man bei der manuellen Verwendung mehr Probleme und Risiken. |
| |
Lösungen für diese Herausforderungen können zum einen eine Versionierung mit Hilfe von Git und Orchestrierung der Aufgaben mit einem State-of-th-Art- Werkzeug wie **Ansible** sein. Alternativ könnte auch die eingehende Betrachtung und Überlegung in Richtung **[[https://keyper.dbsentry.com/|KEYPER]]** gehen, sofern man sich auf Container einlassen kann|will. Keyper ist ein Open Source SSH-Schlüssel- und zertifikatsbasierter Authentifizierungsmanager, der auch als SSH-Zertifizierungsstelle (CA) fungiert. | Lösungen für diese Herausforderungen können zum einen eine Versionierung mit Hilfe von Git und Orchestrierung der Aufgaben mit einem State-of-th-Art- Werkzeug wie **Ansible** sein. Alternativ könnte auch die eingehende Betrachtung und Überlegung in Richtung **[[https://keyper.dbsentry.com/|KEYPER]]** gehen, sofern man sich auf Container einlassen kann|will. Keyper ist ein Open Source SSH-Schlüssel- und zertifikatsbasierter Authentifizierungsmanager, der auch als SSH-Zertifizierungsstelle (CA) fungiert. |