Если в инфраструктуре десятки и сотни серверов, а доступ управляется обычными публичными ключами в authorized_keys, со временем накапливаются проблемы: разрастание списков, сложность отзыва, компромиссы по безопасности. SSH‑сертификаты в OpenSSH снимают эти болевые точки: вы выдаёте краткоживущие сертификаты на основе существующих ключей, а серверы доверяют не конкретным ключам, а вашему центру сертификации (CA). В результате доступ контролируется ролями (principals), а отзыв и ротация реализуются централизованно через KRL (Key Revocation List).
Как устроены SSH‑сертификаты в OpenSSH
Идея проста: вместо пуша ключей на каждый сервер мы публикуем на серверах только доверие к нашему CA, а пользователям выдаём сертификаты с коротким TTL. Сертификат — это подпись CA над пользовательским публичным ключом с набором политик (расширений) и списком principals. Сервер при входе проверяет, что сертификат подписан доверенным CA, не просрочен и подходит по политикам и принципам.
Отличие от X.509: OpenSSH использует собственный лёгкий формат сертификатов, создающихся командой
ssh-keygen. Никаких сложных PKI‑компонентов не требуется.
План внедрения
- Разделите CA на два ключа: user CA (подписывает клиентские сертификаты) и host CA (подписывает серверные сертификаты).
- Разместите приватные ключи CA на изолированном узле (часто — bastion), с жёсткими правами доступа и аудитом.
- Доставьте публичные части CA на все сервера и пропишите в
sshd_config. - Настройте принципы (principals) и политики безопасности для пользователей и ролей.
- Организуйте выпуск краткоживущих сертификатов (TTL часы/сутки) и регулярную ротацию.
- Включите KRL и процедуру быстрого отзыва при инцидентах.

