Аппаратные токены FIDO2/U2F для SSH решают главную проблему классических ключей: кражу приватного ключа с клиента. Вместо файла с секретом, который можно скопировать, приватный ключ хранится внутри токена и никогда его не покидает. Подпись выполняется на устройстве, а доступ к операции подтверждается касанием (user presence) и при необходимости ПИН‑кодом (user verification). В результате риск компрометации от вредоносного ПО, бэкапов и физической кражи ноутбука резко снижается.
Зачем использовать FIDO2 для SSH
Если вы админ или девопс и ежедневно используете SSH, то ваши ключи — это мастер‑ключи к инфраструктуре. Даже с грамотными правами и ограничениями в authorized_keys остаётся целый слой рисков: утечка ключа из бэкапа, скомпрометированный ноутбук, невнимательная передача агент‑сокета через перескоки, атаки через пост‑эксплуатационные инструменты. FIDO2/U2F ликвидирует целый класс угроз, поскольку секрет нельзя скопировать, а каждая подпись требует физического подтверждения.
Важно понимать ограничения модели: FIDO2 не «магическая панацея». Он усиливает аутентификацию, но не заменяет базовую гигиену: контроль доступа на сервере, своевременные обновления, аудит, журналирование и сегментацию.
Как это работает в OpenSSH
Поддержка аппаратных ключей есть в OpenSSH 8.2+ через библиотеку FIDO (обычно libfido2). Используются специальные типы ключей:
sk-ecdsa-sha2-nistp256@openssh.com— на базе ECDSA P‑256 (совместимо с U2F и FIDO2), самый универсальный вариант.sk-ssh-ed25519@openssh.com— на базе Ed25519 (требует относительно новых токенов и библиотек).
Файлы «приватного ключа» на диске в случае FIDO — это не сам секрет, а дескриптор (handle), привязанный к определённому токену и приложению ssh:. При подключении OpenSSH запрашивает у токена подпись челенджа. Для завершения операции требуется «прикосновение» к токену; опционально — проверка ПИН‑кода.
Есть два режима выпуска ключей:
- Нерезидентные (по умолчанию): приватный ключ остаётся внутри токена, а дескриптор хранится в файле на диске. Быстрее и привычнее.
- Резидентные (опция
-O resident): сам дескриптор хранится на токене, что упрощает перенос между машинами и восстановление черезssh-keygen -K. Для доступа обычно требуется ПИН.
Важный плюс FIDO2: даже если злоумышленник получит копию вашего «приватного» файла
id_*.sk, он не сможет им воспользоваться без физического токена. Это кардинально меняет оценку рисков по сравнению с классическимed25519.
Требования и проверка окружения
Проверьте версии и поддержку типов ключей на клиенте:
ssh -V
ssh -Q key | grep sk
Если вывод содержит sk-ecdsa-* и sk-ssh-ed25519, клиент поддерживает FIDO. На сервере проверьте настройки:
sshd -T | grep -i pubkeyacceptedalgorithms
sshd -T | grep -i pubkeyacceptedkeytypes
Если нет sk-ecdsa-sha2-nistp256@openssh.com и sk-ssh-ed25519@openssh.com, добавьте их явно в sshd_config и перезагрузите демон. На Linux убедитесь, что система видит токен как HID‑устройство; обычно достаточно правил udev из пакета libfido2. На рабочих станциях с ограничениями USB доступ к устройствам может требовать добавления пользователя в соответствующую группу.

