RE:NODE

AuthorizedKeysFile v sshd_config: tokeny, cesty a testování

Text: Tým RE:NODE
15 min čtení


AuthorizedKeysFile říká démonu sshd, kde má hledat veřejné klíče, kterými se uživatel smí přihlásit. Pokud ho nenastavíš, OpenSSH zkontroluje .ssh/authorized_keys a .ssh/authorized_keys2 v domovském adresáři uživatele, i když mnoho distribucí dodává konfiguraci, která výběr zúží jen na první z nich. Změnu uděláš z jednoho ze tří důvodů: abys dostal klíče z rukou uživatelů do adresáře vlastněného rootem, například /etc/ssh/authorized_keys/%u, abys je mohl číst ještě před připojením domovského adresáře, nebo abys jedné skupině účtů dal jiný zdroj klíčů přes blok Match.

Nastavení je krátké, ale následky chyby jsou velké. Nasměruj ho na místo, které sshd považuje za nebezpečné, nebo zapomeň, že výchozí hodnotu nahrazuje, a ne doplňuje, a na celém stroji přestanou najednou fungovat všechna přihlášení klíčem - včetně tvého. Tento článek popisuje, co direktiva přijímá, jak postavit centrální adresář klíčů, který projde kontrolou StrictModes, jak spolupracuje s sshd_config.d a Match a jak před zavřením relace, na kterou se spoléháš, ověřit, že změna funguje. Generování klíčů, agenty a obecný seznam opatření najdeš v článku SSH klíče a zabezpečení sshd_config; tady je jedna direktiva do hloubky.

K čemu je AuthorizedKeysFile a jaká je výchozí hodnota#

Při autentizaci veřejným klíčem klient nabídne veřejný klíč a sshd ho hledá v souborech uvedených v AuthorizedKeysFile, v daném pořadí. Vyhrává první soubor, který obsahuje odpovídající řádek, a volby na začátku tohoto řádku (restrict, from=, command= a další) se použijí na relaci. Pokud klíč neobsahuje žádný z uvedených souborů, je odmítnut a klient přejde na další klíč nebo metodu.

Zabudovaná výchozí hodnota v současném OpenSSH je:

code
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2

Co skutečně dostaneš, záleží na dodaném konfiguračním souboru:

DistribuceDodaný řádekPlatná hodnota
Debian, Ubuntuzakomentovanýoba soubory
RHEL, Rocky, Alma, Fedora.ssh/authorized_keysjeden soubor
Ukázka z upstreamu OpenSSH.ssh/authorized_keysjeden soubor

authorized_keys2 je pozůstatek přechodu z protokolu SSH 1 na 2 a je zastaralý už přes dvacet let. Nikdo by do něj neměl ukládat klíče, a právě proto stojí za to ho vyloučit: soubor, na který se nikdo nedívá, je dobré místo, kam útočník, který na chvíli získal shell, nechá klíč. Explicitní nastavení hodnoty na .ssh/authorized_keys je na Debianu a Ubuntu malé a bezpečné vylepšení.

Legální jsou ještě dvě další hodnoty. none úplně vypne klíče v souborech, což dává smysl jen tehdy, když klíče pocházejí z AuthorizedKeysCommand (viz níže) nebo se ověřuje certifikátem. A protože se direktiva může objevit uvnitř Match, hodnota se může lišit podle uživatele, skupiny nebo zdrojové adresy.

Změny obsahu souboru s autorizovanými klíči se projeví při příštím přihlášení bez reloadu, protože sshd čte soubor v okamžiku autentizace. Změny samotné direktivy AuthorizedKeysFile vyžadují, aby sshd znovu načetl konfiguraci.

Cesty a tokeny %h, %u, %U a %%#

Po expanzi tokenů se každá hodnota bere buď jako absolutní cesta, nebo jako cesta relativní k domovskému adresáři uživatele. Proto funguje holé .ssh/authorized_keys: před ním je implicitně domovský adresář.

