2022.12.25 - SSH Certificates
Intro
Ostatnio pracuję nad zestawieniem HomeLab/2, a przerwa świąteczna pozwala pobawić się nowymi tematami. Może nie aż tak nowymi bo z 2020 roku, ale nadal mało popularnymi.
Przygotowanie CA
Pierwszym krokiem jest przygotowanie CA do podpisywania kluczy publicznych hostów i userów. Może być jeden wspólny, może być kilka dedytkowanych.
Nowe CA można wygenerować przy pomocy ssh-keygen
# generate new CA
$ ssh-keygen -t rsa -b 4096 -f trusted_user_ca -C 'SSH Validation CA'
Na razie używam pfSense do zarządzania certami, więc nowe subCA tam wygenerowałem. Po ściągnięciu certa i klucza prywatnego należało je przekonwertować na format zrozumiały dla ssh-keygen.
# convert openssl to openssh
$ openssl x509 -inform pem -in nerdoza-studio-ssh-ca.crt -noout -pubkey > nerdoza-studio-ssh-ca.pubkey
$ ssh-keygen -i -f nerdoza-studio-ssh-ca.pubkey -m PKCS8 > nerdoza-studio-ssh-ca.pub
Konfiguracja serwera
Podpisanie kluczy publicznych serwera
Żeby podpisać klucze publiczne musimy mieć pod ręką klucz prywatny CA. Oczywiście poszedłem po linii najmniejszego oporu i po prostu wrzuciłem CA.pub i CA.key bezpośrenio na serwer docelowy do /etc/ssh 🙂 Klucz publiczny musi być w formacie OpenSSL (zaczynać się np. od ssh-rsa)
# sign public keys
$ ssh-keygen -s nerdoza-studio-ssh-ca.key -I serwer.nerdoza.studio -h -n serwer.nerdoza.studio -V -5m:+3650d ssh_host_rsa_key.pub
https://www.man7.org/linux/man-pages/man1/ssh-keygen.1.html
-s- podpisanie klucza prywatnego wybranym kluczem CA (CA.key)-I- ustawienie tożsamości podpisywanego klucza-h- utworzenie certyfikatu hosta zamiast certyfikatu usera-n- lista principalsów (nazwa hosta)-V- okres ważności certyfikatu (5min wstecz, 10lat do przodu)
Operacje wykonałem dla każdego typu klucza: rsa, ecdsa i ed25519.
W odpowiedzi dostałem potwierdzenie utworzenia certyfikatu.
Signed host key serwer-cert.pub: id "serwer.nerdoza.studio" serial 0 for serwer.nerdoza.studio valid from 2022-12-26T19:32:27 to 2032-12-23T19:37:27
# view certificate
$ ssh-keygen -Lf serwer-cert.pub
Konfiguracja sshd
Żeby skorzystać z certów po stronie serwera należy dodać następujące opcje do sshd_config.
HostKey /etc/ssh/ssh_host_rsa_key
HostKey /etc/ssh/ssh_host_ecdsa_key
HostKey /etc/ssh/ssh_host_ed25519_key
HostCertificate /etc/ssh/ssh_host_rsa_key-cert.pub
HostCertificate /etc/ssh/ssh_host_ecdsa_key-cert.pub
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
PubkeyAuthentication yes
# Accept user certs signed by this CA
TrustedUserCAKeys /etc/ssh/nerdoza-studio-ssh-ca.pub
# RevokedKeys /etc/ssh/revoked_keys
Na koniec trzeba zrestartować sshd
$ systemctl restart sshd
Lista odwołanych kluczy czyli KRL
SSH przyjmuje dwa rodzaje pliku z odwołanymi kluczami - plik tekstowy albo plik binarny:
RevokedKeys
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 refused 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 generated by ssh-keygen(1). For more information on KRLs, see the KEY
REVOCATION LISTS section in ssh-keygen(1).
Dla pliku tekstowego wystarczy wpisać po jednym kluczu per linia
ssh-rsa AAAAB...
ssh-rsa AAAAB...
W przypadku pliku binarnego trzeba nim zarządzać przez ssh-keygen.
https://www.man7.org/linux/man-pages/man1/ssh-keygen.1.html#KEY_REVOCATION_LISTS
Opcji jest kilka - odwołanie przez serial number, public key albo hash to te które mnie interesowały.
Hash można wyciągnąć z /var/log/auth.log
$ cat revoke.txt
---
hash: SHA256:XXXXXXXXXXXXXXXXXX
# create new KRL
$ ssh-keygen -k -f /etc/ssh/revoked_keys revoke.txt
# update KRL
$ ssh-keygen -k -u -f /etc/ssh/revoked_keys revoke.txt
Na razie nie używam KRL, ale konfigurację mam przygotowaną.
# !!! IMPORTANT - file must be readable or SSH will deny all users !!!
$ touch /etc/ssh/revoked_keys
# uncomment in sshd_config
RevokedKeys /etc/ssh/revoked_keys
Na koniec można przełączyć niektóre opcje sshd.
PasswordAuthentication no
# restrict pubkeys to certs only - PubkeyAcceptedKeyTypes or PubkeyAcceptedAlgorithms depending on sshd version
PubkeyAcceptedKeyTypes ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com
Akceptacja certyfikatu hosta przez klienta
Konfiguracja ssh
Dodajemy CA.pub do known_hosts
@cert-authority *.nerdoza.studio ssh-rsa AAAAB...
Konfiguracja Putty
Tutaj jest więcej zabawy i dodatkowo potrzeba Putty w wersji 0.78+
Wybieramy Configure host CAs
Ustawiamy nazwę, ładujemy zawartość z pliku, dodajemy listę hostów (analogicznie do known_hosts)
W rejestrze pojawią się nowe wpisy
Konfiguracja klienta
Podpisanie klucza
Klucz podpisujemy analogicznie do podpisu serwera jednak bez opcji -h.
# sign public key
$ ssh-keygen -s ssh-ca.key -I myuser@myhost -n myuser -V -5m:+3650d myid_rsa.pub
-n- lista principalsów (domyślnie nazwy użytkowników, którymi loguje się klient, jeśli serwer nie ma ustawionej opcji AuthorizedPrincipalsFile)
https://man.openbsd.org/sshd_config.5#AuthorizedPrincipalsFile
Konfiguracja ssh
Dodajemy wpisy do pliku ~/.ssh/config. Dodatkowo ustawiłem listę używanych algorytmów algorytmów (tylko certy).
https://man.openbsd.org/ssh_config#PubkeyAcceptedAlgorithms
Host myhost
IdentitiesOnly yes
IdentityFile ~/.ssh/myid_rsa
PubkeyAcceptedAlgorithms ssh-ed25519-cert-v01@openssh.com,ecdsa-sha2-nistp256-cert-v01@openssh.com,ecdsa-sha2-nistp384-cert-v01@openssh.com,ecdsa-sha2-nistp521-cert-v01@openssh.com,sk-ssh-ed25519-cert-v01@openssh.com,sk-ecdsa-sha2-nistp256-cert-v01@openssh.com,rsa-sha2-512-cert-v01@openssh.com,rsa-sha2-256-cert-v01@openssh.com
User myuser
Weryfikujemy połączenie przez dodanie -v do komendy ssh.
(...)
debug1: Reading configuration data C:\\Users\\#####/.ssh/config
debug1: C:\\Users\\#####/.ssh/config line 4: Applying options for serwer.nerdoza.studio
debug1: C:\\Users\\#####/.ssh/config line 7: Applying options for *
debug1: Connecting to serwer.nerdoza.studio [192.*.*.*] port 22.
debug1: Connection established.
debug1: identity file C:\\Users\\#####/.ssh/mykey_rsa type 0
debug1: identity file C:\\Users\\#####/.ssh/mykey_rsa-cert type 4
debug1: Authenticating to serwer.nerdoza.studio:22 as '#####'
debug1: Server host certificate: ssh-ed25519-cert-v01@openssh.com SHA256:#####, serial 0 ID "serwer.nerdoza.studio" CA ssh-rsa SHA256:##### valid from 2022-12-26T02:22:00 to 2032-12-23T02:23:17
debug1: Host 'serwer.nerdoza.studio' is known and matches the ED25519-CERT host certificate.
debug1: Found CA key in C:\\Users\\#####/.ssh/known_hosts:1
debug1: Skipping ssh-rsa key C:\\Users\\#####/.ssh/mykey_rsa - corresponding algo not in PubkeyAcceptedAlgorithms
debug1: Will attempt key: C:\\Users\\#####/.ssh/mykey_rsa RSA-CERT SHA256:##### explicit
debug1: Authentications that can continue: publickey
debug1: Next authentication method: publickey
debug1: Offering public key: C:\\Users\\#####/.ssh/mykey_rsa RSA-CERT SHA256:##### explicit
debug1: Server accepts key: C:\\Users\\#####/.ssh/mykey_rsa RSA-CERT SHA256:##### explicit
debug1: Authentication succeeded (publickey).
Authenticated to serwer.nerdoza.studio ([192.*.*.*]:22).
(...)
Konfiguracja Putty
Najpierw należy przekonwertować klucz prywatny do postaci PPK.
https://gcore.com/support/articles/360012640597/
Następnie konfigurację w Putty ustawiam per sesję.
Podczas połączenia wyskakuje monit o hasło do klucza prywatnego (PPK).
Użycie certów możemy zweryfikować w logu Puttiego (włączamy przez Session → Logging)
(...)
Incoming packet #0x2, type 21 / 0x15 (SSH2_MSG_NEWKEYS)
Event Log: Server also has ssh-ed25519/ecdsa-sha2-nistp256/rsa-sha2-512/rsa-sha2-256/ssh-rsa/ecdsa-sha2-nistp256-cert-v01@openssh.com/rsa-sha2-512-cert-v01@openssh.com/rsa-sha2-256-cert-v01@openssh.com/ssh-rsa-cert-v01@openssh.com host keys, but we don't know any of them
Event Log: Host key fingerprint is:
Event Log: ssh-ed25519-cert-v01@openssh.com 255 SHA256:#####
Event Log: Host key is a certificate. Hash including certificate:
Event Log: ssh-ed25519-cert-v01@openssh.com 255 SHA256:#####
Event Log: Certificate ID string is "serwer.nerdoza.studio"
Event Log: Fingerprint of certification authority:
Event Log: ssh-rsa 4096 SHA256:#####
Event Log: Certification authority matches 'nerdoza-studio-ssh-ca'
Event Log: Accepted certificate
Outgoing packet #0x2, type 21 / 0x15 (SSH2_MSG_NEWKEYS)
(...)
Incoming packet #0x4, type 6 / 0x06 (SSH2_MSG_SERVICE_ACCEPT)
Event Log: Reading key file "C:\Users\#####\.ssh\mykey_rsa.ppk"
Event Log: Reading certificate file "C:\Users\#####\.ssh\mykey_rsa-cert.pub"
Outgoing packet #0x4, type 50 / 0x32 (SSH2_MSG_USERAUTH_REQUEST)
Incoming packet #0x5, type 51 / 0x33 (SSH2_MSG_USERAUTH_FAILURE)
Event Log: Sending public key with certificate from "C:\Users\#####\.ssh\mykey_rsa-cert.pub"
Event Log: Offered public key
Outgoing packet #0x5, type 50 / 0x32 (SSH2_MSG_USERAUTH_REQUEST)
Incoming packet #0x6, type 60 / 0x3c (SSH2_MSG_USERAUTH_PK_OK)
Event Log: Offer of public key accepted
Event Log: Sent public key signature
Outgoing packet #0x6, type 50 / 0x32 (SSH2_MSG_USERAUTH_REQUEST)
Incoming packet #0x7, type 52 / 0x34 (SSH2_MSG_USERAUTH_SUCCESS)
Event Log: Access granted
Event Log: Opening main session channel
(...)
Linki
- https://en.wikibooks.org/wiki/OpenSSH/Cookbook/Certificate-based_Authentication
- https://goteleport.com/blog/how-to-configure-ssh-certificate-based-authentication/
- https://www.lorier.net/docs/ssh-ca.html
- https://www.man7.org/linux/man-pages/man1/ssh-keygen.1.html#KEY_REVOCATION_LISTS
- https://the.earth.li/~sgtatham/putty/0.78/htmldoc/Chapter4.html#config-ssh-auth-creds
- https://sleeplessbeastie.eu/2020/02/17/how-to-revoke-specific-key-used-to-login-with-openssh/
- https://www.youtube.com/watch?v=lYzklWPTbsQ