Генерация ключей: безопасные пресеты
Вариант 1: универсальный ECDSA‑ключ (совместим с U2F)
Подходит, если вы не уверены в поддержке Ed25519 на всех токенах и серверах.
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk -C "admin@work fido2" -O verify-required
Опция -O verify-required заставляет устройство требовать ПИН при каждой подписи. Это повышает стойкость даже при краже токена. Если хотите хранить дескриптор на токене, добавьте -O resident и укажите имя пользователя, которое пригодится при восстановлении:
ssh-keygen -t ecdsa-sk -f ~/.ssh/id_ecdsa_sk_res -C "admin@work fido2 resident" -O verify-required -O resident -O user=admin
Вариант 2: Ed25519‑ключ (современнее и компактнее)
Используйте, если ваши токены и клиенты точно его поддерживают:
ssh-keygen -t ed25519-sk -f ~/.ssh/id_ed25519_sk -C "admin@work ed25519-sk" -O verify-required
Проверить список идентификаторов на токене (для резидентных ключей) можно так:
ssh-keygen -K
Команда импортирует публичные части резидентных ключей в ~/.ssh, не извлекая приватный материал с токена.
Размещение публичного ключа на сервере
Передайте ключ на сервер удобным способом. Самый простой вариант — ssh-copy-id:
ssh-copy-id -i ~/.ssh/id_ed25519_sk.pub user@server
Либо вручную:
ssh user@server 'mkdir -m 700 -p ~/.ssh'
cat ~/.ssh/id_ed25519_sk.pub | ssh user@server 'cat >> ~/.ssh/authorized_keys'
ssh user@server 'chmod 600 ~/.ssh/authorized_keys'
Для усиления политики в authorized_keys можно добавить ограничения перед типом ключа: from="10.0.0.0/8",restrict. Также имеет смысл запретить лишние возможности: no-agent-forwarding,no-port-forwarding,no-pty — если они не нужны для конкретного пользователя.
from="10.0.0.0/8",restrict,no-agent-forwarding,no-port-forwarding sk-ssh-ed25519@openssh.com AAAAC3NzaC1lZDI1NTE5AAAA.... comment
Если вы не используете резидентные ключи с ПИН по умолчанию, применяйте -O verify-required при генерации. На некоторых версиях OpenSSH требование можно продублировать флагами при выпуске ключа — это надёжнее, чем надеяться на интерпретацию в authorized_keys.
Минимальная настройка сервера
Убедитесь, что сервер принимает FIDO‑ключи и при необходимости отключите пароли:
sudo sed -i 's/^#\?PubkeyAuthentication.*/PubkeyAuthentication yes/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?PasswordAuthentication.*/PasswordAuthentication no/' /etc/ssh/sshd_config
sudo sed -i 's/^#\?KbdInteractiveAuthentication.*/KbdInteractiveAuthentication no/' /etc/ssh/sshd_config
В новых версиях директива называется PubkeyAcceptedAlgorithms (в старых — PubkeyAcceptedKeyTypes). Добавьте поддержку sk-* явно, если их нет по умолчанию:
echo 'PubkeyAcceptedAlgorithms sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com' | sudo tee -a /etc/ssh/sshd_config
Затем перезагрузите службу:
sudo systemctl reload sshd
Проверьте вход с клиента и держите план отката (консоль, IPMI/ILO, отдельный аккаунт со старым ключом на период миграции).
Конфигурация клиента и работа через бастион
Рекомендую явно закрепить ключи и запретить агент‑форвардинг по умолчанию. В ~/.ssh/config это может выглядеть так:
Host bastion
HostName bastion.example
User admin
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519_sk
PubkeyAcceptedAlgorithms sk-ssh-ed25519@openssh.com,sk-ecdsa-sha2-nistp256@openssh.com
ForwardAgent no
Host internal-*
User deploy
ProxyJump bastion
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ed25519_sk
ForwardAgent no
Вместо передачи агент‑сокета по цепочке используйте ProxyJump. Если форвардинг всё же нужен, включайте его точечно и добавляйте ключ в агент с TTL: ssh-add -t 3600 ~/.ssh/id_ed25519_sk. Нужен изолированный бастион? Поднимите его на VDS. Если выбираете панель для управления сервером, пригодится сравнение панелей для VDS; а для инфраструктурного апгрейда смотрите переезд с шаред‑хостинга на VDS.
Если OpenSSH собран без встроенного FIDO‑провайдера, укажите источник: SecurityKeyProvider internal в клиентском конфиге.