TokenExpanduje se naPříklad výsledku
%hdomovský adresář/home/alice
%uuživatelské jménoalice
%Učíselné ID uživatele1001
%%doslovné %%

%U přijímají současná vydání OpenSSH; starší znají jen %h, %u a %%, takže se před použitím podívej do man sshd_config na daném stroji. Domovský adresář se bere z databáze hesel (/etc/passwd nebo LDAP přes NSS), ne z $HOME, takže ho uživatel nemůže přesměrovat proměnnou prostředí.

Několik ekvivalentních i neekvivalentních zápisů, protože na rozdílech se často chybuje:

code
# These two are the same fileAuthorizedKeysFile .ssh/authorized_keysAuthorizedKeysFile %h/.ssh/authorized_keys# Absolute, one file per user, outside the home directoryAuthorizedKeysFile /etc/ssh/authorized_keys/%u# Not what it looks like: relative to the home directory, so /home/alice/etc/keysAuthorizedKeysFile etc/keys

Vlnovka není v této direktivě token. Když myslíš domovský adresář, napiš %h. A %u se použije doslovně, takže uživatelské jméno se znaky, které souborový systém nemá rád (vzácné, ale účty z LDAP a Active Directory někdy nesou doménovou příponu), se stane součástí názvu souboru. Podívej se na expandovanou cestu ve výstupu ladění popsaném níže a nespoléhej na domněnky.

Více souborů najednou#

Několik cest se zapisuje na jeden řádek oddělených mezerami. Prohledávají se v pořadí a vyhrává první shoda.

/etc/ssh/sshd_config.d/20-keys.conf
AuthorizedKeysFile /etc/ssh/authorized_keys/%u .ssh/authorized_keys

Tak vypadá migrace. Klíče spravované centrálně - tebou, nástrojem pro správu konfigurace nebo provisioning skriptem - leží pod /etc/ssh a vlastní soubor každého uživatele dál funguje, dokud lidi přesouváš. Chybějící soubor není chyba: sshd si ho poznamená na úrovni debug a zkusí další. Nastavení tak můžeš nasadit na celou flotilu dřív, než bude mít centrální soubor každý uživatel.

Pořadí má význam v jedné situaci. Pokud je tentýž klíč v obou souborech s různými volbami, rozhoduje řádek z prvního souboru. Klíč omezený pomocí from= v centrálním souboru nerozvolní neomezená kopie v souboru uživatele, protože hledání končí u první shody - ale platí to i opačně, takže soubor, který ovládáš ty, dej na první místo.

Podstatný důsledek direktivy je, že nahrazuje výchozí hodnotu. Nastavení samotného AuthorizedKeysFile /etc/ssh/authorized_keys/%u znamená, že se od příštího reloadu ignoruje každý ~/.ssh/authorized_keys na stroji. Pokud je tvůj klíč jen v domovském adresáři, právě ses zamkl venku. Uvést během změny obě cesty je nejlevnější pojistka, jaká existuje.

Centrální adresář klíčů vlastněný rootem#

Hlavní důvod, proč měnit AuthorizedKeysFile, je kontrola. S výchozím nastavením může každý uživatel přidávat klíče do vlastního souboru, takže kdokoli, kdo kdy měl shell pod tímto uživatelem, může zanechat trvalou zadní vrátka, a každý audit musí číst soubory rozeseté po domovských adresářích. Adresář vlastněný rootem z otázky „kdo se smí přihlásit jako kdo“ udělá věc, která žije na jednom místě a mění se jen přes roota nebo tvůj nástroj pro správu konfigurace.

Řeší také dva praktické problémy: domovské adresáře na síťovém úložišti, které se připojí až po přihlášení, a šifrované domovské adresáře, které jsou nečitelné, dokud se uživatel neověří heslem. Soubor s klíči mimo /home je čitelný v okamžiku autentizace vždy.

Rozvržení:

bash
$ sudo mkdir -p /etc/ssh/authorized_keys$ sudo chown root:root /etc/ssh/authorized_keys$ sudo chmod 755 /etc/ssh/authorized_keys$ sudo cp /home/alice/.ssh/authorized_keys /etc/ssh/authorized_keys/alice$ sudo chown root:root /etc/ssh/authorized_keys/alice$ sudo chmod 644 /etc/ssh/authorized_keys/alice

Právě 644 lidé dělají špatně a je to proti intuici. sshd čte soubory s autorizovanými klíči s oprávněním cílového uživatele, ne jako root. Soubor root:root 600 je pro alice nečitelný, a tedy i pro sshd při kontrole jejího klíče, takže přihlášení selže. Veřejné klíče jsou veřejné; to, že je soubor čitelný pro všechny, neprozradí nic, co by útočník mohl použít. Nesmí se stát, aby do něj mohl zapisovat uživatel nebo kdokoli jiný.

Přijatelné jsou dva modely vlastnictví:

  • root:root, režim 644. Uživatel své klíče přečte, ale nezmění. V tom je smysl centrálního adresáře.
  • Vlastník uživatel, režim 600 nebo 644, v adresáři vlastněném rootem. Uživatel může upravovat svůj soubor, ale nemůže vytvářet ani mazat soubory ostatním. Kompromis, který ale vrací většinu toho, co jsi chtěl vzít.

Vedlejší efekt, na který upozorni kolegy: ssh-copy-id zapisuje do ~/.ssh/authorized_keys na druhé straně a o tvém nastavení nic neví. Ohlásí úspěch, a pokud už soubor v domovském adresáři v seznamu není, nainstalovaný klíč se nikdy nepoužije.

StrictModes a kontroly oprávnění#

StrictModes je ve výchozím stavu yes a tak by to mělo zůstat. Když je zapnuté, sshd před důvěrou v soubor s autorizovanými klíči zkontroluje soubor i každý adresář na cestě k němu. Pravidla ve zkratce:

ObjektMusí vlastnitNesmí být
Soubor s klíčiroot nebo uživatelzapisovatelný pro skupinu ani pro všechny
Každý adresář nad nímroot nebo uživatelzapisovatelný pro skupinu ani pro všechny
Domovský adresář uživateleroot nebo uživatelzapisovatelný pro skupinu ani pro všechny

Pokud cokoli selže, klíč je odmítnut a klient uvidí jen „Permission denied (publickey)“. Skutečný důvod je v logu serveru už na výchozí úrovni:

code
Authentication refused: bad ownership or modes for directory /home/alice

Tato zpráva je nejčastější příčinou „přestal mi fungovat klíč“ a obvykle ji způsobí něco, co s SSH nesouvisí: nasazovací skript, který na domovský adresář spustil chmod -R 775, skupinově zapisovatelný /home/alice vytvořený ovládacím panelem, nebo centrální adresář vytvořený účtem, který není root. Řešením je opravit oprávnění, nikdy ne nastavit StrictModes no. Vypnutí kontroly znamená, že uživateli, jehož domovský adresář je zapisovatelný pro skupinu, mohou klíče podstrčit všichni členové té skupiny.

U centrálního adresáře se kontroluje cesta /etc, /etc/ssh, /etc/ssh/authorized_keys a soubor. Na běžném systému jsou první dva už root:root 755. Problémy se objeví, když adresář leží na méně upraveném místě - pod /srv na svazku připojeném s podivnými oprávněními nebo na sdílení s mapovaným vlastnictvím. Článek Oprávnění a vlastnictví souborů herního serveru vysvětluje, jak číst výstup ls -l, pokud ti režimy nejsou samozřejmé.

Na systémech rodiny RHEL se zapnutým SELinuxem existuje druhá brána. Klíče v domovském adresáři potřebují štítek ssh_home_t, který po kopírování nebo obnově opraví restorecon -Rv ~/.ssh. Soubory pod /etc/ssh obvykle dědí štítek, který sshd přečte. Pokud zvolíš jiné umístění, příznak je stejný - odmítnuté přihlášení při čistých režimech souborů; zkontroluj ausearch -m avc -ts recent a adresář označ pomocí semanage fcontext, místo abys SELinux vypínal.

sshd_config.d, Include a vyhrává první hodnota#

Od OpenSSH 8.2 může sshd_config načítat další soubory pomocí Include. Debian 12, Ubuntu 22.04 a novější i nedávná vydání Fedory a RHEL dodávají hlavní soubor, jehož rané řádky zahrnují /etc/ssh/sshd_config.d/*.conf. Zahrnuté soubory se čtou v lexikálním pořadí, jako by byly vložené na místo řádku Include.

Přidej k tomu nejdůležitější pravidlo v sshd_config: u většiny klíčových slov se použije první získaná hodnota. Nastavení v /etc/ssh/sshd_config.d/10-local.conf má přednost před stejným nastavením níž v hlavním souboru a 10-local.conf má přednost před 50-cloud-init.conf, protože se řadí dřív. Když upravíš hlavní soubor a nic se nezmění, je to téměř vždy tohle.

Praktické rozvržení:

/etc/ssh/sshd_config.d/20-authorized-keys.conf
# Central keys first, the user's own file as a fallback during migrationAuthorizedKeysFile /etc/ssh/authorized_keys/%u .ssh/authorized_keys

Každou záležitost drž ve vlastním malém očíslovaném souboru. Než nějaký napíšeš, vypiš si, co už v adresáři je: cloudové image sem často pustí soubor, který nastavuje volby autentizace, a chceš o něm vědět dřív, než začneš testovat. Pak se spoléhej na sshd -T níže, které ti řekne, co vyhrálo, místo abys pořadí odvozoval ručně.

Bloky Match: jiné klíče pro jiné účty#

AuthorizedKeysFile je jedno z klíčových slov povolených uvnitř bloku Match, takže zdroj klíčů se může lišit podle uživatele, skupiny, zdrojové adresy nebo lokálního portu. Blok Match trvá do dalšího Match nebo do konce souboru, ve kterém je, takže bloky patří na konec souboru, za všechna globální nastavení. Match all blok výslovně ukončí, pokud se potřebuješ vrátit ke globálnímu kontextu.

Častý vzor: běžní zaměstnanci si ponechají vlastní authorized_keys, zatímco servisní účty a zákazníci jen s SFTP dostanou klíče, které může měnit jen root.

/etc/ssh/sshd_config.d/30-match.conf
Match Group sftp-only    AuthorizedKeysFile /etc/ssh/authorized_keys/%u    ChrootDirectory /srv/sftp/%u    ForceCommand internal-sftp    AllowTcpForwarding noMatch User deploy,backup    AuthorizedKeysFile /etc/ssh/authorized_keys/%u

Případ SFTP ukazuje, proč je tato dvojice užitečná. Autentizace probíhá před aplikací chrootu, takže soubor s klíči leží úplně mimo adresář, který uživatel vidí. Nemůže své klíče číst, nahrazovat ani k nim připisovat ze své SFTP relace, což by klíč v domovském adresáři pod chrootem dovolil.

Pamatuj, že i uvnitř Match platí pravidlo první hodnoty pro blok, který se shodoval. Pokud uživateli odpovídají dva bloky Match a oba nastavují AuthorizedKeysFile, vyhrává dřívější. Testuj konkrétního uživatele, ne jen soubor.

Testování pomocí sshd -t a sshd -T#

Dva přepínače, dva úkoly. Oba potřebují root, protože sshd chce číst své hostitelské klíče i při testu, a oba žijí v /usr/sbin/sshd, což nemusí být v PATH běžného uživatele.

sshd -t je kontrola syntaxe. Zparsuje každý soubor včetně každého Include a tiše skončí se stavem 0, pokud je konfigurace platná. Překlep v klíčovém slově, klíčové slovo nepovolené uvnitř Match nebo nečitelný hostitelský klíč vyvolá chybu a nenulový návratový kód. Spusť ho před každým reloadem, pokaždé.

sshd -T vypíše efektivní konfiguraci: každé klíčové slovo malými písmeny poté, co se uplatnily výchozí hodnoty, includy a pravidlo první hodnoty. Je to jediná spolehlivá odpověď na otázku „co bude sshd skutečně dělat“. Přidej -C, aby se vyhodnotily bloky Match pro konkrétní spojení:

bash
$ sudo sshd -t && echo config okconfig ok$ sudo sshd -T | grep -i authorizedkeysfileauthorizedkeysfile /etc/ssh/authorized_keys/%u .ssh/authorized_keys$ sudo sshd -T -C user=deploy,host=laptop,addr=203.0.113.50 | grep -i authorizedkeysauthorizedkeysfile /etc/ssh/authorized_keys/%u

Starší verze OpenSSH trvají v -C na všech třech hodnotách user, host a addr; novější přijmou podmnožinu. Zadej všechny tři a bude to fungovat všude. Všimni si, že sshd -T ukazuje tokeny neexpandované; expanze se provádí při každém přihlášení.

Chceš-li sledovat skutečné přihlášení proti nové konfiguraci bez zásahu do běžícího démona, spusť druhý sshd v ladicím režimu na volném portu. Obslouží jedno spojení, vypíše každé rozhodnutí do tvého terminálu a skončí:

bash
$ sudo /usr/sbin/sshd -d -p 2222$ ssh -p 2222 -i ~/.ssh/id_ed25519 alice@203.0.113.10   # from your own machine

Ladicí výstup jmenuje každý soubor s autorizovanými klíči, který zkouší, říká, když nějaký chybí, hlásí přesné selhání oprávnění a při úspěchu určí soubor a řádek, který se shodoval. Pro test otevři ve firewallu port 2222 a potom ho zase zavři; průvodce ufw má jednořádkové pravidlo. Konfiguraci zadanou přes -f lze otestovat stejně, než ji zkopíruješ na místo.

Bezpečný reload a obnova#

Postup, který nikoho nezamkne venku:

  1. Nech na serveru otevřený stávající root shell. Nezavírej ho, dokud neuspěje krok 5.
  2. Vytvoř centrální soubor, zkopíruj do něj klíče a nastav vlastnictví a režimy, jak je popsáno výše.
  3. Zapiš direktivu do vlastního souboru v sshd_config.d a uveď i staré umístění.
  4. Spusť sudo sshd -t, potom sudo sshd -T s -C alespoň pro jednoho dotčeného uživatele.
  5. Udělej reload a pak z druhého terminálu otevři nové spojení pro každý druh dotčeného účtu.
bash
$ sudo sshd -t && sudo systemctl reload ssh     # Debian, Ubuntu$ sudo sshd -t && sudo systemctl reload sshd    # RHEL, Rocky, Alma, Fedora

Reload pošle SIGHUP; naslouchající démon znovu načte konfiguraci a stávající relace pokračují bez rušení. Ani restart na moderních jednotkách systemd už navázané relace neukončí, ale reload je šetrnější návyk. Na && záleží: pokud kontrola syntaxe selže, nic se nereloaduje.

Když se to přece pokazí, řešením je otevřená relace: vrať soubor, sshd -t, reload. Bez ní potřebuješ konzoli poskytovatele nebo záchranný režim, a proto první hodina na novém VDS doporučuje najít je dřív, než je budeš potřebovat. Až se dostaneš zpátky, důvody jsou téměř vždy v journalctl -u ssh (nebo -u sshd): odmítnutí kvůli oprávněním, soubor na špatné cestě nebo staré umístění tiše vypuštěné ze seznamu.

Nejen soubory: AuthorizedKeysCommand#

Když seznam klíčů žije v adresářové službě, databázi nebo nástroji pro správu flotily, psát soubory na každém stroji je špatný tvar řešení. AuthorizedKeysCommand spustí program, který vypíše autorizované klíče na standardní výstup ve stejném formátu jako soubor, a AuthorizedKeysCommandUser pojmenuje neprivilegovaný účet, pod kterým běží. Konzultuje se příkaz i soubory, takže lokální nouzový klíč můžeš mít v souboru, zatímco běžné klíče přicházejí z příkazu. Program i jeho adresář musí vlastnit root a nikdo jiný do nich nesmí zapisovat, stejný princip jako u centrálního adresáře. Takto SSSD poskytuje klíče z LDAP nebo FreeIPA.

Pro víc než hrstku lidí a strojů odstraňují SSH certifikáty (TrustedUserCAKeys) seznam klíčů na každém serveru úplně, jak popisuje článek o zabezpečení. AuthorizedKeysFile zůstává správným nástrojem pro malou flotilu, jediné VDS nebo nouzový klíč, který musí fungovat, když všechno chytré neběží. A nech zapnuté LogLevel VERBOSE, aby každé přihlášení zaznamenalo otisk použitého klíče - logy, které stojí za uchování popisují, jak si ty řádky nechat.

Na RE:NODE jde o záležitost jen pro VDS. Herní, aplikační a webové servery nemají démon SSH, který bys konfiguroval: přístup k souborům je přes SFTP s přihlašovacími údaji vydanými pro každý server a konzole je v panelu, jak popisuje článek SFTP a správce souborů. VDS ti dává root a celý sshd_config, včetně každého nastavení výše a odpovědnosti za jeho otestování.

FAQ#

Musím po přidání klíče do authorized_keys restartovat sshd?

Ne. Soubor se čte při každé autentizaci, takže nový řádek funguje při příštím připojení. Reload je potřeba jen tehdy, když měníš samotný AuthorizedKeysFile nebo jinou direktivu v konfiguraci.

Proč můj centrální soubor s klíči funguje pro roota, ale ne pro ostatní uživatele?

Téměř vždy proto, že soubor je 600 a vlastní ho root. sshd ho otevírá s oprávněním přihlašujícího se uživatele, takže ho ten uživatel musí umět číst. Nastav 644 a nech ho ve vlastnictví roota; uživatel své veřejné klíče přečte, ale nezmění je.

Může uživatel po přechodu na /etc/ssh/authorized_keys/%u dál přidávat vlastní klíče?

Jen pokud je .ssh/authorized_keys stále v seznamu. Jakmile je centrální cesta jediná položka, může uživatel ve svém domovském adresáři psát, co chce, a sshd to nikdy nepřečte. To je zamýšlený výsledek, takže lidem dej předem vědět.

Mám prostě nastavit StrictModes no, když je klíč odmítnut?

Ne. Odmítnutí upozorňuje na skutečný problém: domovský adresář, adresář .ssh nebo soubor s klíči, do kterého může zapisovat někdo jiný než uživatel. Oprav vlastnictví nebo režim, který log jmenuje, a klíč bude fungovat a kontrola tě dál chrání.

Ovlivňuje AuthorizedKeysFile přihlášení přes SFTP?

Ano. SFTP běží přes SSH a ověřuje se stejně, takže se prohledávají stejné soubory. S blokem Match a ChrootDirectory jsou klíče mimo chroot běžné uspořádání, protože autentizace probíhá dřív, než je uživatel uzavřen.

Vyplatí se odstranit authorized_keys2 z výchozí hodnoty?

Je to změna jednoho řádku bez nevýhod na jakémkoli moderním systému. Nic legitimního by ten soubor používat nemělo a klíč v něm ukrytý se při auditu snadno přehlédne. Nastav explicitně AuthorizedKeysFile .ssh/authorized_keys a ověř pomocí sshd -T.