TOFU - Trust On First Use - SSH Zertifikate
Ausgangssituation
O.K., worum geht es hier eigentlich?
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
The authenticity of host 'vml172042 (172.17.2.42)' can't be established. ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?
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:
- Woot? Mir egal, ich antworte hier mit
yes
weil mitno
komme ich nicht weiter und so habe ich Ruhe, die Meldung kommt nicht wieder! Und ganz ehrlich ich weiß nicht was das soll.
- Pfff, ich rufe entweder
ssh
mit den Optionen-o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null
auf, bzw. ich habe in meiner SSH-Clientconfig unter~/.ssh/config
die folgenden Zeilen eingetragen bei meinen Hosts:Host * StrictHostKeyChecking=no UserKnownHostsFile=/dev/null
Problem gelöst!
- Natürlich, prüfe ich den Fingerprint, ich kenne den ja auswendig (in unserem obigen Beispiel
SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4
) oder ich habe eine Liste aller möglichen 1860 Host vor mir und tippe den dann vor dem ersten Verbindungsaufbau ein, weil ich weiss was TOFU bedeutet und nehme das ernst.
O.K., Antwort 1 und 2 will man definitiv nicht hören! Bei Antwort 3 sagt mir mein innerstes ICH „echt, Du machst das wirklich so oder da nimmst Du mich doch eher auf den Arm?“.
Wie können wir nun dieses Dilemma beim ersten Verbindungsaufbau nun elegant umschiffen und dies sauber uns auch sicher lösen? Das wollen wir uns nun im nächsten Abschnitt noch etwas genauer ansehen.
Erklärung - Was versteht man unter Trust On First Use (TOFU)
Soviel sei vorab schon mal erwähnt:
Das Securitymodell TOFU1) dient dazu zwischen einer Client-Software und einem Ziel-System ein Vertrauen herzustellen, für den zuvor kein Vertrauen aufgebaut wurde. Im obigen Abschnitt 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. Wie weiss der SSH-Client dies nun? Der SSH-Client versucht die die Kennung des Zielsystems, in der Regel eine Art öffentlichen Schlüssel, in ihrer lokalen Vertrauensdatenbank zu finden. Kann diese im Falle der SSH in der ~/.ssh/known_hosts
dort nicht gefunden werden, wendet sich der SSH-Client in der Regel an den Benutzer, um festzustellen, ob dem Rechner vertraut werden soll. Ist diese Entscheidung positiv, wird die Kennung des Zielsystems in der Vertrauensdatenbank der (SSH-)Client-Software für künftige Verbindungen gespeichert.
Im obigen Abschnitt 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 MITM2) 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!
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 Lösung(smöglichkeit).
Bestätigen wir nun das Vertrauen bei der ersten Verbindungsaufbau/-verwendung (TOFU3)) 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.
Letztendlich es kann da sehr schnell mitunter auch „hässlich“ werden. Das war z.B. auch bei einem Sicherheits-Audit genau diese Antwort des Auditors bei meiner Frage, warum er denn etwas gegen authorized_keys
habe!
Zusammengefasst kann man also schon mal folgende Dinge Festhalten:
Der Zweck von TOFU ist: Das Vertrauen bei der ersten Nutzung ist ein Mechanismus und hat das Ziel ein Vertrauen zu schaffen, wo es vorher keines gab. In der Regel passiert das auf der Grundlage einer Benutzerentscheidung. Bei TOFU überlässt man es im Grunde dem Benutzer, zu entscheiden, ob ein Rechner legitim ist und ob er zu erkennen vermag das bei dieser initialen Verbindung kein Angreifer anwesend ist.
Das Ganze ist also durchaus anfällig, denn die erste Entscheidung, ob einem Rechner vertraut wird ist eine Entscheidung, auf die sich alle nachfolgenden Entscheidungen stützen! Gelingt es einem Angreifer diesen Prozess zu infiltrieren und als vertrauenswürdiger Rechner aufgenommen zu werden, ist die Verbindung und mehr völlig ungeschützt!
Aber wie wir wissen, neigen Benutzer und Administratoren doch auch dazu nicht immer die richtigen Entscheidungen zu treffen - man kann also durchaus auch das als Schwachstelle des TOFU-Modells ausmachen!
Lösung(smöglichkeit)
Wie gehen wir nun am besten mit dem Dilemma um bzw. wie lösen wir es? Hier gibt es wie im Leben immer, natürlich nicht nur den einen einzigartigen Lösungsweg, sondern mehrere, von denen wir uns nun mal zwei genauer ansehen wollen.
Rufen wir uns aber kurz nochmals in Erinnerung wie das Ganze bei der SSH und der Authentifizierung funktioniert:
Die Authentifizierung mit öffentlichem Schlüssel funktioniert wie folgt: Das Verfahren basiert auf der Public-Key-Kryptografie, die Kryptosysteme verwendet, bei denen die Ver- und Entschlüsselung mit getrennten Schlüsseln erfolgt und es nicht möglich ist, den Entschlüsselungsschlüssel aus dem Verschlüsselungsschlüssel abzuleiten. Die Idee ist, dass jeder Benutzer ein öffentliches/privates Schlüsselpaar für Authentifizierungszwecke erstellt. Der Server kennt den öffentlichen Schlüssel, und nur der Benutzer kennt den privaten Schlüssel.
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.
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).
manueller Fingerprintabgleich
O.K. diejenigen unter uns, die nun bei der Betrachtung der Ausgangssituation und bei der Erklärung - Was versteht man unter Trust On First Use (TOFU) noch fleissig mit dem Kopf nickten, zeigen wir nun im ersten Schritt eine Möglichkeit auf das Thema TOFU bestmöglich zu begegnen.
Gehen wir erst einmal noch einen Schritt zurück und bauen unsere erste Verbindung zum gewählten Zielsystem auf.
$ ssh -Y vml172042
The authenticity of host 'vml172042 (172.17.2.42)' can't be established. ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?
Uns wird also der Fingerprint SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4
des Zielsystems genauer gesagt vom /etc/ssh/ssh_host_ed25519_key
des Ziel-Host präsentiert. Doch wie kommen wir nun an diesen?
Den Fingerprint des ED25519-Hostkey vom Server vml172042 könnte man sich ja nun wie folgt ermitteln:
$ ssh-keyscan -t ed25519 vml172042
# vml172042:22 SSH-2.0-OpenSSH_7.4 # vml172042:22 SSH-2.0-OpenSSH_7.4 256 SHA256:syMNF0jPr8b7hgqoCLgUZpSZhMulGeoGKFU/FWm3UKY vml172042 (ED25519)
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.
Wir sehen, Idee war vom Ansatz her schon mal nicht schlecht, aber die Umsetzung doch sehr fehlerbehaftet und daher verwerfen wir diese Variante auch gleich wieder!
Also melden wir uns am besten direkt an der Konsole des Zielsystems an, wenn wir physisch vor diesem stehen. Oder wir verbinden uns mit der GUI des Virtualisierungs-Hosts oder einem RemoteManageBoard wie IPMI oder iDrac je nachdem was der Hardwarehersteller uns hier anbietet. Dort ermitteln wir mit den entsprechenden Rechten den Fingerprint unseres Server-Keys.
# ssh-keygen -E sha256 -lf /etc/ssh/ssh_host_ed25519_key
256 SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4 /etc/ssh/ssh_host_ed25519_key.pub (ED25519)
Diesen notieren wir nun und hinterlegen diesen für alle Admins im Intranet, im WIKI, in GitHub bzw. GitLab, wo immer auch unsere Admins Zugriff haben um diesen zu finden um beim späteren Verbindungsaufbau dann verwenden zu können.
Jetzt verbinden uns nun mit dem uns noch unbekanntem Zielsystem, dessen Key-Fingerprint wir ja nun auf anderem Wege zur Verfügung gestellt bekommen haben:
$ ssh -Y vml172042
The authenticity of host 'vml172042 (172.17.2.42)' can't be established. ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?
Ja wir könnten nun visuell den Fingerprint vergleichen und dann mit yes
bestätigen. Aber Hand aufs Herz wie schnell verguckt man sich da beim optischen Vergleich? Besser ist es, wenn wir unseren Fingerprint den wir z.B.im Intranet gefunden haben, dort manuell eingeben oder cut'n'pasten.
Wollen wir doch mal sehen,was passiert wenn wir uns vertippen (die drei X am Ende!):
Are you sure you want to continue connecting (yes/no/[fingerprint])? SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8XXX
Please type 'yes', 'no' or the fingerprint:
Aha, die beiden Fingerprints stimmt also nicht überein:
SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4 SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8XXX
O.K. wir bestätigen also nun den richtigen Fingerprint:
Please type 'yes', 'no' or the fingerprint:SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1K14U503r5P1nN3r8nO4
Nun erhalten wir einen Hinweis dass unser Host nun dauerhaft bekannt ist:
Warning: Permanently added '172.17.2.42' (ED25519) to the list of known hosts.
… und voila wir sind auf dem Zielhost:
[django@vml172042 ~]$
Verbinden wir uns nun ab sofort, erneut mit dem Zielhost erneut bekommen wir keine TOFU-Warnung mehr präsentiert, sondern gelangen direkt ohne Umwege auf unseren Zielhost. Verantwortlich ist der letzte Eintrag der vorhin bei ersten Aufbau in unserer ~./.ssh/know_hosts
eingetragen wurde!
Ja aber, wir vielleicht nun jemand sagen, wir haben noch immer das Problem mit den wechselnden Host-Keys! Ändert nun jemand aus welchem Grund auch immer den ssh_host_key auf einem der vielen Zielsysteme oder wird die virtuelle Maschine getauscht ändert sich in aller Regel auch dessen Host-Key. Was wird also vermutlich passiere, wenn wir uns nun erneut mit einem zuvor als validem Zielsystem erkannten System verbinden wollen?
$ ssh -Y vml172042
The authenticity of host 'vml172042 (172.17.2.42)' can't be established. ED25519 key fingerprint is SHA256:syMNF0jPr8b0j4N90154933khMulGeoGKFU/FWm3UKY. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?
Da wir ja nun bestens mit der TOFU-Thematik auseinandergesetzt haben wissen wir Bescheid, wie besorgen uns den neuen Fingerprint des Servers, vergleichen diesen mit dem präsentierten oder geben den neu bekannt gegebenen Fingerprint ein. O.K. wir sind wieder auf dem richtigen Zielhost, den wir vertrauen.
ABER, was erneut passiert ist der Eintag in der known_hosts, der bestehende alte verbleibt dort ebenso! Diese wird also unweigerlich zum steten Anwachsen der ~/.ssh/know_hosts
führen, mit vielen hunderten oder gar tausenden Zeilen mit zum Teil alten verwaisten Daten → nicht schön, will man so eigentlich nicht haben sondern vermeiden wollen.
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.
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.
Bei Bedarf wirft man also einen Blick in besagte Manual-Pages (zum Öffnen der im WIKI abgelegten Man-Pages auf die grauen Balken klicken!) :
$ man ssh
SSH(1) General Commands Manual SSH(1)
NAME
ssh — OpenSSH remote login client
SYNOPSIS
ssh [-46AaCfGgKkMNnqsTtVvXxYy] [-B bind_interface] [-b bind_address] [-c cipher_spec] [-D [bind_address:]port]
[-E log_file] [-e escape_char] [-F configfile] [-I pkcs11] [-i identity_file] [-J destination] [-L address]
[-l login_name] [-m mac_spec] [-O ctl_cmd] [-o option] [-P tag] [-p port] [-Q query_option] [-R address]
[-S ctl_path] [-W host:port] [-w local_tun[:remote_tun]] destination [command [argument ...]]
DESCRIPTION
ssh (SSH client) is a program for logging into a remote machine and for executing commands on a remote machine. It is
intended to provide secure encrypted communications between two untrusted hosts over an insecure network. X11 connec‐
tions, arbitrary TCP ports and Unix-domain sockets can also be forwarded over the secure channel.
ssh connects and logs into the specified destination, which may be specified as either [user@]hostname or a URI of the
form ssh://[user@]hostname[:port]. The user must prove their identity to the remote machine using one of several methods
(see below).
If a command is specified, it will be executed on the remote host instead of a login shell. A complete command line may
be specified as command, or it may have additional arguments. If supplied, the arguments will be appended to the com‐
mand, separated by spaces, before it is sent to the server to be executed.
The options are as follows:
-4 Forces ssh to use IPv4 addresses only.
-6 Forces ssh to use IPv6 addresses only.
-A Enables forwarding of connections from an authentication agent such as ssh-agent(1). This can also be specified
on a per-host basis in a configuration file.
Agent forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote
host (for the agent's Unix-domain socket) can access the local agent through the forwarded connection. An at‐
tacker cannot obtain key material from the agent, however they can perform operations on the keys that enable
them to authenticate using the identities loaded into the agent. A safer alternative may be to use a jump host
(see -J).
-a Disables forwarding of the authentication agent connection.
-B bind_interface
Bind to the address of bind_interface before attempting to connect to the destination host. This is only useful
on systems with more than one address.
-b bind_address
Use bind_address on the local machine as the source address of the connection. Only useful on systems with more
than one address.
-C Requests compression of all data (including stdin, stdout, stderr, and data for forwarded X11, TCP and
Unix-domain connections). The compression algorithm is the same used by gzip(1). Compression is desirable on
modem lines and other slow connections, but will only slow down things on fast networks. The default value can
be set on a host-by-host basis in the configuration files; see the Compression option in ssh_config(5).
-c cipher_spec
Selects the cipher specification for encrypting the session. cipher_spec is a comma-separated list of ciphers
listed in order of preference. See the Ciphers keyword in ssh_config(5) for more information.
-D [bind_address:]port
Specifies a local “dynamic” application-level port forwarding. This works by allocating a socket to listen to
port on the local side, optionally bound to the specified bind_address. Whenever a connection is made to this
port, the connection is forwarded over the secure channel, and the application protocol is then used to determine
where to connect to from the remote machine. Currently the SOCKS4 and SOCKS5 protocols are supported, and ssh
will act as a SOCKS server. Only root can forward privileged ports. Dynamic port forwardings can also be speci‐
fied in the configuration file.
IPv6 addresses can be specified by enclosing the address in square brackets. Only the superuser can forward
privileged ports. By default, the local port is bound in accordance with the GatewayPorts setting. However, an
explicit bind_address may be used to bind the connection to a specific address. The bind_address of “localhost”
indicates that the listening port be bound for local use only, while an empty address or ‘*’ indicates that the
port should be available from all interfaces.
-E log_file
Append debug logs to log_file instead of standard error.
-e escape_char
Sets the escape character for sessions with a pty (default: ‘~’). The escape character is only recognized at the
beginning of a line. The escape character followed by a dot (‘.’) closes the connection; followed by control-Z
suspends the connection; and followed by itself sends the escape character once. Setting the character to “none”
disables any escapes and makes the session fully transparent.
-F configfile
Specifies an alternative per-user configuration file. If a configuration file is given on the command line, the
system-wide configuration file (/etc/ssh/ssh_config) will be ignored. The default for the per-user configuration
file is ~/.ssh/config. If set to “none”, no configuration files will be read.
-f Requests ssh to go to background just before command execution. This is useful if ssh is going to ask for pass‐
words or passphrases, but the user wants it in the background. This implies -n. The recommended way to start
X11 programs at a remote site is with something like ssh -f host xterm.
If the ExitOnForwardFailure configuration option is set to “yes”, then a client started with -f will wait for all
remote port forwards to be successfully established before placing itself in the background. Refer to the de‐
scription of ForkAfterAuthentication in ssh_config(5) for details.
-G Causes ssh to print its configuration after evaluating Host and Match blocks and exit.
-g Allows remote hosts to connect to local forwarded ports. If used on a multiplexed connection, then this option
must be specified on the master process.
-I pkcs11
Specify the PKCS#11 shared library ssh should use to communicate with a PKCS#11 token providing keys for user au‐
thentication.
-i identity_file
Selects a file from which the identity (private key) for public key authentication is read. You can also specify
a public key file to use the corresponding private key that is loaded in ssh-agent(1) when the private key file
is not present locally. The default is ~/.ssh/id_rsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519,
~/.ssh/id_ed25519_sk and ~/.ssh/id_dsa. Identity files may also be specified on a per-host basis in the configu‐
ration file. It is possible to have multiple -i options (and multiple identities specified in configuration
files). If no certificates have been explicitly specified by the CertificateFile directive, ssh will also try to
load certificate information from the filename obtained by appending -cert.pub to identity filenames.
-J destination
Connect to the target host by first making an ssh connection to the jump host described by destination and then
establishing a TCP forwarding to the ultimate destination from there. Multiple jump hops may be specified sepa‐
rated by comma characters. This is a shortcut to specify a ProxyJump configuration directive. Note that config‐
uration directives supplied on the command-line generally apply to the destination host and not any specified
jump hosts. Use ~/.ssh/config to specify configuration for jump hosts.
-K Enables GSSAPI-based authentication and forwarding (delegation) of GSSAPI credentials to the server.
-k Disables forwarding (delegation) of GSSAPI credentials to the server.
-L [bind_address:]port:host:hostport
-L [bind_address:]port:remote_socket
-L local_socket:host:hostport
-L local_socket:remote_socket
Specifies that connections to the given TCP port or Unix socket on the local (client) host are to be forwarded to
the given host and port, or Unix socket, on the remote side. This works by allocating a socket to listen to ei‐
ther a TCP port on the local side, optionally bound to the specified bind_address, or to a Unix socket. Whenever
a connection is made to the local port or socket, the connection is forwarded over the secure channel, and a con‐
nection is made to either host port hostport, or the Unix socket remote_socket, from the remote machine.
Port forwardings can also be specified in the configuration file. Only the superuser can forward privileged
ports. IPv6 addresses can be specified by enclosing the address in square brackets.
By default, the local port is bound in accordance with the GatewayPorts setting. However, an explicit
bind_address may be used to bind the connection to a specific address. The bind_address of “localhost” indicates
that the listening port be bound for local use only, while an empty address or ‘*’ indicates that the port should
be available from all interfaces.
-l login_name
Specifies the user to log in as on the remote machine. This also may be specified on a per-host basis in the
configuration file.
-M Places the ssh client into “master” mode for connection sharing. Multiple -M options places ssh into “master”
mode but with confirmation required using ssh-askpass(1) before each operation that changes the multiplexing
state (e.g. opening a new session). Refer to the description of ControlMaster in ssh_config(5) for details.
-m mac_spec
A comma-separated list of MAC (message authentication code) algorithms, specified in order of preference. See
the MACs keyword in ssh_config(5) for more information.
-N Do not execute a remote command. This is useful for just forwarding ports. Refer to the description of
SessionType in ssh_config(5) for details.
-n Redirects stdin from /dev/null (actually, prevents reading from stdin). This must be used when ssh is run in the
background. A common trick is to use this to run X11 programs on a remote machine. For example, ssh -n
shadows.cs.hut.fi emacs & will start an emacs on shadows.cs.hut.fi, and the X11 connection will be automatically
forwarded over an encrypted channel. The ssh program will be put in the background. (This does not work if ssh
needs to ask for a password or passphrase; see also the -f option.) Refer to the description of StdinNull in
ssh_config(5) for details.
-O ctl_cmd
Control an active connection multiplexing master process. When the -O option is specified, the ctl_cmd argument
is interpreted and passed to the master process. Valid commands are: “check” (check that the master process is
running), “forward” (request forwardings without command execution), “cancel” (cancel forwardings), “exit” (re‐
quest the master to exit), and “stop” (request the master to stop accepting further multiplexing requests).
-o option
Can be used to give options in the format used in the configuration file. This is useful for specifying options
for which there is no separate command-line flag. For full details of the options listed below, and their possi‐
ble values, see ssh_config(5).
AddKeysToAgent
AddressFamily
BatchMode
BindAddress
CanonicalDomains
CanonicalizeFallbackLocal
CanonicalizeHostname
CanonicalizeMaxDots
CanonicalizePermittedCNAMEs
CASignatureAlgorithms
CertificateFile
CheckHostIP
Ciphers
ClearAllForwardings
Compression
ConnectionAttempts
ConnectTimeout
ControlMaster
ControlPath
ControlPersist
DynamicForward
EnableEscapeCommandline
EscapeChar
ExitOnForwardFailure
FingerprintHash
ForkAfterAuthentication
ForwardAgent
ForwardX11
ForwardX11Timeout
ForwardX11Trusted
GatewayPorts
GlobalKnownHostsFile
GSSAPIAuthentication
GSSAPIDelegateCredentials
HashKnownHosts
Host
HostbasedAcceptedAlgorithms
HostbasedAuthentication
HostKeyAlgorithms
HostKeyAlias
Hostname
IdentitiesOnly
IdentityAgent
IdentityFile
IPQoS
KbdInteractiveAuthentication
KbdInteractiveDevices
KexAlgorithms
KnownHostsCommand
LocalCommand
LocalForward
LogLevel
MACs
Match
NoHostAuthenticationForLocalhost
NumberOfPasswordPrompts
PasswordAuthentication
PermitLocalCommand
PermitRemoteOpen
PKCS11Provider
Port
PreferredAuthentications
ProxyCommand
ProxyJump
ProxyUseFdpass
PubkeyAcceptedAlgorithms
PubkeyAuthentication
RekeyLimit
RemoteCommand
RemoteForward
RequestTTY
RequiredRSASize
SendEnv
ServerAliveInterval
ServerAliveCountMax
SessionType
SetEnv
StdinNull
StreamLocalBindMask
StreamLocalBindUnlink
StrictHostKeyChecking
TCPKeepAlive
Tunnel
TunnelDevice
UpdateHostKeys
User
UserKnownHostsFile
VerifyHostKeyDNS
VisualHostKey
XAuthLocation
-P tag Specify a tag name that may be used to select configuration in ssh_config(5). Refer to the Tag and Match key‐
words in ssh_config(5) for more information.
-p port
Port to connect to on the remote host. This can be specified on a per-host basis in the configuration file.
-Q query_option
Queries for the algorithms supported by one of the following features: cipher (supported symmetric ciphers),
cipher-auth (supported symmetric ciphers that support authenticated encryption), help (supported query terms for
use with the -Q flag), mac (supported message integrity codes), kex (key exchange algorithms), key (key types),
key-ca-sign (valid CA signature algorithms for certificates), key-cert (certificate key types), key-plain (non-
certificate key types), key-sig (all key types and signature algorithms), protocol-version (supported SSH proto‐
col versions), and sig (supported signature algorithms). Alternatively, any keyword from ssh_config(5) or
sshd_config(5) that takes an algorithm list may be used as an alias for the corresponding query_option.
-q Quiet mode. Causes most warning and diagnostic messages to be suppressed.
-R [bind_address:]port:host:hostport
-R [bind_address:]port:local_socket
-R remote_socket:host:hostport
-R remote_socket:local_socket
-R [bind_address:]port
Specifies that connections to the given TCP port or Unix socket on the remote (server) host are to be forwarded
to the local side.
This works by allocating a socket to listen to either a TCP port or to a Unix socket on the remote side. When‐
ever a connection is made to this port or Unix socket, the connection is forwarded over the secure channel, and a
connection is made from the local machine to either an explicit destination specified by host port hostport, or
local_socket, or, if no explicit destination was specified, ssh will act as a SOCKS 4/5 proxy and forward connec‐
tions to the destinations requested by the remote SOCKS client.
Port forwardings can also be specified in the configuration file. Privileged ports can be forwarded only when
logging in as root on the remote machine. IPv6 addresses can be specified by enclosing the address in square
brackets.
By default, TCP listening sockets on the server will be bound to the loopback interface only. This may be over‐
ridden by specifying a bind_address. An empty bind_address, or the address ‘*’, indicates that the remote socket
should listen on all interfaces. Specifying a remote bind_address will only succeed if the server's GatewayPorts
option is enabled (see sshd_config(5)).
If the port argument is ‘0’, the listen port will be dynamically allocated on the server and reported to the
client at run time. When used together with -O forward, the allocated port will be printed to the standard out‐
put.
-S ctl_path
Specifies the location of a control socket for connection sharing, or the string “none” to disable connection
sharing. Refer to the description of ControlPath and ControlMaster in ssh_config(5) for details.
-s May be used to request invocation of a subsystem on the remote system. Subsystems facilitate the use of SSH as a
secure transport for other applications (e.g. sftp(1)). The subsystem is specified as the remote command. Refer
to the description of SessionType in ssh_config(5) for details.
-T Disable pseudo-terminal allocation.
-t Force pseudo-terminal allocation. This can be used to execute arbitrary screen-based programs on a remote ma‐
chine, which can be very useful, e.g. when implementing menu services. Multiple -t options force tty allocation,
even if ssh has no local tty.
-V Display the version number and exit.
-v Verbose mode. Causes ssh to print debugging messages about its progress. This is helpful in debugging connec‐
tion, authentication, and configuration problems. Multiple -v options increase the verbosity. The maximum is 3.
-W host:port
Requests that standard input and output on the client be forwarded to host on port over the secure channel. Im‐
plies -N, -T, ExitOnForwardFailure and ClearAllForwardings, though these can be overridden in the configuration
file or using -o command line options.
-w local_tun[:remote_tun]
Requests tunnel device forwarding with the specified tun(4) devices between the client (local_tun) and the server
(remote_tun).
The devices may be specified by numerical ID or the keyword “any”, which uses the next available tunnel device.
If remote_tun is not specified, it defaults to “any”. See also the Tunnel and TunnelDevice directives in
ssh_config(5).
If the Tunnel directive is unset, it will be set to the default tunnel mode, which is “point-to-point”. If a
different Tunnel forwarding mode it desired, then it should be specified before -w.
-X Enables X11 forwarding. This can also be specified on a per-host basis in a configuration file.
X11 forwarding should be enabled with caution. Users with the ability to bypass file permissions on the remote
host (for the user's X authorization database) can access the local X11 display through the forwarded connection.
An attacker may then be able to perform activities such as keystroke monitoring.
For this reason, X11 forwarding is subjected to X11 SECURITY extension restrictions by default. Refer to the ssh
-Y option and the ForwardX11Trusted directive in ssh_config(5) for more information.
-x Disables X11 forwarding.
-Y Enables trusted X11 forwarding. Trusted X11 forwardings are not subjected to the X11 SECURITY extension con‐
trols.
-y Send log information using the syslog(3) system module. By default this information is sent to stderr.
ssh may additionally obtain configuration data from a per-user configuration file and a system-wide configuration file.
The file format and configuration options are described in ssh_config(5).
AUTHENTICATION
The OpenSSH SSH client supports SSH protocol 2.
The methods available for authentication are: GSSAPI-based authentication, host-based authentication, public key authen‐
tication, keyboard-interactive authentication, and password authentication. Authentication methods are tried in the or‐
der specified above, though PreferredAuthentications can be used to change the default order.
Host-based authentication works as follows: If the machine the user logs in from is listed in /etc/hosts.equiv or
/etc/ssh/shosts.equiv on the remote machine, the user is non-root and the user names are the same on both sides, or if
the files ~/.rhosts or ~/.shosts exist in the user's home directory on the remote machine and contain a line containing
the name of the client machine and the name of the user on that machine, the user is considered for login. Additionally,
the server must be able to verify the client's host key (see the description of /etc/ssh/ssh_known_hosts and
~/.ssh/known_hosts, below) for login to be permitted. This authentication method closes security holes due to IP spoof‐
ing, DNS spoofing, and routing spoofing. [Note to the administrator: /etc/hosts.equiv, ~/.rhosts, and the rlogin/rsh
protocol in general, are inherently insecure and should be disabled if security is desired.]
Public key authentication works as follows: The scheme is based on public-key cryptography, using cryptosystems where en‐
cryption and decryption are done using separate keys, and it is unfeasible to derive the decryption key from the encryp‐
tion key. The idea is that each user creates a public/private key pair for authentication purposes. The server knows
the public key, and only the user knows the private key. ssh implements public key authentication protocol automati‐
cally, using one of the DSA, ECDSA, Ed25519 or RSA algorithms. The HISTORY section of ssl(8) contains a brief discussion
of the DSA and RSA algorithms.
The file ~/.ssh/authorized_keys lists the public keys that are permitted for logging in. When the user logs in, the ssh
program tells the server which key pair it would like to use for authentication. The client proves that it has access to
the private key and the server checks that the corresponding public key is authorized to accept the account.
The server may inform the client of errors that prevented public key authentication from succeeding after authentication
completes using a different method. These may be viewed by increasing the LogLevel to DEBUG or higher (e.g. by using the
-v flag).
The user creates their key pair by running ssh-keygen(1). This stores the private key in ~/.ssh/id_dsa (DSA),
~/.ssh/id_ecdsa (ECDSA), ~/.ssh/id_ecdsa_sk (authenticator-hosted ECDSA), ~/.ssh/id_ed25519 (Ed25519),
~/.ssh/id_ed25519_sk (authenticator-hosted Ed25519), or ~/.ssh/id_rsa (RSA) and stores the public key in
~/.ssh/id_dsa.pub (DSA), ~/.ssh/id_ecdsa.pub (ECDSA), ~/.ssh/id_ecdsa_sk.pub (authenticator-hosted ECDSA),
~/.ssh/id_ed25519.pub (Ed25519), ~/.ssh/id_ed25519_sk.pub (authenticator-hosted Ed25519), or ~/.ssh/id_rsa.pub (RSA) in
the user's home directory. The user should then copy the public key to ~/.ssh/authorized_keys in their home directory on
the remote machine. The authorized_keys file corresponds to the conventional ~/.rhosts file, and has one key per line,
though the lines can be very long. After this, the user can log in without giving the password.
A variation on public key authentication is available in the form of certificate authentication: instead of a set of pub‐
lic/private keys, signed certificates are used. This has the advantage that a single trusted certification authority can
be used in place of many public/private keys. See the CERTIFICATES section of ssh-keygen(1) for more information.
The most convenient way to use public key or certificate authentication may be with an authentication agent. See
ssh-agent(1) and (optionally) the AddKeysToAgent directive in ssh_config(5) for more information.
Keyboard-interactive authentication works as follows: The server sends an arbitrary "challenge" text and prompts for a
response, possibly multiple times. Examples of keyboard-interactive authentication include BSD Authentication (see
login.conf(5)) and PAM (some non-OpenBSD systems).
Finally, if other authentication methods fail, ssh prompts the user for a password. The password is sent to the remote
host for checking; however, since all communications are encrypted, the password cannot be seen by someone listening on
the network.
ssh automatically maintains and checks a database containing identification for all hosts it has ever been used with.
Host keys are stored in ~/.ssh/known_hosts in the user's home directory. Additionally, the file /etc/ssh/ssh_known_hosts
is automatically checked for known hosts. Any new hosts are automatically added to the user's file. If a host's identi‐
fication ever changes, ssh warns about this and disables password authentication to prevent server spoofing or man-in-
the-middle attacks, which could otherwise be used to circumvent the encryption. The StrictHostKeyChecking option can be
used to control logins to machines whose host key is not known or has changed.
When the user's identity has been accepted by the server, the server either executes the given command in a non-interac‐
tive session or, if no command has been specified, logs into the machine and gives the user a normal shell as an interac‐
tive session. All communication with the remote command or shell will be automatically encrypted.
If an interactive session is requested, ssh by default will only request a pseudo-terminal (pty) for interactive sessions
when the client has one. The flags -T and -t can be used to override this behaviour.
If a pseudo-terminal has been allocated, the user may use the escape characters noted below.
If no pseudo-terminal has been allocated, the session is transparent and can be used to reliably transfer binary data.
On most systems, setting the escape character to “none” will also make the session transparent even if a tty is used.
The session terminates when the command or shell on the remote machine exits and all X11 and TCP connections have been
closed.
ESCAPE CHARACTERS
When a pseudo-terminal has been requested, ssh supports a number of functions through the use of an escape character.
A single tilde character can be sent as ~~ or by following the tilde by a character other than those described below.
The escape character must always follow a newline to be interpreted as special. The escape character can be changed in
configuration files using the EscapeChar configuration directive or on the command line by the -e option.
The supported escapes (assuming the default ‘~’) are:
~. Disconnect.
~^Z Background ssh.
~# List forwarded connections.
~& Background ssh at logout when waiting for forwarded connection / X11 sessions to terminate.
~? Display a list of escape characters.
~B Send a BREAK to the remote system (only useful if the peer supports it).
~C Open command line. Currently this allows the addition of port forwardings using the -L, -R and -D options (see
above). It also allows the cancellation of existing port-forwardings with -KL[bind_address:]port for local,
-KR[bind_address:]port for remote and -KD[bind_address:]port for dynamic port-forwardings. !command allows the
user to execute a local command if the PermitLocalCommand option is enabled in ssh_config(5). Basic help is
available, using the -h option.
~R Request rekeying of the connection (only useful if the peer supports it).
~V Decrease the verbosity (LogLevel) when errors are being written to stderr.
~v Increase the verbosity (LogLevel) when errors are being written to stderr.
TCP FORWARDING
Forwarding of arbitrary TCP connections over a secure channel can be specified either on the command line or in a config‐
uration file. One possible application of TCP forwarding is a secure connection to a mail server; another is going
through firewalls.
In the example below, we look at encrypting communication for an IRC client, even though the IRC server it connects to
does not directly support encrypted communication. This works as follows: the user connects to the remote host using
ssh, specifying the ports to be used to forward the connection. After that it is possible to start the program locally,
and ssh will encrypt and forward the connection to the remote server.
The following example tunnels an IRC session from the client to an IRC server at “server.example.com”, joining channel
“#users”, nickname “pinky”, using the standard IRC port, 6667:
$ ssh -f -L 6667:localhost:6667 server.example.com sleep 10
$ irc -c '#users' pinky IRC/127.0.0.1
The -f option backgrounds ssh and the remote command “sleep 10” is specified to allow an amount of time (10 seconds, in
the example) to start the program which is going to use the tunnel. If no connections are made within the time speci‐
fied, ssh will exit.
X11 FORWARDING
If the ForwardX11 variable is set to “yes” (or see the description of the -X, -x, and -Y options above) and the user is
using X11 (the DISPLAY environment variable is set), the connection to the X11 display is automatically forwarded to the
remote side in such a way that any X11 programs started from the shell (or command) will go through the encrypted chan‐
nel, and the connection to the real X server will be made from the local machine. The user should not manually set
DISPLAY. Forwarding of X11 connections can be configured on the command line or in configuration files.
The DISPLAY value set by ssh will point to the server machine, but with a display number greater than zero. This is nor‐
mal, and happens because ssh creates a “proxy” X server on the server machine for forwarding the connections over the en‐
crypted channel.
ssh will also automatically set up Xauthority data on the server machine. For this purpose, it will generate a random
authorization cookie, store it in Xauthority on the server, and verify that any forwarded connections carry this cookie
and replace it by the real cookie when the connection is opened. The real authentication cookie is never sent to the
server machine (and no cookies are sent in the plain).
If the ForwardAgent variable is set to “yes” (or see the description of the -A and -a options above) and the user is us‐
ing an authentication agent, the connection to the agent is automatically forwarded to the remote side.
VERIFYING HOST KEYS
When connecting to a server for the first time, a fingerprint of the server's public key is presented to the user (unless
the option StrictHostKeyChecking has been disabled). Fingerprints can be determined using ssh-keygen(1):
$ ssh-keygen -l -f /etc/ssh/ssh_host_rsa_key
If the fingerprint is already known, it can be matched and the key can be accepted or rejected. If only legacy (MD5)
fingerprints for the server are available, the ssh-keygen(1) -E option may be used to downgrade the fingerprint algorithm
to match.
Because of the difficulty of comparing host keys just by looking at fingerprint strings, there is also support to compare
host keys visually, using random art. By setting the VisualHostKey option to “yes”, a small ASCII graphic gets displayed
on every login to a server, no matter if the session itself is interactive or not. By learning the pattern a known
server produces, a user can easily find out that the host key has changed when a completely different pattern is dis‐
played. Because these patterns are not unambiguous however, a pattern that looks similar to the pattern remembered only
gives a good probability that the host key is the same, not guaranteed proof.
To get a listing of the fingerprints along with their random art for all known hosts, the following command line can be
used:
$ ssh-keygen -lv -f ~/.ssh/known_hosts
If the fingerprint is unknown, an alternative method of verification is available: SSH fingerprints verified by DNS. An
additional resource record (RR), SSHFP, is added to a zonefile and the connecting client is able to match the fingerprint
with that of the key presented.
In this example, we are connecting a client to a server, “host.example.com”. The SSHFP resource records should first be
added to the zonefile for host.example.com:
$ ssh-keygen -r host.example.com.
The output lines will have to be added to the zonefile. To check that the zone is answering fingerprint queries:
$ dig -t SSHFP host.example.com
Finally the client connects:
$ ssh -o "VerifyHostKeyDNS ask" host.example.com
[...]
Matching host key fingerprint found in DNS.
Are you sure you want to continue connecting (yes/no)?
See the VerifyHostKeyDNS option in ssh_config(5) for more information.
SSH-BASED VIRTUAL PRIVATE NETWORKS
ssh contains support for Virtual Private Network (VPN) tunnelling using the tun(4) network pseudo-device, allowing two
networks to be joined securely. The sshd_config(5) configuration option PermitTunnel controls whether the server sup‐
ports this, and at what level (layer 2 or 3 traffic).
The following example would connect client network 10.0.50.0/24 with remote network 10.0.99.0/24 using a point-to-point
connection from 10.1.1.1 to 10.1.1.2, provided that the SSH server running on the gateway to the remote network, at
192.168.1.15, allows it.
On the client:
# ssh -f -w 0:1 192.168.1.15 true
# ifconfig tun0 10.1.1.1 10.1.1.2 netmask 255.255.255.252
# route add 10.0.99.0/24 10.1.1.2
On the server:
# ifconfig tun1 10.1.1.2 10.1.1.1 netmask 255.255.255.252
# route add 10.0.50.0/24 10.1.1.1
Client access may be more finely tuned via the /root/.ssh/authorized_keys file (see below) and the PermitRootLogin server
option. The following entry would permit connections on tun(4) device 1 from user “jane” and on tun device 2 from user
“john”, if PermitRootLogin is set to “forced-commands-only”:
tunnel="1",command="sh /etc/netstart tun1" ssh-rsa ... jane
tunnel="2",command="sh /etc/netstart tun2" ssh-rsa ... john
Since an SSH-based setup entails a fair amount of overhead, it may be more suited to temporary setups, such as for wire‐
less VPNs. More permanent VPNs are better provided by tools such as ipsecctl(8) and isakmpd(8).
ENVIRONMENT
ssh will normally set the following environment variables:
DISPLAY The DISPLAY variable indicates the location of the X11 server. It is automatically set by ssh to
point to a value of the form “hostname:n”, where “hostname” indicates the host where the shell
runs, and ‘n’ is an integer ≥ 1. ssh uses this special value to forward X11 connections over the
secure channel. The user should normally not set DISPLAY explicitly, as that will render the X11
connection insecure (and will require the user to manually copy any required authorization cook‐
ies).
HOME Set to the path of the user's home directory.
LOGNAME Synonym for USER; set for compatibility with systems that use this variable.
MAIL Set to the path of the user's mailbox.
PATH Set to the default PATH, as specified when compiling ssh.
SSH_ASKPASS If ssh needs a passphrase, it will read the passphrase from the current terminal if it was run from
a terminal. If ssh does not have a terminal associated with it but DISPLAY and SSH_ASKPASS are
set, it will execute the program specified by SSH_ASKPASS and open an X11 window to read the
passphrase. This is particularly useful when calling ssh from a .xsession or related script.
(Note that on some machines it may be necessary to redirect the input from /dev/null to make this
work.)
SSH_ASKPASS_REQUIRE Allows further control over the use of an askpass program. If this variable is set to “never” then
ssh will never attempt to use one. If it is set to “prefer”, then ssh will prefer to use the
askpass program instead of the TTY when requesting passwords. Finally, if the variable is set to
“force”, then the askpass program will be used for all passphrase input regardless of whether
DISPLAY is set.
SSH_AUTH_SOCK Identifies the path of a Unix-domain socket used to communicate with the agent.
SSH_CONNECTION Identifies the client and server ends of the connection. The variable contains four space-sepa‐
rated values: client IP address, client port number, server IP address, and server port number.
SSH_ORIGINAL_COMMAND This variable contains the original command line if a forced command is executed. It can be used
to extract the original arguments.
SSH_TTY This is set to the name of the tty (path to the device) associated with the current shell or com‐
mand. If the current session has no tty, this variable is not set.
SSH_TUNNEL Optionally set by sshd(8) to contain the interface names assigned if tunnel forwarding was re‐
quested by the client.
SSH_USER_AUTH Optionally set by sshd(8), this variable may contain a pathname to a file that lists the authenti‐
cation methods successfully used when the session was established, including any public keys that
were used.
TZ This variable is set to indicate the present time zone if it was set when the daemon was started
(i.e. the daemon passes the value on to new connections).
USER Set to the name of the user logging in.
Additionally, ssh reads ~/.ssh/environment, and adds lines of the format “VARNAME=value” to the environment if the file
exists and users are allowed to change their environment. For more information, see the PermitUserEnvironment option in
sshd_config(5).
FILES
~/.rhosts
This file is used for host-based authentication (see above). On some machines this file may need to be world-
readable if the user's home directory is on an NFS partition, because sshd(8) reads it as root. Additionally,
this file must be owned by the user, and must not have write permissions for anyone else. The recommended per‐
mission for most machines is read/write for the user, and not accessible by others.
~/.shosts
This file is used in exactly the same way as .rhosts, but allows host-based authentication without permitting lo‐
gin with rlogin/rsh.
~/.ssh/
This directory is the default location for all user-specific configuration and authentication information. There
is no general requirement to keep the entire contents of this directory secret, but the recommended permissions
are read/write/execute for the user, and not accessible by others.
~/.ssh/authorized_keys
Lists the public keys (DSA, ECDSA, Ed25519, RSA) that can be used for logging in as this user. The format of
this file is described in the sshd(8) manual page. This file is not highly sensitive, but the recommended per‐
missions are read/write for the user, and not accessible by others.
~/.ssh/config
This is the per-user configuration file. The file format and configuration options are described in
ssh_config(5). Because of the potential for abuse, this file must have strict permissions: read/write for the
user, and not writable by others.
~/.ssh/environment
Contains additional definitions for environment variables; see “ENVIRONMENT”, above.
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the private key for authentication. These files contain sensitive data and should be readable by the
user but not accessible by others (read/write/execute). ssh will simply ignore a private key file if it is ac‐
cessible by others. It is possible to specify a passphrase when generating the key which will be used to encrypt
the sensitive part of this file using AES-128.
~/.ssh/id_dsa.pub
~/.ssh/id_ecdsa.pub
~/.ssh/id_ecdsa_sk.pub
~/.ssh/id_ed25519.pub
~/.ssh/id_ed25519_sk.pub
~/.ssh/id_rsa.pub
Contains the public key for authentication. These files are not sensitive and can (but need not) be readable by
anyone.
~/.ssh/known_hosts
Contains a list of host keys for all hosts the user has logged into that are not already in the systemwide list
of known host keys. See sshd(8) for further details of the format of this file.
~/.ssh/rc
Commands in this file are executed by ssh when the user logs in, just before the user's shell (or command) is
started. See the sshd(8) manual page for more information.
/etc/hosts.equiv
This file is for host-based authentication (see above). It should only be writable by root.
/etc/ssh/shosts.equiv
This file is used in exactly the same way as hosts.equiv, but allows host-based authentication without permitting
login with rlogin/rsh.
/etc/ssh/ssh_config
Systemwide configuration file. The file format and configuration options are described in ssh_config(5).
/etc/ssh/ssh_host_key
/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys and are used for host-based authentication.
/etc/ssh/ssh_known_hosts
Systemwide list of known host keys. This file should be prepared by the system administrator to contain the pub‐
/etc/ssh/ssh_host_dsa_key
/etc/ssh/ssh_host_ecdsa_key
/etc/ssh/ssh_host_ed25519_key
/etc/ssh/ssh_host_rsa_key
These files contain the private parts of the host keys and are used for host-based authentication.
/etc/ssh/ssh_known_hosts
Systemwide list of known host keys. This file should be prepared by the system administrator to contain the pub‐
lic host keys of all machines in the organization. It should be world-readable. See sshd(8) for further details
of the format of this file.
/etc/ssh/sshrc
Commands in this file are executed by ssh when the user logs in, just before the user's shell (or command) is
started. See the sshd(8) manual page for more information.
EXIT STATUS
ssh exits with the exit status of the remote command or with 255 if an error occurred.
SEE ALSO
scp(1), sftp(1), ssh-add(1), ssh-agent(1), ssh-keygen(1), ssh-keyscan(1), tun(4), ssh_config(5), ssh-keysign(8), sshd(8)
STANDARDS
S. Lehtinen and C. Lonvick, The Secure Shell (SSH) Protocol Assigned Numbers, RFC 4250, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Protocol Architecture, RFC 4251, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Authentication Protocol, RFC 4252, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Transport Layer Protocol, RFC 4253, January 2006.
T. Ylonen and C. Lonvick, The Secure Shell (SSH) Connection Protocol, RFC 4254, January 2006.
J. Schlyter and W. Griffin, Using DNS to Securely Publish Secure Shell (SSH) Key Fingerprints, RFC 4255, January 2006.
F. Cusack and M. Forssen, Generic Message Exchange Authentication for the Secure Shell Protocol (SSH), RFC 4256, January
2006.
J. Galbraith and P. Remaker, The Secure Shell (SSH) Session Channel Break Extension, RFC 4335, January 2006.
M. Bellare, T. Kohno, and C. Namprempre, The Secure Shell (SSH) Transport Layer Encryption Modes, RFC 4344, January 2006.
B. Harris, Improved Arcfour Modes for the Secure Shell (SSH) Transport Layer Protocol, RFC 4345, January 2006.
M. Friedl, N. Provos, and W. Simpson, Diffie-Hellman Group Exchange for the Secure Shell (SSH) Transport Layer Protocol,
RFC 4419, March 2006.
J. Galbraith and R. Thayer, The Secure Shell (SSH) Public Key File Format, RFC 4716, November 2006.
D. Stebila and J. Green, Elliptic Curve Algorithm Integration in the Secure Shell Transport Layer, RFC 5656, December
2009.
A. Perrig and D. Song, Hash Visualization: a New Technique to improve Real-World Security, 1999, International Workshop
on Cryptographic Techniques and E-Commerce (CrypTEC '99).
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus
Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus
Friedl contributed the support for SSH protocol versions 1.5 and 2.0.
GNU July 23, 2023 SSH(1)
$ man ssh-keygen
SSH-KEYGEN(1) General Commands Manual SSH-KEYGEN(1)
NAME
ssh-keygen — OpenSSH authentication key utility
SYNOPSIS
ssh-keygen [-q] [-a rounds] [-b bits] [-C comment] [-f output_keyfile] [-m format] [-N new_passphrase] [-O option]
[-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa] [-w provider] [-Z cipher]
ssh-keygen -p [-a rounds] [-f keyfile] [-m format] [-N new_passphrase] [-P old_passphrase] [-Z cipher]
ssh-keygen -i [-f input_keyfile] [-m key_format]
ssh-keygen -e [-f input_keyfile] [-m key_format]
ssh-keygen -y [-f input_keyfile]
ssh-keygen -c [-a rounds] [-C comment] [-f keyfile] [-P passphrase]
ssh-keygen -l [-v] [-E fingerprint_hash] [-f input_keyfile]
ssh-keygen -B [-f input_keyfile]
ssh-keygen -D pkcs11
ssh-keygen -F hostname [-lv] [-f known_hosts_file]
ssh-keygen -H [-f known_hosts_file]
ssh-keygen -K [-a rounds] [-w provider]
ssh-keygen -R hostname [-f known_hosts_file]
ssh-keygen -r hostname [-g] [-f input_keyfile]
ssh-keygen -M generate [-O option] output_file
ssh-keygen -M screen [-f input_file] [-O option] output_file
ssh-keygen -I certificate_identity -s ca_key [-hU] [-D pkcs11_provider] [-n principals] [-O option]
[-V validity_interval] [-z serial_number] file ...
ssh-keygen -L [-f input_keyfile]
ssh-keygen -A [-a rounds] [-f prefix_path]
ssh-keygen -k -f krl_file [-u] [-s ca_public] [-z version_number] file ...
ssh-keygen -Q [-l] -f krl_file file ...
ssh-keygen -Y find-principals [-O option] -s signature_file -f allowed_signers_file
ssh-keygen -Y match-principals -I signer_identity -f allowed_signers_file
ssh-keygen -Y check-novalidate [-O option] -n namespace -s signature_file
ssh-keygen -Y sign [-O option] -f key_file -n namespace file ...
ssh-keygen -Y verify [-O option] -f allowed_signers_file -I signer_identity -n namespace -s signature_file
[-r revocation_file]
DESCRIPTION
ssh-keygen generates, manages and converts authentication keys for ssh(1). ssh-keygen can create keys for use by SSH
protocol version 2.
The type of key to be generated is specified with the -t option. If invoked without any arguments, ssh-keygen will gen‐
erate an Ed25519 key.
ssh-keygen is also used to generate groups for use in Diffie-Hellman group exchange (DH-GEX). See the “MODULI
GENERATION” section for details.
Finally, ssh-keygen can be used to generate and update Key Revocation Lists, and to test whether given keys have been re‐
voked by one. See the “KEY REVOCATION LISTS” section for details.
Normally each user wishing to use SSH with public key authentication runs this once to create the authentication key in
~/.ssh/id_dsa, ~/.ssh/id_ecdsa, ~/.ssh/id_ecdsa_sk, ~/.ssh/id_ed25519, ~/.ssh/id_ed25519_sk or ~/.ssh/id_rsa. Addition‐
ally, the system administrator may use this to generate host keys, as seen in /etc/rc.
Normally this program generates the key and asks for a file in which to store the private key. The public key is stored
in a file with the same name but “.pub” appended. The program also asks for a passphrase. The passphrase may be empty
to indicate no passphrase (host keys must have an empty passphrase), or it may be a string of arbitrary length. A
passphrase is similar to a password, except it can be a phrase with a series of words, punctuation, numbers, whitespace,
or any string of characters you want. Good passphrases are 10-30 characters long, are not simple sentences or otherwise
easily guessable (English prose has only 1-2 bits of entropy per character, and provides very bad passphrases), and con‐
tain a mix of upper and lowercase letters, numbers, and non-alphanumeric characters. The passphrase can be changed later
by using the -p option.
There is no way to recover a lost passphrase. If the passphrase is lost or forgotten, a new key must be generated and
the corresponding public key copied to other machines.
ssh-keygen will by default write keys in an OpenSSH-specific format. This format is preferred as it offers better pro‐
tection for keys at rest as well as allowing storage of key comments within the private key file itself. The key comment
may be useful to help identify the key. The comment is initialized to “user@host” when the key is created, but can be
changed using the -c option.
It is still possible for ssh-keygen to write the previously-used PEM format private keys using the -m flag. This may be
used when generating new keys, and existing new-format keys may be converted using this option in conjunction with the -p
(change passphrase) flag.
After a key is generated, ssh-keygen will ask where the keys should be placed to be activated.
The options are as follows:
-A Generate host keys of all default key types (rsa, ecdsa, and ed25519) if they do not already exist. The host
keys are generated with the default key file path, an empty passphrase, default bits for the key type, and de‐
fault comment. If -f has also been specified, its argument is used as a prefix to the default path for the re‐
sulting host key files. This is used by /etc/rc to generate new host keys.
-a rounds
When saving a private key, this option specifies the number of KDF (key derivation function, currently
bcrypt_pbkdf(3)) rounds used. Higher numbers result in slower passphrase verification and increased resistance
to brute-force password cracking (should the keys be stolen). The default is 16 rounds.
-B Show the bubblebabble digest of specified private or public key file.
-b bits
Specifies the number of bits in the key to create. For RSA keys, the minimum size is 1024 bits and the default
is 3072 bits. Generally, 3072 bits is considered sufficient. DSA keys must be exactly 1024 bits as specified by
FIPS 186-2. For ECDSA keys, the -b flag determines the key length by selecting from one of three elliptic curve
sizes: 256, 384 or 521 bits. Attempting to use bit lengths other than these three values for ECDSA keys will
fail. ECDSA-SK, Ed25519 and Ed25519-SK keys have a fixed length and the -b flag will be ignored.
-C comment
Provides a new comment.
-c Requests changing the comment in the private and public key files. The program will prompt for the file contain‐
ing the private keys, for the passphrase if the key has one, and for the new comment.
-D pkcs11
Download the public keys provided by the PKCS#11 shared library pkcs11. When used in combination with -s, this
option indicates that a CA key resides in a PKCS#11 token (see the “CERTIFICATES” section for details).
-E fingerprint_hash
Specifies the hash algorithm used when displaying key fingerprints. Valid options are: “md5” and “sha256”. The
default is “sha256”.
-e This option will read a private or public OpenSSH key file and print to stdout a public key in one of the formats
specified by the -m option. The default export format is “RFC4716”. This option allows exporting OpenSSH keys
for use by other programs, including several commercial SSH implementations.
-F hostname | [hostname]:port
Search for the specified hostname (with optional port number) in a known_hosts file, listing any occurrences
found. This option is useful to find hashed host names or addresses and may also be used in conjunction with the
-H option to print found keys in a hashed format.
-f filename
Specifies the filename of the key file.
-g Use generic DNS format when printing fingerprint resource records using the -r command.
-H Hash a known_hosts file. This replaces all hostnames and addresses with hashed representations within the speci‐
fied file; the original content is moved to a file with a .old suffix. These hashes may be used normally by ssh
and sshd, but they do not reveal identifying information should the file's contents be disclosed. This option
will not modify existing hashed hostnames and is therefore safe to use on files that mix hashed and non-hashed
names.
-h When signing a key, create a host certificate instead of a user certificate. See the “CERTIFICATES” section for
details.
-I certificate_identity
Specify the key identity when signing a public key. See the “CERTIFICATES” section for details.
-i This option will read an unencrypted private (or public) key file in the format specified by the -m option and
print an OpenSSH compatible private (or public) key to stdout. This option allows importing keys from other
software, including several commercial SSH implementations. The default import format is “RFC4716”.
-K Download resident keys from a FIDO authenticator. Public and private key files will be written to the current
directory for each downloaded key. If multiple FIDO authenticators are attached, keys will be downloaded from
the first touched authenticator. See the “FIDO AUTHENTICATOR” section for more information.
-k Generate a KRL file. In this mode, ssh-keygen will generate a KRL file at the location specified via the -f flag
that revokes every key or certificate presented on the command line. Keys/certificates to be revoked may be
specified by public key file or using the format described in the “KEY REVOCATION LISTS” section.
-L Prints the contents of one or more certificates.
-l Show fingerprint of specified public key file. For RSA and DSA keys ssh-keygen tries to find the matching public
key file and prints its fingerprint. If combined with -v, a visual ASCII art representation of the key is sup‐
plied with the fingerprint.
-M generate
Generate candidate Diffie-Hellman Group Exchange (DH-GEX) parameters for eventual use by the
‘diffie-hellman-group-exchange-*’ key exchange methods. The numbers generated by this operation must be further
screened before use. See the “MODULI GENERATION” section for more information.
-M screen
Screen candidate parameters for Diffie-Hellman Group Exchange. This will accept a list of candidate numbers and
test that they are safe (Sophie Germain) primes with acceptable group generators. The results of this operation
may be added to the /etc/ssh/moduli file. See the “MODULI GENERATION” section for more information.
-m key_format
Specify a key format for key generation, the -i (import), -e (export) conversion options, and the -p change
passphrase operation. The latter may be used to convert between OpenSSH private key and PEM private key formats.
The supported key formats are: “RFC4716” (RFC 4716/SSH2 public or private key), “PKCS8” (PKCS8 public or private
key) or “PEM” (PEM public key). By default OpenSSH will write newly-generated private keys in its own format,
but when converting public keys for export the default format is “RFC4716”. Setting a format of “PEM” when gen‐
erating or updating a supported private key type will cause the key to be stored in the legacy PEM private key
format.
-N new_passphrase
Provides the new passphrase.
-n principals
Specify one or more principals (user or host names) to be included in a certificate when signing a key. Multiple
principals may be specified, separated by commas. See the “CERTIFICATES” section for details.
-O option
Specify a key/value option. These are specific to the operation that ssh-keygen has been requested to perform.
When signing certificates, one of the options listed in the “CERTIFICATES” section may be specified here.
When performing moduli generation or screening, one of the options listed in the “MODULI GENERATION” section may
be specified.
When generating FIDO authenticator-backed keys, the options listed in the “FIDO AUTHENTICATOR” section may be
specified.
When performing signature-related options using the -Y flag, the following options are accepted:
hashalg=algorithm
Selects the hash algorithm to use for hashing the message to be signed. Valid algorithms are “sha256”
and “sha512.” The default is “sha512.”
print-pubkey
Print the full public key to standard output after signature verification.
verify-time=timestamp
Specifies a time to use when validating signatures instead of the current time. The time may be speci‐
fied as a date or time in the YYYYMMDD[Z] or in YYYYMMDDHHMM[SS][Z] formats. Dates and times will be in‐
terpreted in the current system time zone unless suffixed with a Z character, which causes them to be in‐
terpreted in the UTC time zone.
When generating SSHFP DNS records from public keys using the -r flag, the following options are accepted:
hashalg=algorithm
Selects a hash algorithm to use when printing SSHFP records using the -D flag. Valid algorithms are
“sha1” and “sha256”. The default is to print both.
The -O option may be specified multiple times.
-P passphrase
Provides the (old) passphrase.
-p Requests changing the passphrase of a private key file instead of creating a new private key. The program will
prompt for the file containing the private key, for the old passphrase, and twice for the new passphrase.
-Q Test whether keys have been revoked in a KRL. If the -l option is also specified then the contents of the KRL
will be printed.
-q Silence ssh-keygen.
-R hostname | [hostname]:port
Removes all keys belonging to the specified hostname (with optional port number) from a known_hosts file. This
option is useful to delete hashed hosts (see the -H option above).
-r hostname
Print the SSHFP fingerprint resource record named hostname for the specified public key file.
-s ca_key
Certify (sign) a public key using the specified CA key. See the “CERTIFICATES” section for details.
When generating a KRL, -s specifies a path to a CA public key file used to revoke certificates directly by key ID
or serial number. See the “KEY REVOCATION LISTS” section for details.
-t dsa | ecdsa | ecdsa-sk | ed25519 | ed25519-sk | rsa
Specifies the type of key to create. The possible values are “dsa”, “ecdsa”, “ecdsa-sk”, “ed25519”,
“ed25519-sk”, or “rsa”.
This flag may also be used to specify the desired signature type when signing certificates using an RSA CA key.
The available RSA signature variants are “ssh-rsa” (SHA1 signatures, not recommended), “rsa-sha2-256”, and
“rsa-sha2-512” (the default).
-U When used in combination with -s or -Y sign, this option indicates that a CA key resides in a ssh-agent(1). See
the “CERTIFICATES” section for more information.
-u Update a KRL. When specified with -k, keys listed via the command line are added to the existing KRL rather than
a new KRL being created.
-V validity_interval
Specify a validity interval when signing a certificate. A validity interval may consist of a single time, indi‐
cating that the certificate is valid beginning now and expiring at that time, or may consist of two times sepa‐
rated by a colon to indicate an explicit time interval.
The start time may be specified as:
• The string “always” to indicate the certificate has no specified start time.
• A date or time in the system time zone formatted as YYYYMMDD or YYYYMMDDHHMM[SS].
• A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z.
• A relative time before the current system time consisting of a minus sign followed by an interval in the for‐
mat described in the TIME FORMATS section of sshd_config(5).
• A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal number beginning with “0x”.
The end time may be specified similarly to the start time:
• The string “forever” to indicate the certificate has no specified end time.
• A date or time in the system time zone formatted as YYYYMMDD or YYYYMMDDHHMM[SS].
• A date or time in the UTC time zone as YYYYMMDDZ or YYYYMMDDHHMM[SS]Z.
• A relative time after the current system time consisting of a plus sign followed by an interval in the format
described in the TIME FORMATS section of sshd_config(5).
• A raw seconds since epoch (Jan 1 1970 00:00:00 UTC) as a hexadecimal number beginning with “0x”.
For example:
+52w1d Valid from now to 52 weeks and one day from now.
-4w:+4w
Valid from four weeks ago to four weeks from now.
20100101123000:20110101123000
Valid from 12:30 PM, January 1st, 2010 to 12:30 PM, January 1st, 2011.
20100101123000Z:20110101123000Z
Similar, but interpreted in the UTC time zone rather than the system time zone.
-1d:20110101
Valid from yesterday to midnight, January 1st, 2011.
0x1:0x2000000000
Valid from roughly early 1970 to May 2033.
-1m:forever
Valid from one minute ago and never expiring.
-v Verbose mode. Causes ssh-keygen to print debugging messages about its progress. This is helpful for debugging
moduli generation. Multiple -v options increase the verbosity. The maximum is 3.
-w provider
Specifies a path to a library that will be used when creating FIDO authenticator-hosted keys, overriding the de‐
fault of using the internal USB HID support.
-Y find-principals
Find the principal(s) associated with the public key of a signature, provided using the -s flag in an authorized
signers file provided using the -f flag. The format of the allowed signers file is documented in the “ALLOWED
SIGNERS” section below. If one or more matching principals are found, they are returned on standard output.
-Y match-principals
Find principal matching the principal name provided using the -I flag in the authorized signers file specified
using the -f flag. If one or more matching principals are found, they are returned on standard output.
-Y check-novalidate
Checks that a signature generated using ssh-keygen -Y sign has a valid structure. This does not validate if a
signature comes from an authorized signer. When testing a signature, ssh-keygen accepts a message on standard
input and a signature namespace using -n. A file containing the corresponding signature must also be supplied
using the -s flag. Successful testing of the signature is signalled by ssh-keygen returning a zero exit status.
-Y sign
Cryptographically sign a file or some data using an SSH key. When signing, ssh-keygen accepts zero or more files
to sign on the command-line - if no files are specified then ssh-keygen will sign data presented on standard in‐
put. Signatures are written to the path of the input file with “.sig” appended, or to standard output if the
message to be signed was read from standard input.
The key used for signing is specified using the -f option and may refer to either a private key, or a public key
with the private half available via ssh-agent(1). An additional signature namespace, used to prevent signature
confusion across different domains of use (e.g. file signing vs email signing) must be provided via the -n flag.
Namespaces are arbitrary strings, and may include: “file” for file signing, “email” for email signing. For cus‐
tom uses, it is recommended to use names following a NAMESPACE@YOUR.DOMAIN pattern to generate unambiguous name‐
spaces.
-Y verify
Request to verify a signature generated using ssh-keygen -Y sign as described above. When verifying a signature,
ssh-keygen accepts a message on standard input and a signature namespace using -n. A file containing the corre‐
sponding signature must also be supplied using the -s flag, along with the identity of the signer using -I and a
list of allowed signers via the -f flag. The format of the allowed signers file is documented in the “ALLOWED
SIGNERS” section below. A file containing revoked keys can be passed using the -r flag. The revocation file may
be a KRL or a one-per-line list of public keys. Successful verification by an authorized signer is signalled by
ssh-keygen returning a zero exit status.
-y This option will read a private OpenSSH format file and print an OpenSSH public key to stdout.
-Z cipher
Specifies the cipher to use for encryption when writing an OpenSSH-format private key file. The list of avail‐
able ciphers may be obtained using "ssh -Q cipher". The default is “aes256-ctr”.
-z serial_number
Specifies a serial number to be embedded in the certificate to distinguish this certificate from others from the
same CA. If the serial_number is prefixed with a ‘+’ character, then the serial number will be incremented for
each certificate signed on a single command-line. The default serial number is zero.
When generating a KRL, the -z flag is used to specify a KRL version number.
MODULI GENERATION
ssh-keygen may be used to generate groups for the Diffie-Hellman Group Exchange (DH-GEX) protocol. Generating these
groups is a two-step process: first, candidate primes are generated using a fast, but memory intensive process. These
candidate primes are then tested for suitability (a CPU-intensive process).
Generation of primes is performed using the -M generate option. The desired length of the primes may be specified by the
# ssh-keygen -M generate -O bits=2048 moduli-2048.candidates
By default, the search for primes begins at a random point in the desired length range. This may be overridden using the
-O start option, which specifies a different start point (in hex).
Once a set of candidates have been generated, they must be screened for suitability. This may be performed using the -M
screen option. In this mode ssh-keygen will read candidates from standard input (or a file specified using the -f op‐
tion). For example:
# ssh-keygen -M screen -f moduli-2048.candidates moduli-2048
By default, each candidate will be subjected to 100 primality tests. This may be overridden using the -O prime-tests op‐
tion. The DH generator value will be chosen automatically for the prime under consideration. If a specific generator is
desired, it may be requested using the -O generator option. Valid generator values are 2, 3, and 5.
Screened DH groups may be installed in /etc/ssh/moduli. It is important that this file contains moduli of a range of bit
lengths.
A number of options are available for moduli generation and screening via the -O flag:
lines=number
Exit after screening the specified number of lines while performing DH candidate screening.
start-line=line-number
Start screening at the specified line number while performing DH candidate screening.
checkpoint=filename
Write the last line processed to the specified file while performing DH candidate screening. This will be used
to skip lines in the input file that have already been processed if the job is restarted.
memory=mbytes
Specify the amount of memory to use (in megabytes) when generating candidate moduli for DH-GEX.
start=hex-value
Specify start point (in hex) when generating candidate moduli for DH-GEX.
generator=value
Specify desired generator (in decimal) when testing candidate moduli for DH-GEX.
CERTIFICATES
ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication. Certifi‐
cates consist of a public key, some identity information, zero or more principal (user or host) names and a set of op‐
tions that are signed by a Certification Authority (CA) key. Clients or servers may then trust only the CA key and ver‐
ify its signature on a certificate rather than trusting many user/host keys. Note that OpenSSH certificates are a dif‐
ferent, and much simpler, format to the X.509 certificates used in ssl(8).
ssh-keygen supports two types of certificates: user and host. User certificates authenticate users to servers, whereas
host certificates authenticate server hosts to users. To generate a user certificate:
$ ssh-keygen -s /path/to/ca_key -I key_id /path/to/user_key.pub
The resultant certificate will be placed in /path/to/user_key-cert.pub. A host certificate requires the -h option:
$ ssh-keygen -s /path/to/ca_key -I key_id -h /path/to/host_key.pub
The host certificate will be output to /path/to/host_key-cert.pub.
It is possible to sign using a CA key stored in a PKCS#11 token by providing the token library using -D and identifying
the CA key by providing its public half as an argument to -s:
$ ssh-keygen -s ca_key.pub -D libpkcs11.so -I key_id user_key.pub
Similarly, it is possible for the CA key to be hosted in a ssh-agent(1). This is indicated by the -U flag and, again,
the CA key must be identified by its public half.
$ ssh-keygen -Us ca_key.pub -I key_id user_key.pub
In all cases, key_id is a "key identifier" that is logged by the server when the certificate is used for authentication.
Certificates may be limited to be valid for a set of principal (user/host) names. By default, generated certificates are
valid for all users or hosts. To generate a certificate for a specified set of principals:
$ ssh-keygen -s ca_key -I key_id -n user1,user2 user_key.pub
$ ssh-keygen -s ca_key -I key_id -h -n host.domain host_key.pub
Additional limitations on the validity and use of user certificates may be specified through certificate options. A cer‐
tificate option may disable features of the SSH session, may be valid only when presented from particular source ad‐
dresses or may force the use of a specific command.
The options that are valid for user certificates are:
clear Clear all enabled permissions. This is useful for clearing the default set of permissions so permissions may be
added individually.
critical:name[=contents]
extension:name[=contents]
Includes an arbitrary certificate critical option or extension. The specified name should include a domain suf‐
fix, e.g. “name@example.com”. If contents is specified then it is included as the contents of the extension/op‐
tion encoded as a string, otherwise the extension/option is created with no contents (usually indicating a flag).
Extensions may be ignored by a client or server that does not recognise them, whereas unknown critical options
will cause the certificate to be refused.
force-command=command
Forces the execution of command instead of any shell or command specified by the user when the certificate is
used for authentication.
no-agent-forwarding
Disable ssh-agent(1) forwarding (permitted by default).
no-port-forwarding
Disable port forwarding (permitted by default).
no-pty Disable PTY allocation (permitted by default).
no-user-rc
Disable execution of ~/.ssh/rc by sshd(8) (permitted by default).
no-x11-forwarding
Disable X11 forwarding (permitted by default).
permit-agent-forwarding
Allows ssh-agent(1) forwarding.
permit-port-forwarding
Allows port forwarding.
permit-pty
Allows PTY allocation.
permit-user-rc
Allows execution of ~/.ssh/rc by sshd(8).
permit-X11-forwarding
Allows X11 forwarding.
no-touch-required
Do not require signatures made using this key include demonstration of user presence (e.g. by having the user
touch the authenticator). This option only makes sense for the FIDO authenticator algorithms ecdsa-sk and
ed25519-sk.
source-address=address_list
Restrict the source addresses from which the certificate is considered valid. The address_list is a comma-sepa‐
rated list of one or more address/netmask pairs in CIDR format.
verify-required
Require signatures made using this key indicate that the user was first verified. This option only makes sense
for the FIDO authenticator algorithms ecdsa-sk and ed25519-sk. Currently PIN authentication is the only sup‐
ported verification method, but other methods may be supported in the future.
At present, no standard options are valid for host keys.
Finally, certificates may be defined with a validity lifetime. The -V option allows specification of certificate start
and end times. A certificate that is presented at a time outside this range will not be considered valid. By default,
certificates are valid from the Unix Epoch to the distant future.
For certificates to be used for user or host authentication, the CA public key must be trusted by sshd(8) or ssh(1). Re‐
fer to those manual pages for details.
FIDO AUTHENTICATOR
ssh-keygen is able to generate FIDO authenticator-backed keys, after which they may be used much like any other key type
supported by OpenSSH, so long as the hardware authenticator is attached when the keys are used. FIDO authenticators gen‐
erally require the user to explicitly authorise operations by touching or tapping them. FIDO keys consist of two parts:
a key handle part stored in the private key file on disk, and a per-device private key that is unique to each FIDO au‐
thenticator and that cannot be exported from the authenticator hardware. These are combined by the hardware at authenti‐
cation time to derive the real key that is used to sign authentication challenges. Supported key types are ecdsa-sk and
ed25519-sk.
The options that are valid for FIDO keys are:
application
Override the default FIDO application/origin string of “ssh:”. This may be useful when generating host or do‐
main-specific resident keys. The specified application string must begin with “ssh:”.
challenge=path
Specifies a path to a challenge string that will be passed to the FIDO authenticator during key generation. The
challenge string may be used as part of an out-of-band protocol for key enrollment (a random challenge is used by
default).
device Explicitly specify a fido(4) device to use, rather than letting the authenticator middleware select one.
no-touch-required
Indicate that the generated private key should not require touch events (user presence) when making signatures.
Note that sshd(8) will refuse such signatures by default, unless overridden via an authorized_keys option.
resident
Indicate that the key handle should be stored on the FIDO authenticator itself. This makes it easier to use the
authenticator on multiple computers. Resident keys may be supported on FIDO2 authenticators and typically re‐
quire that a PIN be set on the authenticator prior to generation. Resident keys may be loaded off the authenti‐
cator using ssh-add(1). Storing both parts of a key on a FIDO authenticator increases the likelihood of an at‐
tacker being able to use a stolen authenticator device.
user A username to be associated with a resident key, overriding the empty default username. Specifying a username
may be useful when generating multiple resident keys for the same application name.
verify-required
Indicate that this private key should require user verification for each signature. Not all FIDO authenticators
support this option. Currently PIN authentication is the only supported verification method, but other methods
may be supported in the future.
write-attestation=path
May be used at key generation time to record the attestation data returned from FIDO authenticators during key
generation. This information is potentially sensitive. By default, this information is discarded.
KEY REVOCATION LISTS
ssh-keygen is able to manage OpenSSH format Key Revocation Lists (KRLs). These binary files specify keys or certificates
to be revoked using a compact format, taking as little as one bit per certificate if they are being revoked by serial
number.
KRLs may be generated using the -k flag. This option reads one or more files from the command line and generates a new
KRL. The files may either contain a KRL specification (see below) or public keys, listed one per line. Plain public
keys are revoked by listing their hash or contents in the KRL and certificates revoked by serial number or key ID (if the
serial is zero or not available).
Revoking keys using a KRL specification offers explicit control over the types of record used to revoke keys and may be
used to directly revoke certificates by serial number or key ID without having the complete original certificate on hand.
A KRL specification consists of lines containing one of the following directives followed by a colon and some directive-
specific information.
serial: serial_number[-serial_number]
Revokes a certificate with the specified serial number. Serial numbers are 64-bit values, not including zero and
may be expressed in decimal, hex or octal. If two serial numbers are specified separated by a hyphen, then the
range of serial numbers including and between each is revoked. The CA key must have been specified on the
ssh-keygen command line using the -s option.
id: key_id
Revokes a certificate with the specified key ID string. The CA key must have been specified on the ssh-keygen
command line using the -s option.
key: public_key
Revokes the specified key. If a certificate is listed, then it is revoked as a plain public key.
sha1: public_key
Revokes the specified key by including its SHA1 hash in the KRL.
sha256: public_key
Revokes the specified key by including its SHA256 hash in the KRL. KRLs that revoke keys by SHA256 hash are not
supported by OpenSSH versions prior to 7.9.
hash: fingerprint
Revokes a key using a fingerprint hash, as obtained from a sshd(8) authentication log message or the ssh-keygen
-l flag. Only SHA256 fingerprints are supported here and resultant KRLs are not supported by OpenSSH versions
prior to 7.9.
KRLs may be updated using the -u flag in addition to -k. When this option is specified, keys listed via the command line
are merged into the KRL, adding to those already there.
It is also possible, given a KRL, to test whether it revokes a particular key (or keys). The -Q flag will query an ex‐
isting KRL, testing each key specified on the command line. If any key listed on the command line has been revoked (or
an error encountered) then ssh-keygen will exit with a non-zero exit status. A zero exit status will only be returned if
no key was revoked.
ALLOWED SIGNERS
When verifying signatures, ssh-keygen uses a simple list of identities and keys to determine whether a signature comes
from an authorized source. This "allowed signers" file uses a format patterned after the AUTHORIZED_KEYS FILE FORMAT de‐
scribed in sshd(8). Each line of the file contains the following space-separated fields: principals, options, keytype,
base64-encoded key. Empty lines and lines starting with a ‘#’ are ignored as comments.
The principals field is a pattern-list (see PATTERNS in ssh_config(5)) consisting of one or more comma-separated USER@DO‐
MAIN identity patterns that are accepted for signing. When verifying, the identity presented via the -I option must
match a principals pattern in order for the corresponding key to be considered acceptable for verification.
The options (if present) consist of comma-separated option specifications. No spaces are permitted, except within double
quotes. The following option specifications are supported (note that option keywords are case-insensitive):
cert-authority
Indicates that this key is accepted as a certificate authority (CA) and that certificates signed by this CA may
be accepted for verification.
namespaces=namespace-list
Specifies a pattern-list of namespaces that are accepted for this key. If this option is present, the signature
namespace embedded in the signature object and presented on the verification command-line must match the speci‐
fied list before the key will be considered acceptable.
valid-after=timestamp
Indicates that the key is valid for use at or after the specified timestamp, which may be a date or time in the
YYYYMMDD[Z] or YYYYMMDDHHMM[SS][Z] formats. Dates and times will be interpreted in the current system time zone
unless suffixed with a Z character, which causes them to be interpreted in the UTC time zone.
valid-before=timestamp
Indicates that the key is valid for use at or before the specified timestamp.
When verifying signatures made by certificates, the expected principal name must match both the principals pattern in the
allowed signers file and the principals embedded in the certificate itself.
An example allowed signers file:
# Comments allowed at start of line
user1@example.com,user2@example.com ssh-rsa AAAAX1...
# A certificate authority, trusted for all principals in a domain.
*@example.com cert-authority ssh-ed25519 AAAB4...
# A key that is accepted only for file signing.
user2@example.com namespaces="file" ssh-ed25519 AAA41...
ENVIRONMENT
SSH_SK_PROVIDER
Specifies a path to a library that will be used when loading any FIDO authenticator-hosted keys, overriding the
default of using the built-in USB HID support.
FILES
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519, authenticator-hosted Ed25519 or RSA authentication
identity of the user. This file should not be readable by anyone but the user. It is possible to specify a
passphrase when generating the key; that passphrase will be used to encrypt the private part of this file using
unless suffixed with a Z character, which causes them to be interpreted in the UTC time zone.
valid-before=timestamp
Indicates that the key is valid for use at or before the specified timestamp.
When verifying signatures made by certificates, the expected principal name must match both the principals pattern in the
allowed signers file and the principals embedded in the certificate itself.
An example allowed signers file:
# Comments allowed at start of line
user1@example.com,user2@example.com ssh-rsa AAAAX1...
# A certificate authority, trusted for all principals in a domain.
*@example.com cert-authority ssh-ed25519 AAAB4...
# A key that is accepted only for file signing.
user2@example.com namespaces="file" ssh-ed25519 AAA41...
ENVIRONMENT
SSH_SK_PROVIDER
Specifies a path to a library that will be used when loading any FIDO authenticator-hosted keys, overriding the
default of using the built-in USB HID support.
FILES
~/.ssh/id_dsa
~/.ssh/id_ecdsa
~/.ssh/id_ecdsa_sk
~/.ssh/id_ed25519
~/.ssh/id_ed25519_sk
~/.ssh/id_rsa
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519, authenticator-hosted Ed25519 or RSA authentication
identity of the user. This file should not be readable by anyone but the user. It is possible to specify a
passphrase when generating the key; that passphrase will be used to encrypt the private part of this file using
128-bit AES. This file is not automatically accessed by ssh-keygen but it is offered as the default file for the
private key. ssh(1) will read this file when a login attempt is made.
~/.ssh/id_dsa.pub
~/.ssh/id_ecdsa.pub
~/.ssh/id_ecdsa_sk.pub
~/.ssh/id_ed25519.pub
~/.ssh/id_ed25519_sk.pub
~/.ssh/id_rsa.pub
Contains the DSA, ECDSA, authenticator-hosted ECDSA, Ed25519, authenticator-hosted Ed25519 or RSA public key for
authentication. The contents of this file should be added to ~/.ssh/authorized_keys on all machines where the
user wishes to log in using public key authentication. There is no need to keep the contents of this file se‐
cret.
/etc/ssh/moduli
Contains Diffie-Hellman groups used for DH-GEX. The file format is described in moduli(5).
SEE ALSO
ssh(1), ssh-add(1), ssh-agent(1), moduli(5), sshd(8)
The Secure Shell (SSH) Public Key File Format, RFC 4716, 2006.
AUTHORS
OpenSSH is a derivative of the original and free ssh 1.2.12 release by Tatu Ylonen. Aaron Campbell, Bob Beck, Markus
Friedl, Niels Provos, Theo de Raadt and Dug Song removed many bugs, re-added newer features and created OpenSSH. Markus
Friedl contributed the support for SSH protocol versions 1.5 and 2.0.
GNU September 4, 2023 SSH-KEYGEN(1)
Wie wir den Manual-Pages entnehmen konnten, unterstützt die OpenSSH-Implementierung von SSH einen zertifikatsbasierten Mechanismus. Dieser kann dazu beitragen, die Komplexität zu reduzieren sobald sich berechtigte Administratoren sich die SSH zu Hilfe nehmen und dabei eben Benutzer den SSH-Hosts und Hosts den SSH-Benutzern vertrauen (müssen).
Bevor wir uns nun mit der Konfiguration und dem Umgang mit Zertifiklaten und signierten Schlüsselmaterial eingehender beschäftigen, sei noch der Hinweis gestattet: Die hier vorgestellte Lösung mit der Verwendung von SSH-Zertifikaten ist kein Allheilmittel für die Sicherheit. Wie jede andere technische Lösung hat diese natürlich Vor- und Nachteile - hier seien nur mal DNS, Implementierung, Zertifikatsenrollment, Revocation-Lists, Handling und Verständnis der handelnden Personen genannt - die mit den bestehenden Anforderungen abgewogen werden müssen!
Glücklicherweise enthalten aktuelle Versionen4) von SSH viele Verbesserungen, die uns die Möglichkeit geben, authorized_keys mit AuthorizedKeysCommand zu zentralisieren und besser und leichter zu verwalten. Allerdings bieten SSH-Zertifikate neben der Lösung des TOFU-Problems viele weitere Vorteile/Funktionen (z. B. Ablauf des Zertifikats, Verwendung von Auftraggebern usw.), die die SSH-Authentifizierungsverwaltung verbessern und von allen Organisationen, die SSH verwenden, genutzt werden sollten.
Wie wir wissen, müssen wir nun sicherstellen dass beide Parteien sich gegenseitig vertrauen können. Bewerkstelligt wird dies unter Zuhilfename einer Zertifizierungsstelle, die hilft allen Kommunikationspartnern eine Vertrauensstellung einzuräumen. Hierzu sind zwei Zertifizierungsstellen nötig, wobei hier Zertifizierungsstelle ein doch eher sehr klingender Name, aber im SSH-Umfeld bei eingehender und genauerer Betrachtung eigentlich „nur“ je ein weiterer SSH-Schlüssel (wieder mit öffentlichem SSH-Schlüssel und seinem privaten SSH-Schlüssel), ist. Statt nun komplexe Zertifikate im X.509-Stil zu verwenden, hat sich SSH für sein eigenes, einfacheres Zertifikatsformat entschieden, das mit der CLI ssh-keygen einfach verwaltet werden kann.
- Host-Zertifizierungsstelle (Host CA): Ein SSH-Schlüsselpaar, bei dem mit Hilfe des privater SSH-Schlüssel die Ausstellung von Host-Zertifikaten verwendet wird. Ihr öffentlicher SSH-Schlüssel wiederum wird von den Administratoren verwendet, um zu überprüfen, ob denn nun die Host-Zertifikate von der Host-Zertifizierungsstelle ausgestellt wurden, der sie vertrauen.
- Benutzerzertifizierungsstelle (User CA): Ein SSH-Schlüsselpaar, dessen privater SSH-Schlüssel bei der Ausstellung von Benutzerzertifikaten Anwendung findet. Dessen öffentlicher SSH-Schlüssel wird von Hosts bei der Prüfung verwendet, ob die Benutzerzertifikate von der Benutzerzertifizierungsstelle ausgestellt wurden, der sie vertrauen.
Zertifizierungsstellen (Host und User CA)
Wenn es um Vertrauen geht, kann uns bei diesem Unterfangen eine Zertifizierungsstelle sehr hilfreich sein. Wir werden uns also jeweils eine erstellen, damit die Benutzer den Hosts vertrauen können und eine, damit die Hosts den Benutzern vertrauen können.
Die SSH-Zertifizierungsstelle (CA) kann theoretisch auf jedem Computer mit ssh-keygen
eingerichtet werden. Auf Grund der Wichtigkeit die wir dieser CA einräumen, werden wir natürlich hierzu einem separaten Host der sich in einer entsprechenden Schutzzone befindet verwenden, auf dem dann nur ein sehr ausgewählter Administratorenkreis Zugriff bekommen wird. Die SSH-Zertifizierungsstelle ist bei genauer Betrachtung „lediglich nur“ jeweils ein ist ein Schlüsselpaar, das zum Signieren öffentlicher SSH-Schlüssel verwendet wird, um Zertifikate zu erzeugen. Daher werden wir uns nun zu erst jeweils ein Schlüsselpaar für jede Zertifizierungsstelle„ generieren.
Wie wir der man-page von ssh-keygen
entnehmen konnten, werden wir nun diese beiden keys (CA) anlegen, nachdem wir uns zwei zugehörige Unterverzeichnisse angelegt haben. Somit haben wir es später beim täglichen Gebrauch dann doch leichter die Ganze Sache überblicken zu können.
# mkdir /etc/ssh/ssh_ca
Nun erstellen wir uns mit den Optionen -t ed25519
(Schlüsseltyp), -C "Host CA key"
(Kommentar ab Ende des Public-Keys) und -f /etc/ssh/ssh_ca_host/ssh_ca_host
(Speicherort und Name der Schlüsseldateien) die Schlüssel für die Host CA:
# ssh-keygen -t ed25519 -C "Host CA key" -f /etc/ssh/ssh_ca/ssh_ca_host_key
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /etc/ssh/ssh_ca/ssh_ca_host_key Your public key has been saved in /etc/ssh/ssh_ca/ssh_ca_host_key.pub The key fingerprint is: SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk Host CA key The key's randomart image is: +--[ED25519 256]--+ | + .=B*.o | | . Eo .++ + = | | o o+.. . X o | | .... . o * | | o. S . + + | | .. o = | | .. . | | .+ + . o. | | .. Bo..+oo | +----[SHA256]-----+
Entsprechend verfahren wir nun auch noch und erstellen das Schlüsselpaar für unsere User CA:
# ssh-keygen -t ed25519 -C "User CA key" -f /etc/ssh/ssh_ca/ssh_ca_user_key
Generating public/private ed25519 key pair. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /etc/ssh/ssh_ca/ssh_ca_user_key Your public key has been saved in /etc/ssh/ssh_ca/ssh_ca_user_key.pub The key fingerprint is: SHA256:iRZv/JZQRbMjshPjKavpy7X5mvxRzAOERXrnUzhHGiU User CA key The key's randomart image is: +--[ED25519 256]--+ | ++ Eo* | | .o B o | | o * B = | | B # = . | | + S B | | . + = + | | o . + | | . = + o | | .*.*+o | +----[SHA256]-----+
Wir haben nun im betreffenden Verzeichnis pro CA je zwei Dateien, einmal den privaten und einmal den öffentlichen Schlüssel für unsere beiden CAs:
# ls -Al /etc/ssh/ssh_ca
total 16 -rw------- 1 root root 444 Nov 26 15:57 ssh_ca_host_key -rw-r--r-- 1 root root 93 Nov 26 15:57 ssh_ca_host_key.pub -rw------- 1 root root 444 Nov 26 15:59 ssh_ca_user_key -rw-r--r-- 1 root root 93 Nov 26 15:59 ssh_ca_user_key.pub
Dank des Kommentars, den wir bei der Generierung der Schlüssel angegeben hatten, erkennen wir auch später an Hand des Kommentars um welches Schlüssel sprich welche CA es sich handelt.
# cat /etc/ssh/ssh_ca/ssh_ca_host_key.pub /etc/ssh/ssh_ca/ssh_ca_user_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4Z+nMbZeGy2ugFDZri+y5aDCNHJkcxCk1w++iWZDLL Host CA key ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPQNQsEBk4c7vF//uWKix5QA8lHS0JMoWbMar9eP94BB User CA key
Was nun noch fehlt ist die SSH-Schlüsselwiderrufsliste KRL5), welche die Liste aller widerrufenen Zertifikate dann halten wird. Denn schliesslich könnte ja ein Zertifikat später mal gesperrt werden müssen, weil ein Schlüssel abhanden gekommen ist oder ein Personalabgang bei den handelnden Personen erfolgt.
# ssh-keygen -k -f /etc/ssh/ssh_ca/ssh_ca_krl
Im Zielverzeichnis finden wir nun auch diese Datei.
# ls -Al /etc/ssh/ssh_ca/ssh_ca_krl
-rw-r--r-- 1 root root 44 Nov 26 16:11 /etc/ssh/ssh_ca/ssh_ca_krl
Das Handling mit dieser KRL werden wir uns später noch genauer in diesem Abschnitt dann zu Gemüte führen.
Wir müssen jetzt anschliessend nur noch sowohl Server und auch unsere Administratoren/Clients dazu bringen mit den noch zu signierenden Zertifikaten, oder sprechen wir im SSH-Umfeld doch lieber von signierten Schlüsseln, umzugehen.
Erzeugen des Hostkey-Zertifikates
Im nächsten Schritt werden wir nun das nötige Vertrauen vorbereiten, welches unseren Administratoren dann Hilft beim Thema TOFU nicht überfordert zu werden.
Wir holen bzw. kopieren zunächst den SSH-Public-Key - dies wir unter aktuell verwendeten ED25519 Schlüsselmaterial entsprechend die Datei /etc/ssh/ssh_host_ed25519_key.pub
- unseres bzw. später unserer Zielhosts auf unseren geschützten Host, auf dem wir zuvor unsere Keys und die KRL angelegt hatten. Diesen Schlüssel legen wir am Besten unter eigenem Namen in unseren CA-Verzeichnis /etc/ssh/ssh_ca
ab.
Beispiel:
# cat /etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDY4Wzo8EUH3nl4Xea6hpt3pOi3HL4PxSr6x351NPbv5 KVM-Host 1
Diesen Öffentlichen Schlüssel signieren wir nun mit dem öffentlichen CA-Key der Host CA, dabei verwenden bzw. setzen wir die Optionen wie folgt:
-h
: Host-Zertifikat erstellen-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“.-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-Hostnamekvm
für den Hostpml010002.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 diehostname
s und zusätzlich noch derfqdn
s.ssh_host_ed25519_pml010002_key.pub
: Schlüsseldatei des Hosts, die von der CA signiert werden wird.
# ssh-keygen -h \ -s /etc/ssh/ssh_ca/ssh_ca_host_key \ -z 1000 \ -V +52w1d \ -I kvm \ -n kvm,kvm.intra.nausch.org,pml010002,pml010002.intra.nausch.org \ /etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key.pub
Enter passphrase:
Nach Eingabe der Passphrase unseres Host CA Schlüssels erhalten wir dann die Information der erfolgreichen Ausstellung unseres Zertifikates angezeigt.
Signed host key /etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key-cert.pub: id "kvm" serial 1000 for kvm,kvm.intra.nausch.org,pml010002,pml010002.intra.nausch.org valid from 2023-11-26T23:11:00 to 2024-11-25T23:12:51
In unserem CA Host Verzeichnis /etc/ssh/ssh_ca/
haben wir nun also neben der Datei ssh_host_ed25519_pml010002_key.pub
, die den öffentlichen Schlüssel unseres host bereithält, nun auch die Datei mit dem signierten Schlüssel ssh_host_ed25519_pml010002_key-cert.pub
, sprich unser Server-Zertifikat.
Wir können natürlich auch einen Blick in dieses Zertifikat werfen. hierzu benutzen wir folgenden Befehl:
# ssh-keygen -L -f /etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key-cert.pub
/etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com host certificate Public key: ED25519-CERT SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4 Signing CA: ED25519 SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk (using ssh-ed25519) Key ID: "kvm" Serial: 1000 Valid: from 2023-11-26T23:11:00 to 2024-11-25T23:12:51 Principals: kvm kvm.intra.nausch.org pml010002 pml010002.intra.nausch.org Critical Options: (none) Extensions: (none)
Hostkey-Zertifikate ablegen und konfigurieren
Das gerade generierte Host-Key-Zertifikat kopieren wir nun auf unseren Zielhost und legen es im Verzeichnis /etc/ssh
zu den anderen Schlüsseldateien.
- Key auf Host kopieren
Im ersten Schritt kopieren wir nun die Datei von unserem geschützten SSH-CA-Host auf den Ziel-Host:$ scp /etc/ssh/ssh_ca/ssh_host_ed25519_pml010002_key-cert.pub kvm:
- Key in Zielverzeichnis kopieren
Anschliessend kopieren wir auf dem Zielhost die Datei aus dem User-Verzeichnis/home/django
unseres Admins - in diesem Beispiel vom User django - in das Zielverzeichnis.# cp /home/django/ssh_host_ed25519_pml010002_key-cert.pub /etc/ssh/ssh_host_ed25519_key-cert.pub
wir haben nunmehr drei ED25519-Schlüsseldateien, den
- Private-Key :
/etc/ssh/ssh_host_ed25519_key
- Public-Key :
/etc/ssh/ssh_host_ed25519_key.pub
- Zertifikat:
/etc/ssh/ssh_host_ed25519_key-cert.pub
den von der HOST CA signierten Public-Key.
$ ls -Al /etc/ssh/ssh_host_ed*
-rw-r-----. 1 root ssh_keys 387 Apr 7 2021 /etc/ssh/ssh_host_ed25519_key -rw-r--r-- 1 root root 545 Nov 27 12:31 /etc/ssh/ssh_host_ed25519_key-cert.pub -rw-r--r--. 1 root root 82 Apr 7 2021 /etc/ssh/ssh_host_ed25519_key.pub
- SSH-Damon konfigurieren und neu starten
Nun weisen wir denn SSH-Daemon auf dem Zielhost an, nicht nur den Fingerprint des Server-Keys zu präsentieren, sondern auch unser neues Server-Zertificat. Wir ergänzen dazu die Konfigurationmsdatei vom SSH-Daemon entsprechend.# vim /etc/ssh/sshd_config
... # Specifies a file containing a private host key used by SSH. The default # is /etc/ssh/ssh_host_key for protocol version 1, and # /etc/ssh/ssh_host_rsa_key and /etc/ssh/ssh_host_dsa_key for protocol # version 2. Note that sshd(8) will refuse to use a file if it is # group/world-accessible. It is possible to have multiple host key files. # ''rsa1'' keys are used for version 1 and ''dsa'' or ''rsa'' are used for # version 2 of the SSH protocol. HostKey /etc/ssh/ssh_host_ed25519_key # Django : 2023-11-26 # Specifies a file containing a public host certificate. The certificate's # public key must match a private host key already specified by HostKey. # The default behaviour of sshd is not to load any certificates. HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub ...
Dies weist den SSH-Daemon an, bei Bedarf das signierte Zertifikat vorzuzeigen. Zum Aktivieren starten wir nun den SSH-Daemon einmal neu:
# systemctl restart sshd.service
Zur Sicherheit können wir auch noch den Status des SSH-Damon abfragen.
# systemctl status sshd.service
● sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-11-26 23:20:39 CET; 11s ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 1777 (sshd) Tasks: 1 CGroup: /system.slice/sshd.service └─1777 /usr/sbin/sshd -D Nov 26 23:20:38 pml010002.intra.nausch.org systemd[1]: Starting OpenSSH server daemon... Nov 26 23:20:39 pml010002.intra.nausch.org sshd[16129]: Server listening on 10.0.10.2 port 22. Nov 26 23:20:39 pml010002.intra.nausch.org systemd[1]: Started OpenSSH server daemon.
- Ablegen des öffentlichen Schlüssels
ssh_ca_host_key
der SSH HOST CA auf dem Admin-Rechner
Damit später der Client auch die Validät des angebotenen Server-Zertifikats überprüfen kann, benötigt dieser den öffentlichen Schlüssel der SSH HOST CA, den wir hier erstellt hatten. Diesen holen wir uns nun noch auf unseren Admin-Rechner und packen diesen bzw den Inhalt dieser Datei in entweder bei jedem Admin in das File~/.ssh/known_hosts
oder als Systemvorgabe in die Datei/etc/ssh/ssh_known_hosts
. Diese Datei wird künftig pro verwendeter SSH HOST CA lediglich nur noch eine oder wenige Zeilen enthalten!$ echo "@cert-authority *.nausch.org ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAID4Z+nMbZeGy2ugFDZri+y5aDCNHJkcxCk1w++iWZDLL Host CA key" > ~/.ssh/known_hosts
Verfügt der Client NICHT über den richtigen öffentlichen Schlüssel der SSH HOST CA (aus seiner eigenen~/.ssh/known_hosts
oder der für alle User geltenden aus/etc/ssh/ssh_known_hosts
bzw. ist dieser nicht mehr gültig wird der vertrauensbekannte Verbindungsaufbau zum Zielhost erst einmal fehl schlagen und dem Anwender die obligatorische TOFU Frage stellen: This key is not known by any other names - Are you sure you want to continue connecting (yes/no/[fingerprint])? . Man kann dies auch sehr gut beim Aufruf vonshh
mit der OPtion-v
erkennen.$ ssh kvm
... debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4, serial 1000 ID "voip" CA ssh-ed25519 SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk valid from 2023-11-26T22:12:00 to 2023-11-25T22:20:11 ... debug1: No matching CA found. Retry with plain key The authenticity of host 'kvm.intra.nausch.org (10.0.10.2)' can't be established. ED25519 key fingerprint is SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4. This key is not known by any other names Are you sure you want to continue connecting (yes/no/[fingerprint])?
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 Befehlsssh-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.$ ssh-keygen -f ~/.ssh/known_hosts -R kvm.intra.nausch.org
# Host kvm.intra.nausch.org found: line 1408 /home/django/.ssh/known_hosts updated. Original contents retained as /home/django/.ssh/known_hosts.old
Nun starten wir eine SSH-Session zu unserem Zielhost.
$ ssh kvm.intra.nausch.org -v
... debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4, serial 1000 ID "kvm" CA ssh-ed25519 SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk valid from 2023-11-27T12:27:00 to 2024-11-26T12:28:44 debug1: Host 'kvm.intra.nausch.org' is known and matches the ED25519-CERT host certificate. debug1: Found CA key in /etc/ssh/ssh_known_hosts:1 ...
[django@pml010002 ~]$
Sofern die Aufgabenstellung war, „nur“ dafür zu sorgen, den Admins die manuelle|visuelle Prüfung von SSH-Key Fingerprints beim ersten Verbindungsausbau abzunehmen, oder ausufernde ~/.ssh/known_hosts
abzunehmen, können wir hir unsere Aufgabe abschließen und direkt zum Anschnitt Fazit und Ausblick springen.
Erzeugen der|des Userkey-Zertifikate(s)
Für die Erzeugung von signierten Client-Zertifikaten für unseren Client/Adminuser django führen wir folgenden Schritte aus:
- Kopieren des Public-Keys unseres Adminusers auf den SSH CA Host
In unserem Beispiel kopieren wir nun den public-ssh-key~/.ssh/id_ed25519.pub
vom Admin django auf den Zielhost ssh-ca.idmz.nausch.org.$ scp ~/.ssh/id_ed25519.pub ssh-ca.idmz.nausch.org:
- Kopieren des Admin-Public-SSH-Keys in das Verzeichnis unserer SSH CA
Hier kopieren wir dann den public-key in unser CA-Verzeichnis/etc/ssh/ssh_ca
. Dabei vermerken wir den Namen des betreffenden Admins im Dateinamen der Schlüsseldatei. So haben wir es später leichter diese auseinander zu halten.cp /home/django/id_ed25519.pub /etc/ssh/ssh_ca/id_ed25519_django.pub
Somit haben wir in unserem Beispiel hier den Public-Key zur Verfügung:
# cat /etc/ssh/ssh_ca/id_ed25519_django.pub
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDYjDCtBTfrpbHHkRrqH1khsMagrrD5d+IbkU6ddoBSp django@nausch.org
- Generieren des User-Zertifikates
Analog zur Erstellung des Host-Zertifikates signieren wir nun diesen Schlüssel des Users mit dem öffentlichen CA-Key der User CA, dabei verwenden bzw. setzen wir die Optionen wie folgt:-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“.-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.- Definiert den beim Signieren eines öffentlichen Server-Schlüssels die Schlüsselidentität der CA.
-n django
: 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.id_ed25519_django.pub
: Datei mit dem public-key des Admin-Users, die von der CA signiert werden wird.# ssh-keygen -s /etc/ssh/ssh_ca/ssh_ca_user_key \ -z 1 \ -V +52w1d \ -I django \ -n django \ /etc/ssh/ssh_ca/id_ed25519_django.pub
Enter passphrase:
Nach Eingabe der Passphrase unseres USER CA Schlüssels erhalten wir dann die Information der erfolgreichen Ausstellung unseres Zertifikates angezeigt.
Signed user key /etc/ssh/ssh_ca/id_ed25519_django-cert.pub: id "django" serial 10 for django valid from 2023-11-26T18:17:00 to 2024-11-25T18:18:33
In unserem CA User Verzeichnis
/etc/ssh/ssh_ca#
haben wir nun also neben der Dateiid_ed25519_django.pub
, die den öffentlichen Schlüssel unseres Adminsdjango
bereithält, nun auch die Datei mit dem signierten Schlüsselid_ed25519_django-cert.pub
, also das signierte User-Zertifikat.
Wir können natürlich auch einen Blick in dieses Zertifikat werfen. Hierzu benutzen wir folgenden Befehl:# ssh-keygen -L -f /etc/ssh/ssh_ca/id_ed25519_django-cert.pub
/etc/ssh/ssh_ca/id_ed25519_django-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com user certificate Public key: ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 Signing CA: ED25519 SHA256:iRZv/JZQRbMjshPjKavpy7X5mvxRzAOERXrnUzhHGiU (using ssh-ed25519) Key ID: "django" Serial: 1 Valid: from 2023-11-26T22:27:00 to 2024-11-25T22:28:37 Principals: django Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc
- Zertifikat/Signierte Key Datei auf Host kopieren
Das gerade generierte User-Key-Zertifikat kopieren wir nun auf unseren Zielhost und legen es zu den anderen Schlüsseldateien im~/.ssh
Verzeichnis. Dazu kopieren wir nun die Datei von unserem geschützten SSH-CA-Host auf den Ziel-Host:$ scp /etc/ssh/ssh_ca/id_ed25519_django-cert.pub admin-pc:
- Zertifikat/Signierte Key Datei kopieren
Anschliessend verschieben wir auf dem Zielhost die Datei aus dem User-Verzeichnis~/.ssh/
unseres Admins in das Zielverzeichnis.# mv ~/id_ed25519_dmz_django-cert.pub ~/.ssh/id_ed25519_dmz-cert.pub
- Ablegen des öffentlichen Schlüssels
ssh_ca_host_key
der SSH HOST CA auf dem Admin-Rechner
Den öffentlichen Schlüssel der SSH HOST CA, den wir Hostkey-Zertifikate ablegen und konfigurieren erstellt hatten, haben wir ja in dem vorherigen Abschnitt schon auf unseren Admin-Rechner geholt und entsprechende Konfigurationsanpassungen in der~/.ssh/known_hosts
bzw.~/etc/ssh/ssh_known_hosts
vorgenommen. - Konfiguration des SSH-Client
Damit der SSH-Client beim Verbindungsaufbau auch weiß, welches Zertifikat er präsentieren soll, hinterlegen wir dieses noch in der zugehörigen Client-Konfiguirationsdatei~/.ssh/config
.$ vim ~/.ssh/config
Host kvm Hostname kvm.intra.nausch.org User django CertificateFile ~/.ssh/id_ed25519-cert.pub
- Konfigurieren des SSH-Daemon auf dem Zielsystem
Damit der Host auf dem wir uns anmelden können, muss natürlich wissen, ob das Zertifikat soweit vertraut werden kann. Dazu benötigt der Host unter anderem das Zertifikat unserer CA. welches wir bei der Anlage der User CA bereits erzeugt hatten. Diese Datei/etc/ssh/ssh_ca/ssh_ca_user_key.pub
kopieren wir nun auf unseren Zielhost und legen diese Date im Verzeichnis/etc/ssh
ab.# ls -Al /etc/ssh/*ca_user*
-rw-r--r-- 1 root root 93 Nov 26 22:25 /etc/ssh/ssh_ca_user_key.pub
Damit unser SSH-Daemon diese Key-Datei auch nutzen kann, müssen wir diesem noch mitteilen wo die Datei liegt. Dazu erweitern wir die Konfigurationsdatei unseres SSH-Daemon
/etc/ssh/sshd_config
wie folgt.vim /etc/ssh/sshd_config
... # Specifies a file containing public keys of certificate authorities that # are trusted to sign user certificates for authentication, or none to not # use one. Keys are listed one per line; empty lines and comments starting # with ‘#’ are allowed. If a certificate is presented for authentication # and has its signing CA key listed in this file, then it may be used for # authentication for any user listed in the certificate's principals list. # Note that certificates that lack a list of principals will not be per- # mitted for authentication using TrustedUserCAKeys. TrustedUserCAKeys /etc/ssh/ssh_ca_user_key.pub ...
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 OptionAuthorizedPrincipalsFile
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.$ ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
/home/django/.ssh/id_ed25519-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com user certificate Public key: ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 Signing CA: ED25519 SHA256:iRZv/JZQRbMjshPjKavpy7X5mvxRzAOERXrnUzhHGiU (using ssh-ed25519) Key ID: "django" Serial: 5 Valid: from 2023-11-27T18:02:00 to 2024-11-26T18:03:05 Principals: django Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc
Hier haben wir also bei den
Principals
den Wertdjango
. 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 denPrincipal
-Namen aus dem Zertifikat in dieser Liste.# vim /etc/ssh/ssh_auth_principals
- /etc/ssh/ssh_auth_principals
# Liste aller Administratoren, die berechtigt sind sich hier mit Hilfe der SSH zu verbinden. django michael
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.# vim /etc/ssh/sshd_config
... # Specifies a file that lists principal names that are accepted for certifi- # cate authentication. When using certificates signed by a key listed in # TrustedUserCAKeys, this file lists names, one of which must appear in the # certificate for it to be accepted for authentication. Names are listed # one per line preceded by key options (as described in AUTHORIZED_KEYS FILE # FORMAT. Empty lines and comments starting with ‘#’ are ignored. # Arguments to AuthorizedPrincipalsFile accept the tokens described in the # TOKENS section. After expansion, AuthorizedPrincipalsFile is taken to be # an absolute path or one relative to the user's home directory. The default # is none, i.e. not to use a principals file – in this case, the username of # the user must appear in a certificate's principals list for it to be # accepted. # Note that AuthorizedPrincipalsFile is only used when authentication pro- # ceeds using a CA listed in TrustedUserCAKeys and is not consulted for # certification authorities trusted via ~/.ssh/authorized_keys, though the # principals= key option offers a similar facility. AuthorizedPrincipalsFile /etc/ssh/ssh_auth_principals ...
Da wir die Konfiguration des SSH-Daemon nun vorerst abgeschlossen haben, ist es an der Zeit diesen neu zu starten. Zum Aktivieren starten wir nun den SSH-Daemon einmal neu:
# systemctl restart sshd.service
Zur Sicherheit können wir auch noch den Status des SSH-Damon abfragen.
# systemctl status sshd.service
● sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled) Active: active (running) since Sun 2023-11-26 23:20:39 CET; 11s ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 1777 (sshd) Tasks: 1 CGroup: /system.slice/sshd.service └─1777 /usr/sbin/sshd -D Nov 26 23:57:38 pml010002.intra.nausch.org systemd[1]: Starting OpenSSH server daemon... Nov 26 23:57:39 pml010002.intra.nausch.org sshd[16129]: Server listening on 10.0.10.2 port 22. Nov 26 23:57:39 pml010002.intra.nausch.org systemd[1]: Started OpenSSH server daemon.
Nun ist es an der Zeit unsere Konfiguration auch zu testen. Bis jetzt haben wir vermutlich mit Einträgen in der~/.ssh/authorized_keys
gearbeitet. bei Anmeldung mit Zertifikat benötigen wir die Option aber nicht mehr, da der SSH-Client ja sein Zertifikat dem Server zur Authentifizierung schickt.$ rm ~/.ssh/authorized_keys<code> Die Anmeldung mit Hilfe des privaten SSH-Keys des Admins ist nunmehr unterbunden. Der Administrator kann sich nunmehr nur nur mit (s)einem gültigen Zertifikat anmelden. <code> # ssh -v kvm.intra.nausch.org
Der SSH-Server präsentiert dem Client sein Host-Zertifikat und wir sehen auch dass kein known_hosts-Dateien mehr benitzt werden (können).:
... debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4, serial 1000 ID "kvm" CA ssh-ed25519 SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk valid from 2023-11-27T12:27:00 to 2024-11-26T12:28:44 debug1: load_hostkeys: fopen /home/django/.ssh/known_hosts2: No such file or directory debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory debug1: Host 'kvm.intra.nausch.org' is known and matches the ED25519-CERT host certificate. debug1: Found CA key in /etc/ssh/ssh_known_hosts:1 ...
Anschließend päsentiert der Client dem Server das entsprechende Clientzertifikat des Admins django.
... debug1: Authentications that can continue: publickey debug1: Next authentication method: publickey debug1: Offering public key: /home/django/.ssh/id_ed25519_dmz-cert.pub ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 explicit debug1: Server accepts key: /home/django/.ssh/id_ed25519_dmz-cert.pub ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 explicit Authenticated to kvm.intra.nausch.org ([10.0.10.2]:22) using "publickey". ...
… und schon sind wir angemeldet.
[django@pml010002 ~]$
Key Revocation List
Was ist aber nun, wenn nun ein Administrator die Berechtigung verliert sich an Systemen anzumelden? Klar, früher hätte man auf dem System(en) in der authorized_keys
die betreffenden Schlüsseleinträge gelöscht. Alternativ könnten wir in unserem Konfigurationsbeispiel hier den Principal-Eintrag auf dem oder den Servern löschen - für die temporäre Sperre ein durchaus gangbarer Weg. Was ist aber wenn ein User-Zertifikat abhanden gekommen ist oder wenn der Admin gekündigt hat oder in seinen wohlverdienten Ruhestand verabschiedet? Ganz einfach, wir sperren das kompromittierte Zertifikat und stellen dem Admin ein neues Zertifikat aus, oder im Falle des Ausscheidens begnügen wir uns mit der Sperre dieses einen Zertifikats.
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 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.
# vim /etc/ssh/sshd_config
... # Specifies revoked public keys file, or none to not use one. Keys listed # in this file will be refused for public key authentication. Note that if # this file is not readable, then public key authentication will be re- # fused for all users. Keys may be specified as a text file, listing one # public key per line, or as an OpenSSH Key Revocation List (KRL) as gene- # rated by ssh-keygen. RevokedKeys /etc/ssh/ssh_ca_krl ...
Bevor wir den Daemon nun neu starten vergewissern wir uns nochmals, ob die Datei auch wirklich vorhanden ist, denn wenn diese Datei nicht lesbar ist wird die Authentifizierung mit öffentlichen Schlüsseln für alle Benutzer verweigert!
# ls -Al /etc/ssh/ssh_ca_krl
-rw-r--r-- 1 root root 121 Nov 27 13:42 /etc/ssh/ssh_ca_krl
Alles klar, diese Datei ist vorhanden und für alle auch lesbar, wir können also den SSH-Daemon neu starten.
# systemctl restart sshd.service
● sshd.service - OpenSSH server daemon Loaded: loaded (/usr/lib/systemd/system/sshd.service; enabled; vendor preset: enabled) Active: active (running) since Mon 2023-11-27 02:34:19 CET; 15s ago Docs: man:sshd(8) man:sshd_config(5) Main PID: 1777 (sshd) Tasks: 1 CGroup: /system.slice/sshd.service └─1777 /usr/sbin/sshd -D Nov 27 02:34:02 pml010002.intra.nausch.org systemd[1]: Starting OpenSSH server daemon... Nov 27 02:34:02 pml010002.intra.nausch.org sshd[16129]: Server listening on 10.0.10.2 port 22. Nov 27 02:34:02 pml010002.intra.nausch.org systemd[1]: Started OpenSSH server daemon.
Mit dem Programm ssh-keygen
sind wir in der Lage, Key Revocation Lists (KRLs) im OpenSSH-Format zu verwalten. Diese Binärdateien geben die zu sperrenden Schlüssel oder Zertifikate in einem kompakten Format an, das nur ein Bit pro Zertifikat benötigt, wenn sie nach Seriennummer gesperrt werden.
KRLs können mit dem Option -k
erzeugt werden. Diese Option liest eine oder mehrere Dateien von der Befehlszeile und erzeugt eine neue KRL. Die Dateien können entweder eine KRL-Spezifikation oder öffentliche Schlüssel enthalten, die einzeln pro Zeile aufgeführt werden. Einfache öffentliche Schlüssel werden widerrufen, indem ihr Hash oder ihr Inhalt in der KRL aufgelistet wird, und Zertifikate werden anhand der Seriennummer oder der Schlüssel-ID widerrufen.
Das Widerrufen von Schlüsseln mit Hilfe einer KRL-Spezifikation bietet eine explizite Kontrolle über die Arten von Aufzeichnungen, die zum Widerrufen von Schlüsseln verwendet werden, und kann verwendet werden, um Zertifikate direkt nach Seriennummer oder Schlüssel-ID zu widerrufen, ohne das vollständige Originalzertifikat zur Hand zu haben. Eine KRL-Spezifikation besteht aus Zeilen, die eine der folgenden Direktiven enthalten, gefolgt von einem Doppelpunkt und einigen richtlinienspezifischen Informationen.
serial: serial_number[-serial_number]
Widerruft ein Zertifikat mit der angegebenen Seriennummer. Seriennummern sind 64-Bit-Werte (ohne Null) und können dezimal, hexadezimal oder oktal angegeben werden. Wenn zwei Seriennummern durch einen Bindestrich getrennt angegeben werden, dann wird der Bereich der Seriennummern einschließlich und zwischen den beiden Nummern widerrufen. Der CA-Schlüssel muss in der Befehlszeile von ssh-keygen mit der Option -s angegeben worden sein.id: schlüssel_id
Widerruft ein Zertifikat mit der angegebenen Schlüssel-ID-Zeichenkette. Der CA-Schlüssel muss in der Befehlszeile von ssh-keygen mit der Option -s angegeben worden sein.key: public_key
Widerruft den angegebenen Schlüssel. Wenn ein Zertifikat aufgeführt ist, wird es als einfacher öffentlicher Schlüssel widerrufen.sha1: public_key
Widerruft den angegebenen Schlüssel anhand seines SHA1-Hashes.
KRLs können mit dem Option -u
zusätzlich zu -k
aktualisiert werden. Wenn diese Option angegeben wird, werden die über die Befehlszeile aufgelisteten Schlüssel in die KRL eingefügt und zu den bereits vorhandenen hinzugefügt.
Es ist auch möglich, anhand einer KRL zu prüfen, ob sie einen bestimmten Schlüssel (oder mehrere Schlüssel) widerruft. Mit dem Flag -Q wird eine vorhandene KRL abgefragt, wobei jeder in der Befehlszeile angegebene Schlüssel getestet wird. Wurde ein in der Befehlszeile aufgeführter Schlüssel widerrufen wurde (oder ein Fehler aufgetreten ist), wird ssh-keygen mit einem Exit-Status ungleich Null beendet. Ein Exit-Status von Null wird nur zurückgegeben, wenn kein Schlüssel widerrufen wurde.
Beim Widerrufen Revoken eines Zertifikates gehen wir am besten wir folgt vor:
- Seriennummer des Zertifikats ermitteln
Damit wir später ganz gezielt ein und nur ein ganz bestimmtes Zertifikat revoken können bedienen wir uns am Besten an der Serien-Nummer des Zertifikates. Diese ermitteln wir nun wie folgt.# ssh-keygen -L -f /etc/ssh/ssh_ca/id_ed25519_test-cert.pub
/etc/ssh/ssh_ca/id_ed25519_test-cert.pub: Type: ssh-ed25519-cert-v01@openssh.com user certificate Public key: ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 Signing CA: ED25519 SHA256:iRZv/JZQRbMjshPjKavpy7X5mvxRzAOERXrnUzhHGiU (using ssh-ed25519) Key ID: "django" Serial: 4 Valid: from 2023-11-27T17:58:00 to 2024-11-26T17:59:50 Principals: django Critical Options: (none) Extensions: permit-X11-forwarding permit-agent-forwarding permit-port-forwarding permit-pty permit-user-rc
Wir sehen also hier die
Serial: 4
(Serien-Nummer) und denPrincipals: 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:ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub
/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): ok
Das Zertifikat ist aktuell also noch gültig!
- Revoken des Zertifikates
Zum Rückrufen des Zertifikates mit der Seriennummer4
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!# ssh-keygen -u -k -f /etc/ssh/ssh_ca/ssh_ca_krl -z 4 /etc/ssh/ssh_ca/id_ed25519_test-cert.pub
Revoking from /etc/ssh/ssh_ca/id_ed25519_test-cert.pub
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:ssh-keygen -Qf /etc/ssh/ssh_ca/ssh_ca_krl /etc/ssh/ssh_ca/id_ed25519_test.pub
/etc/ssh/ssh_ca/id_ed25519_test.pub (django@nausch.org): REVOKED
Das Zertifikat ist also definitiv gesperrt/zurückgerufen!
Versucht der Admin sich nun erneut mit dem Host unter Verwendung seines Zertifikates, welches wir soeben revoked haben, wird dies erwartungsgemäss scheitern.
$ ssh -v kvm
...
debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:kIe5Ki/ItvQq9Cpfw/qLReo1wiVkdREVOz6a67I8nO4, serial 1000 ID "kvm" CA ssh-ed25519 SHA256:wOyuN+fm0j83vkViB9Lx2PIiQHRkWD9jBJKRqhEplzk valid from 2023-11-27T12:27:00 to 2024-11-26T12:28:44
debug1: load_hostkeys: fopen /home/django/.ssh/known_hosts2: No such file or directory
debug1: load_hostkeys: fopen /etc/ssh/ssh_known_hosts2: No such file or directory
debug1: Host 'kvm.intra.nausch.org' is known and matches the ED25519-CERT host certificate.
debug1: Found CA key in /etc/ssh/ssh_known_hosts:1
...
Der Server präsentierte sein gültiges Zertifikat, soweit so gut, aber der Entscheidende Punkt folgt sofort:
...
debug1: Offering public key: /home/django/.ssh/id_ed25519_dmz-cert.pub ED25519-CERT SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 explicit
debug1: Authentications that can continue: publickey
debug1: Offering public key: /home/django/.ssh/id_ed25519_dmz ED25519 SHA256:IqPRdnvM1+xSqaESGaxmfevXUsay8yRKPm9sn3eHTz0 explicit agent
debug1: Authentications that can continue: publickey
debug1: No more authentication methods to try.
django@kvm.intra.nausch.org: Permission denied (publickey).
Der Client wird mit seinem Zertifikat zurückgewiesen, welches ja revoked wurde. Auch der Anmeldeversuch nur mit dem unsignierten SSH-Key schlägt fehl, da wir das ja auch explizit verboten hatten!
Fazit und Ausblick
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.
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 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.