Ротация ключей и резерв
С аппаратными токенами основная проблема — неэкспортируемость. Это хорошо для безопасности, но требует дисциплины при ротации:
- Держите два токена и выпустите по ключу на каждый. Оба публичных ключа добавьте в
authorized_keys. - Обновляйте ключи по очереди: добавляйте новые записи параллельно со старыми, затем удаляйте устаревшие.
- Храните аварийный классический ключ с ограничениями
from=иcommand=офлайн как «спасательный трос». - Документируйте процесс замены и список серверов/учёток, чтобы не потерять доступ.
Потеряли токен и резервный не настроен? Придётся восстанавливать доступ через альтернативные каналы администрирования. Планируйте аварийные сценарии заранее.
Типичные ошибки и диагностика
- Permission denied (publickey): сервер не принимает
sk-*. Проверьтеsshd -Tна предмет поддерживаемых алгоритмов, включите нужные типы, перезагрузитеsshd. - sign_and_send_pubkey: signing failed: клиент не видит токен или заблокирован доступ к USB/HID. Проверьте подключение устройства, разблокируйте ПИН, обновите libfido2, переподключите токен.
- Резидентный ключ «пропал» на новой машине: выполните
ssh-keygen -Kдля импорта публичной части из токена в~/.ssh. - PIN/UV ошибки: проверьте, что ключ выпущен с
-O verify-requiredи ПИН задан на токене. Сброс ПИН может удалить резидентные креденшалы. - WSL/виртуалки: проброс USB может быть ограничен. Используйте системный OpenSSH на хосте или продумайте прокси вместо прямого доступа к токену из гостя.
Практики безопасности
- Выпускайте ключи с
-O verify-required, чтобы подпись требовала ПИН, а не только касание. - Ограничивайте входы по IP через
from=, включайтеrestrictвauthorized_keys, разрешайте только необходимые форвардинги. - На сервере отключайте пароли (
PasswordAuthentication no) и интерактивную аутентификацию (KbdInteractiveAuthentication no), снижайтеLoginGraceTimeиMaxAuthTries. - Минимизируйте время жизни ключа в агенте:
ssh-add -t 600, и держитеForwardAgent noпо умолчанию. - Следите за журналами:
journalctl -u sshdи логи аутентификации помогут быстро отловить проблемы.
Что выбрать: ecdsa-sk или ed25519-sk
ecdsa-sk остаётся самым совместимым вариантом благодаря поддержке U2F (CTAP1) и FIDO2 (CTAP2). ed25519-sk современнее и немного компактнее, но требует новых токенов и библиотек. Компромисс для разнородной инфраструктуры: выпускать оба типа и регистрировать оба публичных ключа на критичных серверах.
Переход с классических ключей без простоя
- Выпустите новый FIDO‑ключ на токене 1, добавьте его на все нужные сервера.
- Подтвердите вход на каждого из них.
- Выпустите ключ на токене 2 и также добавьте в
authorized_keys. - Только после этого удаляйте старые классические ключи.
Если использовали автоматизацию и деплой через SSH, заранее проверьте совместимость инструментов: большинство клиентов прозрачно работают с sk-*, но первые подключения часто требуют ручного подтверждения касанием токена, что влияет на безоператорные сценарии. Для non-interactive задач используйте отдельного пользователя со строго ограниченными правами и классическим ключом, либо токен в безопасном HSM‑стенде, если подтверждение возможно.
Итоги
Переход на FIDO2/U2F‑ключи для SSH — один из самых эффективных апгрейдов безопасности для админов и девопсов. Аппаратный ключ делает невозможным тихую кражу приватного материала, а требование касания и ПИН ставит физический барьер для удалённой эксплуатации. На практике миграция сводится к обновлению OpenSSH, выпуску sk-* ключей, добавлению их на сервера и корректировке политик клиента/сервера. Дополните это разумной ротацией и резервом — и ваша поверхность атаки заметно сузится.


