AuthorizedKeysFile сообщает sshd, где искать публичные ключи, с которыми пользователю разрешено входить. Если вы его не задавали, OpenSSH проверяет .ssh/authorized_keys и .ssh/authorized_keys2 в домашнем каталоге пользователя, хотя во многих дистрибутивах поставляется конфигурация, которая сужает список до первого файла. Менять эту директиву стоит по одной из трёх причин: чтобы вынести ключи из-под контроля пользователей в каталог, принадлежащий root, например /etc/ssh/authorized_keys/%u; чтобы ключи читались до монтирования домашнего каталога; или чтобы через блок Match дать одной группе учётных записей другой источник ключей.
Настройка короткая, а последствия ошибки серьёзные. Если указать путь, который sshd считает небезопасным, или забыть, что директива заменяет значение по умолчанию, а не дополняет его, то вход по ключам перестанет работать сразу на всей машине - в том числе для вас. В этой статье разбираем, какие значения принимает директива, как собрать общий каталог ключей, проходящий проверки StrictModes, как она сочетается с sshd_config.d и Match и как убедиться, что изменение работает, до того как вы закроете сессию, на которую рассчитываете. Генерация ключей, агенты и общий список мер по защите описаны в статье SSH keys and sshd_config hardening; здесь речь об одной директиве, но подробно.
Что делает AuthorizedKeysFile и какое у неё значение по умолчанию#
При аутентификации по публичному ключу клиент предъявляет ключ, а sshd ищет его по порядку в файлах, перечисленных в AuthorizedKeysFile. Побеждает первый файл, содержащий подходящую строку, и параметры в начале этой строки (restrict, from=, command= и другие) применяются к сессии. Если ключа нет ни в одном из файлов, он отклоняется, и клиент переходит к следующему ключу или способу входа.
Значение, зашитое в современный OpenSSH по умолчанию, такое:
AuthorizedKeysFile .ssh/authorized_keys .ssh/authorized_keys2Что вы получите на самом деле, зависит от поставляемого конфигурационного файла:
| Дистрибутив | Строка в поставляемом файле | Действующее значение |
|---|---|---|
| Debian, Ubuntu | закомментирована | оба файла |
| RHEL, Rocky, Alma, Fedora | .ssh/authorized_keys | один файл |
| Образец из upstream OpenSSH | .ssh/authorized_keys | один файл |
authorized_keys2 - наследие перехода с протокола SSH 1 на 2, и он объявлен устаревшим больше двадцати лет назад. Класть в него ключи не должен никто, и именно поэтому его стоит исключить: файл, в который никто не заглядывает, - удобное место для ключа, оставленного злоумышленником, который ненадолго получил оболочку. Явно задать значение .ssh/authorized_keys на Debian и Ubuntu - небольшое и безопасное улучшение.
Допустимы ещё два значения. none полностью отключает ключи из файлов; это имеет смысл, только когда ключи берутся из AuthorizedKeysCommand (о нём ниже) или вход выполняется по сертификатам. А поскольку директива может стоять внутри Match, значение может отличаться для разных пользователей, групп и исходных адресов.
Изменения в содержимом файла authorized keys вступают в силу при следующем входе без перезагрузки, потому что sshd читает файл в момент аутентификации. Изменения самой директивы AuthorizedKeysFile требуют, чтобы sshd заново прочитал конфигурацию.
Пути и токены %h, %u, %U и %%#
После подстановки токенов каждое значение считается либо абсолютным путём, либо путём относительно домашнего каталога пользователя. Поэтому и работает простое .ssh/authorized_keys: перед ним подразумевается домашний каталог.
| Токен | Заменяется на | Пример результата |
|---|---|---|
%h | домашний каталог | /home/alice |
%u | имя пользователя | alice |
%U | числовой ID пользователя | 1001 |
%% | буквальный % | % |
%U понимают современные версии OpenSSH; более старые знают только %h, %u и %%, поэтому перед использованием проверьте man sshd_config на своей машине. Домашний каталог берётся из базы паролей (/etc/passwd или LDAP через NSS), а не из $HOME, так что пользователь не сможет перенаправить его переменной окружения.
Несколько равнозначных и неравнозначных вариантов записи, потому что на различиях часто спотыкаются:
# 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Тильда в этой директиве токеном не является. Если вы имеете в виду домашний каталог, пишите %h. А %u подставляется как есть, поэтому имя пользователя с символами, которые не нравятся вашей файловой системе (редкость, но учётные записи LDAP и Active Directory иногда несут суффикс домена), станет частью имени файла. Смотрите на развёрнутый путь в отладочном выводе, описанном ниже, а не предполагайте.
Несколько файлов в списке#
Несколько путей записываются в одну строку через пробел. Они проверяются по порядку, побеждает первое совпадение.
AuthorizedKeysFile /etc/ssh/authorized_keys/%u .ssh/authorized_keysТак выглядит миграция. Ключи, которыми управляете централизованно вы, система управления конфигурацией или скрипт развёртывания, лежат в /etc/ssh, а собственный файл каждого пользователя продолжает работать, пока вы переносите людей. Отсутствующий файл ошибкой не считается: sshd отмечает это на уровне debug и пробует следующий. Поэтому настройку можно раскатать на весь парк машин до того, как у каждого пользователя появится центральный файл.
Порядок важен в одной ситуации. Если один и тот же ключ есть в обоих файлах с разными параметрами, решает строка из первого файла. Ключ, ограниченный в центральном файле через from=, не станет свободнее из-за неограниченной копии в собственном файле пользователя, потому что поиск останавливается на первом совпадении, - но верно и обратное, поэтому ставьте первым файл, который контролируете вы.
Важное следствие: директива заменяет значение по умолчанию. Если задать только AuthorizedKeysFile /etc/ssh/authorized_keys/%u, то после ближайшей перезагрузки конфигурации все ~/.ssh/authorized_keys на машине будут игнорироваться. Если ваш ключ лежит только в домашнем каталоге, вы только что заперли себя снаружи. Указать оба пути на время изменения - самая дешёвая страховка.
Общий каталог ключей, принадлежащий root#
Главная причина менять AuthorizedKeysFile - контроль. По умолчанию любой пользователь может дописывать ключи в свой файл, а значит, любой, кто когда-то получал оболочку под этим пользователем, может оставить себе постоянный путь обратно, и при каждом аудите приходится читать файлы, разбросанные по домашним каталогам. Каталог, принадлежащий root, превращает вопрос «кто может входить под какой учётной записью» в то, что хранится в одном месте и меняется только через root или вашу систему управления конфигурацией.
Он также решает две практические проблемы: домашние каталоги на сетевом хранилище, которое монтируется только после входа, и зашифрованные домашние каталоги, недоступные, пока пользователь не аутентифицировался паролем. Файл ключей вне /home читается в момент аутентификации в любом случае.
Структура:
$ 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Режим 644 - то, в чём чаще всего ошибаются, и он неочевиден. sshd читает файлы authorized keys с правами целевого пользователя, а не от root. Файл root:root 600 недоступен для alice, а значит, и для sshd, пока он проверяет её ключ, и вход не удаётся. Публичные ключи публичны; то, что файл доступен всем на чтение, не раскрывает ничего, что мог бы использовать атакующий. Недопустимо другое: чтобы пользователь или кто-то ещё мог писать в этот файл.
Есть две приемлемые модели владения:
root:root, режим644. Пользователь может читать свои ключи, но не менять их. В этом смысл общего каталога.- Владелец - пользователь, режим
600или644, в каталоге, принадлежащем root. Пользователь может править свой файл, но не может создавать и удалять файлы других. Это компромисс, и он возвращает большую часть того, что вы хотели забрать.
Побочный эффект, о котором стоит предупредить коллег: ssh-copy-id пишет в ~/.ssh/authorized_keys на удалённой стороне и ничего не знает о вашей настройке. Он сообщает об успехе, а если домашнего файла больше нет в списке, установленный им ключ никогда не будет проверен.
StrictModes и проверки прав доступа#
StrictModes по умолчанию равен yes, и так должно остаться. Когда он включён, перед тем как доверять файлу authorized keys, sshd проверяет сам файл и каждый каталог на пути к нему. Правила вкратце:
| Объект | Владелец должен быть | Не должен быть |
|---|---|---|
| Файл с ключами | root или пользователь | доступным на запись группе или всем |
| Каждый каталог выше него | root или пользователь | доступным на запись группе или всем |
| Домашний каталог пользователя | root или пользователь | доступным на запись группе или всем |
Если проверка не пройдена, ключ отклоняется, а клиент видит лишь «Permission denied (publickey)». Настоящая причина записывается в журнал сервера на уровне по умолчанию:
Authentication refused: bad ownership or modes for directory /home/aliceЭто сообщение - самая частая причина фразы «мой ключ перестал работать», и вызвано оно обычно чем-то, не связанным с SSH: скриптом развёртывания, выполнившим chmod -R 775 для домашнего каталога, доступным группе на запись /home/alice, созданным панелью управления, или центральным каталогом, созданным не от root. Исправлять нужно права, а не ставить StrictModes no. Отключив проверку, вы позволите каждому члену группы подбросить ключи пользователю, чей домашний каталог доступен этой группе на запись.
Для центрального каталога проверяется путь /etc, /etc/ssh, /etc/ssh/authorized_keys и сам файл. В обычной системе первые два уже имеют root:root 755. Проблемы возникают, когда каталог лежит в менее аккуратном месте - в /srv на томе, смонтированном с необычными правами, или на ресурсе с переназначением владельцев. Статья Game server file permissions and ownership объясняет, как читать вывод ls -l, если режимы для вас не очевидны.
В системах семейства RHEL с включённым SELinux есть ещё один барьер. Ключам в домашнем каталоге нужна метка ssh_home_t, которую исправляет restorecon -Rv ~/.ssh после копирования или восстановления. Файлы в /etc/ssh обычно наследуют метку, которую sshd может читать. Если вы выберете другое место, симптом будет тот же - отказ во входе при чистых правах файлов; проверьте ausearch -m avc -ts recent и назначьте метку каталогу через semanage fcontext, а не выключайте SELinux.
sshd_config.d, Include и правило первого значения#
Начиная с OpenSSH 8.2, sshd_config может подключать другие файлы через Include. Debian 12, Ubuntu 22.04 и новее, а также свежие версии Fedora и RHEL поставляются с основным файлом, в начале которого подключается /etc/ssh/sshd_config.d/*.conf. Подключённые файлы читаются в лексическом порядке, как если бы их вставили на место строки Include.
Добавьте к этому самое важное правило sshd_config: для большинства ключевых слов используется первое полученное значение. Параметр из /etc/ssh/sshd_config.d/10-local.conf побеждает такой же параметр ниже в основном файле, а 10-local.conf побеждает 50-cloud-init.conf, потому что сортируется раньше. Если вы правите основной файл и не видите изменений, почти всегда дело в этом.
Практическая структура:
# Central keys first, the user's own file as a fallback during migrationAuthorizedKeysFile /etc/ssh/authorized_keys/%u .ssh/authorized_keysДержите каждую тему в отдельном небольшом пронумерованном файле. Прежде чем создавать свой, посмотрите, что уже лежит в каталоге: образы облачных провайдеров часто кладут туда файл с параметрами аутентификации, и об этом лучше знать до проверки. А потом полагайтесь на sshd -T, о котором ниже: он скажет, что победило, и вам не придётся разбирать порядок вручную.
Блоки Match: разные ключи для разных учётных записей#
AuthorizedKeysFile - одно из ключевых слов, разрешённых внутри блока Match, поэтому источник ключей может зависеть от пользователя, группы, исходного адреса или локального порта. Блок Match действует до следующего Match или до конца файла, в котором он находится, поэтому блоки следует размещать в конце файла, после всех глобальных настроек. Match all явно завершает блок, если нужно вернуться в глобальный контекст.
Типичная схема: обычные сотрудники хранят свои authorized_keys, а служебные учётные записи и клиенты только с SFTP получают ключи, которые может менять лишь root.
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Случай с SFTP показывает, чем полезна эта связка. Аутентификация происходит до применения chroot, поэтому файл с ключами лежит полностью за пределами каталога, который видит пользователь. Он не может ни прочитать, ни заменить, ни дополнить свои ключи из SFTP-сессии, а ключ в домашнем каталоге внутри chroot это позволил бы.
Помните, что внутри Match правило первого значения тоже действует для сработавшего блока. Если два блока Match подходят пользователю и оба задают AuthorizedKeysFile, побеждает более ранний. Проверяйте конкретного пользователя, а не только файл.
Проверка через sshd -t и sshd -T#
Два флага, две задачи. Оба требуют root, потому что sshd хочет прочитать свои ключи хоста даже при проверке, и оба находятся в /usr/sbin/sshd, которого не всегда есть в PATH обычного пользователя.
sshd -t - проверка синтаксиса. Он разбирает все файлы, включая каждый Include, и молча завершается со статусом 0, если конфигурация корректна. Опечатка в ключевом слове, ключевое слово, недопустимое внутри Match, или нечитаемый ключ хоста приводят к ошибке и ненулевому коду выхода. Запускайте его перед каждой перезагрузкой, каждый раз.
sshd -T выводит действующую конфигурацию: каждое ключевое слово в нижнем регистре после применения значений по умолчанию, подключаемых файлов и правила первого значения. Это единственный надёжный ответ на вопрос «что на самом деле сделает sshd». Добавьте -C, чтобы вычислить блоки Match для конкретного подключения:
$ 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Старые версии OpenSSH требуют в -C все три параметра - user, host и addr; новые принимают часть из них. Передайте все три, и заработает везде. Учтите, что sshd -T показывает токены неразвёрнутыми: подстановка выполняется при каждом входе.
Чтобы посмотреть настоящий вход с новой конфигурацией, не трогая работающий демон, запустите второй sshd в режиме отладки на свободном порту. Он обработает одно подключение, выведет каждое решение в ваш терминал и завершится:
$ sudo /usr/sbin/sshd -d -p 2222$ ssh -p 2222 -i ~/.ssh/id_ed25519 alice@203.0.113.10 # from your own machineВ отладочном выводе названы все файлы authorized keys, которые он пробует, указано, когда файл отсутствует, показана точная причина отказа по правам, а при успехе - файл и строка, давшие совпадение. Откройте порт 2222 в файрволе на время теста и закройте после него; в руководстве по ufw есть правило в одну строку. Конфигурацию, переданную через -f, можно проверить так же до того, как она будет скопирована на место.
Безопасная перезагрузка и восстановление#
Порядок, который никого не запирает снаружи:
- Держите открытой уже существующую root-оболочку на сервере. Не закрывайте её, пока не выполнен шаг 5.
- Создайте центральный файл, скопируйте в него ключи и задайте владельца и режимы, как описано выше.
- Запишите директиву в отдельный файл в
sshd_config.d, указав и старое расположение. - Выполните
sudo sshd -t, затемsudo sshd -Tс-Cхотя бы для одного затронутого пользователя. - Перезагрузите конфигурацию, затем откройте новое подключение из второго терминала под каждым видом затронутых учётных записей.
$ sudo sshd -t && sudo systemctl reload ssh # Debian, Ubuntu$ sudo sshd -t && sudo systemctl reload sshd # RHEL, Rocky, Alma, FedoraПерезагрузка отправляет SIGHUP; слушающий демон заново читает конфигурацию, а существующие сессии продолжают работу без помех. Даже перезапуск не обрывает уже установленные сессии в современных юнитах systemd, но перезагрузка конфигурации - более бережная привычка. Важен оператор &&: если проверка синтаксиса не пройдена, ничего не перезагружается.
Если всё же что-то пошло не так, исправление - это открытая сессия: верните файл, выполните sshd -t, перезагрузите конфигурацию. Без неё вам понадобится консоль провайдера или режим восстановления, поэтому в статье the first hour on a new VDS рекомендуют найти его до того, как он понадобится. Когда вы вернётесь в систему, причины почти всегда найдутся в journalctl -u ssh (или -u sshd): отказ по правам, файл по неверному пути или старое расположение, молча исчезнувшее из списка.
За пределами файлов: AuthorizedKeysCommand#
Когда список ключей живёт в службе каталогов, базе данных или инструменте управления парком машин, записывать файлы на каждой машине - неподходящая форма. AuthorizedKeysCommand запускает программу, которая выводит authorized keys в стандартный вывод в том же формате, что и файл, а AuthorizedKeysCommandUser задаёт непривилегированную учётную запись, от имени которой она работает. Используются и команда, и файлы, поэтому локальный аварийный ключ можно держать в файле, а повседневные ключи получать от команды. Программа и её каталог должны принадлежать root и быть недоступны на запись никому другому - тот же принцип, что и для центрального каталога. Так SSSD выдаёт ключи из LDAP или FreeIPA.
Если людей и машин больше горстки, SSH-сертификаты (TrustedUserCAKeys) полностью устраняют список ключей на каждом сервере, как описано в статье о защите. AuthorizedKeysFile остаётся подходящим инструментом для небольшого парка, одного VDS или аварийного ключа, который должен работать, когда всё хитрое не работает. И оставьте LogLevel VERBOSE включённым, чтобы каждый вход записывал отпечаток использованного ключа - как хранить эти строки, рассказывает статья logs worth keeping.
На RE:NODE это касается только VDS. На игровых, прикладных и веб-серверах нет демона SSH, который вам нужно настраивать: доступ к файлам идёт по SFTP с учётными данными, выдаваемыми для каждого сервера, а консоль находится в панели, как описано в статье SFTP and the file manager. VDS даёт вам root и весь sshd_config, включая все перечисленные настройки, и ответственность за их проверку.
FAQ#
Нужно ли перезапускать sshd после добавления ключа в authorized_keys?
Нет. Файл читается при каждой аутентификации, поэтому новая строка заработает при следующем подключении. Перезагрузка нужна только при изменении самой директивы AuthorizedKeysFile или любой другой директивы в конфигурации.
Почему мой центральный файл ключей работает для root, но не для других пользователей?
Почти всегда потому, что у файла режим 600 и владелец root. sshd открывает его с правами входящего пользователя, поэтому этот пользователь должен иметь возможность его прочитать. Сделайте режим 644 и оставьте владельцем root: пользователь сможет читать свои публичные ключи, но не менять их.
Смогут ли пользователи добавлять свои ключи после перехода на /etc/ssh/authorized_keys/%u?
Только если .ssh/authorized_keys остался в списке. Когда центральный путь - единственная запись, пользователь может писать в домашнем каталоге что угодно, а sshd никогда это не прочитает. Это и есть задуманный результат, так что предупредите людей заранее.
Стоит ли просто поставить StrictModes no, когда ключ отклоняется?
Нет. Отказ указывает на реальную проблему: домашний каталог, каталог .ssh или файл с ключами, в которые может писать кто-то, кроме пользователя. Исправьте владельца или режим, названные в журнале, и ключ заработает, а проверка продолжит вас защищать.
Влияет ли AuthorizedKeysFile на входы по SFTP?
Да. SFTP работает поверх SSH и аутентифицируется так же, поэтому ищутся те же файлы. Если используются блок Match и ChrootDirectory, ключи вне chroot - обычная схема, потому что аутентификация происходит до того, как пользователь будет ограничен.
Стоит ли убирать authorized_keys2 из значения по умолчанию?
Это изменение в одну строку, и ни в одной современной системе от него нет вреда. Ничто легитимное не должно использовать этот файл, а спрятанный в нём ключ легко пропустить при аудите. Явно задайте AuthorizedKeysFile .ssh/authorized_keys и проверьте через sshd -T.