Подготовка ключей CA
Создадим два независимых ключа CA: для пользователей и для хостов. Рекомендуется алгоритм ed25519 (быстрый и безопасный) или современный RSA при необходимости совместимости.
# каталоги для CA
sudo mkdir -p /etc/ssh/ca
sudo chmod 700 /etc/ssh/ca
# user CA (для клиентских сертификатов)
ssh-keygen -t ed25519 -f /etc/ssh/ca/user_ca -C "user-ca" -N ''
# host CA (для сертификатов серверов)
ssh-keygen -t ed25519 -f /etc/ssh/ca/host_ca -C "host-ca" -N ''
# права
sudo chown root:root /etc/ssh/ca/*
sudo chmod 600 /etc/ssh/ca/user_ca /etc/ssh/ca/host_ca
sudo chmod 644 /etc/ssh/ca/user_ca.pub /etc/ssh/ca/host_ca.pub
Хорошая практика — хранить приватные ключи CA только на bastion или отдельной изолированной ВМ, вести аудит доступа и создавать защищённые резервные копии. Для критичных сред возможен офлайн‑root CA с рабочим промежуточным CA.
Доверие к user CA на серверах
На каждом сервере нужно сказать sshd, что он доверяет нашему user CA. Для этого достаточно скопировать user_ca.pub и указать в конфиге директиву TrustedUserCAKeys.
# на сервере
sudo mkdir -p /etc/ssh/ca
sudo cp /tmp/user_ca.pub /etc/ssh/ca/user_ca.pub
sudo chown root:root /etc/ssh/ca/user_ca.pub
sudo chmod 644 /etc/ssh/ca/user_ca.pub
# /etc/ssh/sshd_config
TrustedUserCAKeys /etc/ssh/ca/user_ca.pub
# опционально ограничим вход только по сертификатам
PubkeyAuthentication yes
AuthorizedKeysFile none
# используем principals из файла, а не из authorized_keys
AuthorizedPrincipalsFile /etc/ssh/principals/%u
# подключим KRL для отзыва (создадим позже)
RevokedKeys /etc/ssh/revoked.krl
# применяем
sudo systemctl reload sshd
Схема с AuthorizedPrincipalsFile позволяет хранить на сервере список разрешённых principals для каждого системного пользователя: если сертификат содержит хотя бы один principal, совпадающий с записью в файле, доступ будет предоставлен. Это удобно для ролевого доступа.
Пример principals
# для пользователя "deploy": /etc/ssh/principals/deploy
role-deploy
ci
# для пользователя "root": /etc/ssh/principals/root
role-ops
oncall
Теперь любой сертификат, подписанный нашим CA и содержащий, например, role-deploy, сможет войти под системным пользователем deploy на этот сервер.
Выпуск пользовательских сертификатов с коротким TTL
Сертификат выдаётся на уже существующий публичный ключ разработчика или администратора. Рекомендуемый срок жизни — часы, максимум сутки. Это резко повышает безопасность: компрометация ключа перестаёт быть фатальной на долгие месяцы.
# у пользователя есть ключ, например ~/.ssh/id_ed25519 и ~/.ssh/id_ed25519.pub
# на CA подпишем его с TTL 8 часов, ролями и ограничениями
ssh-keygen -s /etc/ssh/ca/user_ca -I vasya-2025-10-24 -n role-deploy,ci -V +8h -z 10001 -O clear -O permit-pty -O permit-port-forwarding -O source-address=10.0.0.0/8,192.168.0.0/16 /home/vasya/.ssh/id_ed25519.pub
Ключевые моменты:
-I— идентификатор сертификата (удобен в логах и KRL).-n— список principals (роли). Именно они сопоставляются с файлами в/etc/ssh/principals/%u.-V +8h— срок действия. Можно задать интервалы, например-V -5m:+8hс допуском по часовым сдвигам.-z— серийный номер, пригодится для адресного отзыва.-O— политики. Рекомендуется начать с-O clearи явно включить только нужное.source-address— мощный контроль: сертификат работает только с определённых сетей.
При выдаче сертификата рядом с ключом пользователя появится файл вида id_ed25519-cert.pub. Клиент ssh подхватывает его автоматически при наличии приватного ключа id_ed25519. Проверить сертификат можно так:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
Принудительная команда и ограниченные роли
Для сервисных ролей удобно зашить принудительную команду. Например, роль rsync:
ssh-keygen -s /etc/ssh/ca/user_ca -I rsync-2025-10 -n role-rsync -V +12h -z 11001 -O clear -O force-command=/usr/local/bin/rsync-wrapper -O no-port-forwarding -O no-agent-forwarding -O no-pty /srv/keys/rsync.pub
Такой сертификат не даст выполнить интерактивную сессию, а только указанную команду.
Bastion и процесс выдачи
Типовой поток: разработчик аутентифицируется на bastion (например, по FIDO2/OTP плюс свой ключ), запускает команду, которая подписывает его публичный ключ и выдаёт краткоживущий сертификат. Далее он подключается к целевым серверам через ProxyJump bastion, предъявляя свежий сертификат. Если у вас ещё нет отдельного бастиона — поднимите его на VDS; это удобно совмещать с аудитом и MFA. Для ускорения развёртывания пригодится сравнение панелей для VDS.
# примеры пользовательских настроек
# ~/.ssh/config
Host bastion
HostName bastion.corp
User vasya
Host app-*.corp
ProxyJump bastion
User deploy
IdentityFile ~/.ssh/id_ed25519
IdentitiesOnly yes
Сертификаты хоста: избавляемся от TOFU
Серверные сертификаты решают проблему TOFU (trust on first use), когда ssh впервые видит узел и просит «довериться отпечатку». С хост‑сертификатами клиент доверяет не отпечатку, а хост‑CA.
# на сервере генерируем хост‑ключи (если их ещё нет)
sudo ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ''
# перенесём публичный ключ на узел с host CA и подпишем
ssh-keygen -s /etc/ssh/ca/host_ca -I host-app-01 -h -n app-01.corp,app-01,10.0.1.10 -V +52w -z 20001 /etc/ssh/ssh_host_ed25519_key.pub
# скопируем сертификат обратно на сервер
sudo cp ssh_host_ed25519_key-cert.pub /etc/ssh/ssh_host_ed25519_key-cert.pub
# /etc/ssh/sshd_config
HostKey /etc/ssh/ssh_host_ed25519_key
HostCertificate /etc/ssh/ssh_host_ed25519_key-cert.pub
sudo systemctl reload sshd
На клиентской стороне нужно сообщить, какой CA доверен для конкретных доменов. Это делается через запись @cert-authority в known_hosts или глобально.
# ~/.ssh/known_hosts
@cert-authority *.corp ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAI... host-ca
Теперь клиенты перестанут задавать вопросы при первом подключении и будут валидировать серверный сертификат по доверенному CA. Рекомендуется назначать хост‑сертификатам более длинный TTL (недели/месяцы) и плановую ротацию.
Отзыв ключей и сертификатов через KRL
KRL — это компактный файл списка отзыва, который sshd проверяет на сервере, а ssh — на клиенте для хостов. Он поддерживает отзыв по публичным ключам, по серийному номеру, по диапазонам серий и даже по ключу CA (в крайнем случае).
# создаём пустой KRL на сервере доверия
sudo ssh-keygen -k -f /etc/ssh/revoked.krl
# отозвать конкретный пользовательский публичный ключ (например, украден)
sudo ssh-keygen -k -u -f /etc/ssh/revoked.krl -s /etc/ssh/ca/user_ca /home/vasya/.ssh/id_ed25519.pub
# отозвать конкретный сертификат по серийному номеру
sudo ssh-keygen -k -u -f /etc/ssh/revoked.krl -s /etc/ssh/ca/user_ca -z 10001
# отозвать диапазон серий (например, весь выпуск за день)
sudo ssh-keygen -k -u -f /etc/ssh/revoked.krl -s /etc/ssh/ca/user_ca -z 10000:10100
После обновления KRL нужно доставить файл на все сервера, где он указан в sshd_config в директиве RevokedKeys. Перезагрузка демона не требуется — файл перечитывается автоматически при каждом подключении.
Совет: держите KRL в централизованном конфиг‑репозитории и раскатывайте привычным инструментом управления конфигурациями. При инциденте достаточно одной команды, чтобы выключить доступ по утерянному ключу или конкретному сертификату.

Ротация CA и бесперебойность
Ключи CA тоже нужно ротационировать. Делайте это с перекрытием: добавьте новый CA параллельно старому, подпишите им новые сертификаты, затем удалите старый после истечения всех выданных им сертификатов.
# на серверах временно доверяем двум CA
TrustedUserCAKeys /etc/ssh/ca/user_ca.pub /etc/ssh/ca/user_ca_v2.pub
# на клиентах для хостов аналогично добавьте второй @cert-authority
@cert-authority *.corp ssh-ed25519 AAAA... host-ca-v1
@cert-authority *.corp ssh-ed25519 AAAA... host-ca-v2
Планируйте ротацию заранее, учитывая максимальные TTL, чтобы не ломать доступ. Для высоких требований по безопасности уменьшайте TTL и ускоряйте ротации.
Политики и best practices
- Короткие TTL: для людей — 4–12 часов; для сервисов — 12–48 часов; для хостов — недели/месяцы с плановой заменой.
- Разделение ролей: используйте principals типа
role-dev,role-ops,ci, а не именные логины. - Минимальные расширения:
-O clearи включайте только нужное. Для автоматизаций выключайтеpty, форвардинги и агента. - Ограничивайте IP источника (
source-address) для чувствительных ролей и доступов с корпоративных сетей и VPN. - Аудит и логирование: уникальные
-Iи серийные-zдля трассировки событий. - Изоляция CA: узкий доступ, журналирование, MFA, отдельная ВМ. Рассмотрите офлайн‑root CA.
- Быстрый отзыв: KRL под руками и автоматизированная доставка на все узлы.
- Bastion как единая точка входа и «фабрика сертификатов»: там проще внедрить MFA и аудит.
Отладка и диагностика
Часто помогает посмотреть сертификат и расширенный дебаг клиента:
ssh-keygen -L -f ~/.ssh/id_ed25519-cert.pub
ssh -vvv deploy@app-01.corp
На сервере проверьте чтение файлов, права и параметры:
sudo sshd -T | grep -E 'trustedusercakeys|authorizedprincipalsfile|revokedkeys'
sudo journalctl -u sshd -n 200 --no-pager
Если вход падает, типовые причины: отсутствует пересечение principals, просрочен TTL, KRL блокирует ключ, не подхватился сертификат (нет файла id_ed25519-cert.pub рядом с приватным ключом), неверно указан TrustedUserCAKeys.
ЧАВО
Можно ли оставить authorized_keys?
Да, гибридное состояние допустимо на время миграции. Однако целевая модель — только сертификаты плюс AuthorizedPrincipalsFile и KRL.
Как выдавать сертификаты автоматически?
На bastion поднимите небольшую службу, которая после успешной аутентификации пользователя и проверки его ролей запускает ssh-keygen -s с нужными параметрами. Не забывайте про аудит и ограничения.
Что хранить в principals?
Ролевые метки: role-dev, role-ops, oncall, ci. Привязывайте их к системным пользователям через /etc/ssh/principals/%u. Менять доступ тогда просто — редактируете файл на сервере без перекопирования ключей.
Как быстро запретить весь выпуск от скомпрометированного CA?
Добавьте ключ CA в KRL (глобальный отзыв) и выкатите файл на все узлы. Затем выполните внеплановую ротацию CA.
Чеклист внедрения
- Созданы user CA и host CA, настроено резервное копирование и аудит.
- На серверах прописан
TrustedUserCAKeys,AuthorizedPrincipalsFileиRevokedKeys. - На клиентах настроен
@cert-authorityдля хост‑CA. - Отлажен процесс выдачи краткоживущих сертификатов и их доставка пользователям.
- Включён KRL и автоматизирована его доставка.
- Задокументированы политики TTL, роли и процедуры отзыва/ротации.
- Проверены сценарии аварий: компрометация ключа пользователя, отозваны серийные, ротация CA с перекрытием.
Переход на SSH‑сертификаты в OpenSSH — это небольшой проект по внедрению, который быстро окупается: упрощается доступ, ускоряется ротация, повышается безопасность и управляемость. Используйте bastion как центр выдачи, храните CA изолированно, держите TTL короткими, а KRL — под рукой.


