SSH-сертификаты вместо authorized_keys
authorized_keys — это классика, но когда серверов больше десятка, начинается хаос. Добавление нового разработчика превращается в ручное скачивание ключей и раскладку по десяткам машин. SSH-сертификаты решают проблему: один CA-ключ подписывает все публичные ключи, и ни один authorized_keys не нужен.
Зачем authorized_keys — это боль
Схема с authorized_keys требует, чтобы публичный ключ пользователя физически присутствовал на каждом сервере. При масштабировании это означает:
- отдельный шаг деплоя ключей при онбординге;
- единая точка отзыва отсутствует — удаление из authorized_keys делается вручную на каждом хосте;
- ротация ключей затрагивает все машины;
- нет ограничения по времени действия ключа.
SSH-сертификат подписывает публичный ключ пользователя или хоста центральным CA-ключом. Серверу достаточно доверять этому CA — сам ключ подкладывать не нужно.
Как работают SSH-сертификаты
Два участника: CA (Certificate Authority) и подписываемый ключ. CA — это обычная SSH-пара ed25519 или rsa. Подпись создаётся командой ssh-keygen -s <ca_private> -I <identifier> <key.pub> и порождает файл <key-cert.pub>.
Серверу достаточно двух вещей: публичный ключ CA в TrustedUserCAKeys (для пользователей) или HostCertificate (для хостов). Аутентификация проходит, если подпись валидна и сертификат не просрочен.
Сертификат не заменяет ключ. Ключ по-прежнему необходим — он подписывается CA. Сертификат добавляет метаданные: время жизни, principals, расширения.
Генерация CA-ключей
| Флаг | Значение |
|---|---|
-t ed25519 | Тип ключа, ed25519 рекомендован RFC 8709 |
-f | Путь к файлу ключа |
-C | Комментарий, удобен для идентификации CA |
CA-ключи хранятся в защищённом месте — ideally на отдельной машине или в HSM. Приватный ключ CA никогда не должен попадать на целевые серверы.
Подпись user-сертификата: one-liner
| Флаг | Значение |
|---|---|
-s ca_private | Приватный ключ CA |
-I identifier | Строка-идентификатор в логах |
-n principals | Список principals через запятую |
-V +52w | Срок действия: 52 недели от now |
-z serial | Серийный номер, полезен для аудита |
Результат — файл id_ed25519-cert.pub рядом с ключом. Пользователь подкладывает оба файла на машину, с которой работает. Подпись для другого сотрудника — та же команда с другим ключом и CA.
Формат +52w поддерживает суффиксы h (часы), d (дни), w (недели). +1d — сутки, -1d — вчера (сертификат уже истёк).
Подпись host-сертификатов
На каждом сервере создаётся пара host-ключей (если ещё нет):
Подпись сертификата — на машине с CA:
Флаг -h превращает подпись в host-сертификат. -n содержит hostname и IP, которые клиент будет сверять при подключении.
Сертификат кладётся рядом с host-ключом:
sshd_config: CertFile, TrustedUserCAKeys, HostCertificate
Конфигурация sshd на целевом сервере:
После изменения конфига — проверка и перезагрузка:
TrustedUserCAKeys принимает именно публичный ключ CA, не сертификат. Сертификат нужен только для host-ключей.
Ограничение principals и from
При подписи можно задать from — ограничение по IP-адресу источника. Либо в момент подписи:
Либо через from в AuthorizedPrincipalsFile на сервере:
В сертификате может быть несколько principals — sshd проверит, есть ли хотя бы один совпадающий с AuthorizedPrincipalsFile. Это позволяет выдавать сертификат с ubuntu,deploy,admin и раздавать доступ через разные принципалы на разных хостах.
Время жизни и ротация
TTL задаётся при подписи. Рекомендации из практики:
| Роль | Срок | Причина |
|---|---|---|
| CI/CD, автоматика | 24–72 часа | Ключи в pipelines живут недолго |
| Разработчики | 1–6 месяцев | Баланс между безопасностью и удобством |
| Хосты | 12 месяцев | Host-сертификат привязан к hostname/IP |
Ротация — новый сертификат с новым -z serial. Старый автоматически перестаёт работать после истечения. Единая точка отзыва не нужна: истёкший сертификат невалиден, CA самодостаточен.
Fingerprints: проблема host-key
Классический known_hosts хранит fingerprint host-ключа. Host-сертификат ломает эту схему: fingerprint в known_hosts не совпадает с сертификатом. Есть два пути:
Первый — перейти на ssh_known_hosts с ssh-keyscan:
Второй — включить HostKeyAlgorithms с сертификатами, тогда fingerprint игнорируется:
При первом подключении ssh предложит принять сертификат, добавит его в known_hosts и больше спрашивать не будет.
Troubleshooting
Ошибки разбираются по шагам:
В выводе -vvv смотрите строки Certificateهو и Authentications that can continue. Если видите no matching identity — сертификат не найден рядом с ключом. certificate refused — CA не доверен или principal не совпал.
Проверить содержимое сертификата:
Вывод покажет Valid: from ... to ..., Principals:, Serial:. Это первое, что стоит глянуть, если что-то не работает.
Ошибка too many authentication failures при наличии сертификата обычно означает, что ssh перебирает все ключи до сертификата. Добавьте -o PubkeyAuthentication=no перед явным указанием ключа, или уберите лишние ключи из .ssh.
SSH-сертификаты убирают необходимость раскладки ключей по хостам. Один CA, подпись с TTL, principals для разграничения доступа. Если в инфраструктуре больше 5–10 серверов — это уже не luxury, а необходимость.