SSH-Zertifikate und Hashicorp Vault

Es ist schon ein bißchen länger her, da hatte ich den Blog von Marc Päpper (s. unten) gelesen und erfahren, dass ssh, was ich ja täglich benutze, tatsächlich eine Funktion hat, von der ich noch nie gehört hatte: "Zertifikate".

Wer die man-Page von "ssh-keygen" aufmerksam liest oder nach "CERTIFICATES" sucht, findet dort diesen Eintrag:

CERTIFICATES
     ssh-keygen supports signing of keys to produce certificates that may be used for user or host authentication.  Certificates consist of a public key, some identity information, zero or more principal
     (user or host) names and a set of options that are signed by a Certification Authority (CA) key.  Clients or servers may then trust only the CA key and verify its signature on a certificate rather than
     trusting many user/host keys.  Note that OpenSSH certificates are a different, 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 certifi‐
 cate:

           $ 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 certificate option may disable features of the SSH session, may be valid only when
     presented from particular source addresses or may force the use of a specific command.  For a list of valid certificate options, see the documentation for the -O option above.

     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 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).  Please refer to those manual pages for details.

Im Grunde ist das Prinzip ganz einfach: Sowohl Server als auch User vertrauen beide einer "Certificate Authority" (CA). Mit einem von dieser CA signierten ssh public-key, kann sich eine Userin  dann an einem Server einloggen. Im Grunde ist das dieselbe Konstellation wie beim Webbrowser, der auch vielen CAs vertraut - insbesondere denen, die die SSL-Zertifikate der Webserver ausgestellt haben. 

In seinem Artikel schreibt Marc Päpper, dass man einen Dienst bräuchte, der automatisch einen ssh public-key signieren kann, wenn man sich vorher bei ihm mit Username/Passwort authorisiert hat. So ein Dienst ist die "SSH Secrets Engine" vom Hashicorp Vault. Nur damit man es mal gesehen hat - hier die Sammlung an Secrets Engines, die im Vault aktiviert werden können:

Viele der Tutorials, die beschreiben, wie man signierte SSH Schlüssel einsetzt, bleiben leider beim Signieren der ssh public-keys stehen. Der Artikel von Brian Candler (s. rechts) geht nicht nur darauf ein sondern widmet sich außerdem noch dem Erstellen von Rollen und Gruppen, die für ein Authorisierungssystem nicht fehlen dürfen.

Für die User Authentisierung stehen im Vault folgende Möglichkeiten zur Verfügung:

In einem Unternehmen, welches bereits über ein Active Directory verfügt, würde vermutlich "LDAP" zum Einsatz kommen. Für einfache Setups kann man auch "Username & Password" wählen. Es spricht übrigens auch nichts dagegen mehrere Methoden und Secret Engines parallel (oder mehrere Instanzen von einer) zu verwenden. Die Secret Engines und Authentication Methoden werden wie in einem Dateibaum in Vault "gemountet" (früher hieß der Befehl zur Aktivierung sogar so), sodaß einfach dieselben Instanzen unter verschiedenen Namen parallel existieren können.

Ausserdem geht Candler auf die Situation mit alten und neueren Versionen von OpenSSH ein, welche in einem GitHub-Issue (s. rechts) genauer erläutert sind.

Die Tutorials kann eigentlich jeder nachvollziehen, da Hashicorp bei seinen Serverprodukten Consul, Vault und Nomad einen "Development"-Modus einbaut, der es erlaubt, ohne langes Hantieren sofort zu starten. Einfach das Binary bei https://releases.hashicorp.com/ herunterladen, auspacken und mit "vault server -dev" starten. Wenn man nicht auf dem lokalen Arbeitsplatz sondern in einer virtuellen Instanz z. B. in einer Cloud arbeitet, kann man noch deren Adresse angeben, damit man auf die Weboberfläche von Vault zugreifen kann: 

