Выберите продукт

SSH‑сертификаты в OpenSSH: собственный CA, короткие TTL и отзыв ключей

Статические ключи в authorized_keys плохо масштабируются и почти не ревокируются. SSH‑сертификаты решают это: свой CA, короткие TTL, роли (principals) и KRL для быстрого отзыва. Покажу выпуск, проверку и ротацию.
SSH‑сертификаты в OpenSSH: собственный CA, короткие TTL и отзыв ключей

Если в инфраструктуре десятки и сотни серверов, а доступ управляется обычными публичными ключами в 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 и процедуру быстрого отзыва при инцидентах.

Выпуск пользовательских SSH‑сертификатов с коротким TTL

Подготовка ключей 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 в централизованном конфиг‑репозитории и раскатывайте привычным инструментом управления конфигурациями. При инциденте достаточно одной команды, чтобы выключить доступ по утерянному ключу или конкретному сертификату.

Отзыв SSH‑ключей и сертификатов через 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 — под рукой.

Поделиться статьей

Вам будет интересно

Linux watchdog: soft lockup/hard lockup, rcu stall и hung task — диагностика по dmesg и связь с I/O OpenAI Статья написана AI (GPT 5)

Linux watchdog: soft lockup/hard lockup, rcu stall и hung task — диагностика по dmesg и связь с I/O

Если сервер подтормаживает или «замирает», а в логе ядра появляются soft lockup/hard lockup, rcu stall или hung task — это не всег ...
Kubernetes NodePort и ExternalTrafficPolicy: как сохранить IP клиента и не сломать балансировку OpenAI Статья написана AI (GPT 5)

Kubernetes NodePort и ExternalTrafficPolicy: как сохранить IP клиента и не сломать балансировку

NodePort и LoadBalancer нередко «съедают» реальный IP клиента из‑за SNAT в kube-proxy. Разберём режимы externalTrafficPolicy (Clus ...
Kubernetes: ErrImagePull и 401 Unauthorized — настройка imagePullSecrets для private registry OpenAI Статья написана AI (GPT 5)

Kubernetes: ErrImagePull и 401 Unauthorized — настройка imagePullSecrets для private registry

Если Pod застрял в ErrImagePull/ImagePullBackOff и в Events виден 401 Unauthorized, почти всегда виноваты imagePullSecrets: секрет ...