root@vtest1:~# vault server -dev -dev-listen-address="10.65.69.202:8200"                                 
==> Vault server configuration:                     
                                                                                                       
             Api Address: http://10.65.69.202:8200  
                     Cgo: disabled                                                                       
         Cluster Address: https://10.65.69.202:8201 
              Go Version: go1.16.9                  
              Listener 1: tcp (addr: "10.65.69.202:8200", cluster address: "10.65.69.202:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: info
                   Mlock: supported: true, enabled: false
           Recovery Mode: false
                 Storage: inmem
                 Version: Vault v1.8.5
             Version Sha: 647eccfe0bd5817bdd8628f3c3171402dfc8a8fc

==> Vault server started! Log data will stream in below:

2021-11-17T15:48:21.045Z [INFO]  proxy environment: http_proxy="" https_proxy="" no_proxy=""
2021-11-17T15:48:21.046Z [WARN]  no `api_addr` value specified in config or in VAULT_API_ADDR; falling back to detection if possible, but this value should be manually set
2021-11-17T15:48:21.051Z [INFO]  core: security barrier not initialized
2021-11-17T15:48:21.051Z [INFO]  core: security barrier initialized: stored=1 shares=1 threshold=1
2021-11-17T15:48:21.052Z [INFO]  core: post-unseal setup starting
2021-11-17T15:48:21.072Z [INFO]  core: loaded wrapping token key
2021-11-17T15:48:21.072Z [INFO]  core: successfully setup plugin catalog: plugin-directory=""
2021-11-17T15:48:21.072Z [INFO]  core: no mounts; adding default mount table
2021-11-17T15:48:21.075Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
2021-11-17T15:48:21.075Z [INFO]  core: successfully mounted backend: type=system path=sys/
2021-11-17T15:48:21.075Z [INFO]  core: successfully mounted backend: type=identity path=identity/
2021-11-17T15:48:21.079Z [INFO]  core: successfully enabled credential backend: type=token path=token/
2021-11-17T15:48:21.080Z [INFO]  core: restoring leases
2021-11-17T15:48:21.084Z [INFO]  rollback: starting rollback manager
2021-11-17T15:48:21.086Z [INFO]  identity: entities restored
2021-11-17T15:48:21.086Z [INFO]  identity: groups restored
2021-11-17T15:48:21.086Z [INFO]  core: post-unseal setup complete
2021-11-17T15:48:21.087Z [INFO]  core: root token generated
2021-11-17T15:48:21.087Z [INFO]  core: pre-seal teardown starting
2021-11-17T15:48:21.088Z [INFO]  expiration: lease restore complete
2021-11-17T15:48:21.097Z [INFO]  rollback: stopping rollback manager
2021-11-17T15:48:21.097Z [INFO]  core: pre-seal teardown complete
2021-11-17T15:48:21.098Z [INFO]  core.cluster-listener.tcp: starting listener: listener_address=10.65.69.202:8201
2021-11-17T15:48:21.098Z [INFO]  core.cluster-listener: serving cluster requests: cluster_listen_address=10.65.69.202:8201
2021-11-17T15:48:21.098Z [INFO]  core: post-unseal setup starting
2021-11-17T15:48:21.098Z [INFO]  core: loaded wrapping token key
2021-11-17T15:48:21.098Z [INFO]  core: successfully setup plugin catalog: plugin-directory=""
2021-11-17T15:48:21.099Z [INFO]  core: successfully mounted backend: type=system path=sys/
2021-11-17T15:48:21.100Z [INFO]  core: successfully mounted backend: type=identity path=identity/
2021-11-17T15:48:21.100Z [INFO]  core: successfully mounted backend: type=cubbyhole path=cubbyhole/
2021-11-17T15:48:21.102Z [INFO]  core: successfully enabled credential backend: type=token path=token/
2021-11-17T15:48:21.102Z [INFO]  core: restoring leases
2021-11-17T15:48:21.103Z [INFO]  expiration: lease restore complete
2021-11-17T15:48:21.103Z [INFO]  rollback: starting rollback manager
2021-11-17T15:48:21.103Z [INFO]  identity: entities restored
2021-11-17T15:48:21.103Z [INFO]  identity: groups restored
2021-11-17T15:48:21.103Z [INFO]  core: post-unseal setup complete
2021-11-17T15:48:21.103Z [INFO]  core: vault is unsealed
2021-11-17T15:48:21.107Z [INFO]  core: successful mount: namespace="" path=secret/ type=kv
2021-11-17T15:48:21.115Z [INFO]  secrets.kv.kv_c1dd96f8: collecting keys to upgrade
2021-11-17T15:48:21.115Z [INFO]  secrets.kv.kv_c1dd96f8: done collecting keys: num_keys=1
2021-11-17T15:48:21.115Z [INFO]  secrets.kv.kv_c1dd96f8: upgrading keys finished
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variable:

    $ export VAULT_ADDR='http://10.65.69.202:8200'

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: JnudUChjBgEjBEUFRAeRJNAasvIzLliEfdzJt9zDQO8=
Root Token: geheim

Development mode should NOT be used in production installations!

Mit der Version 1.10 von Vault hat HashiCorp auch Multi Factor Authentication für die OSS-Version von Vault freigegeben. Es werden die Methoden

  • Time-Based One-Time Password (TOTP)
  • Okta
  • Duo
  • PingIdentity

unterstützt.


Links:

Using Vault as an SSH certificate authority

VAULT: CONNECTING ENTITIES, AUTH BACKENDS, GROUPS, AND POLICIES OH MY

How to properly manage ssh keys for server access

Signed SSH Certificates

If you’re not using SSH certificates you’re doing SSH wrong

Managing SSH Access at Scale with HashiCorp Vault

https://github.com/hashicorp/vault/issues/11608


Videos: