PIV – это стандарт двухфакторной аутентификации с использованием смарт-карт. И есть более специфический стандарт, который чаще всего используется в этом направлении: PKCS #11.

PKCS #11 – это уже стандарт программной имплементации интерфейса доступа к смарт-картам, токенам и другим криптографическим устройствам.

По итогу получится такая схема, когда публичный и приватный ключ будет храниться прямо на YubiKey, никогда его не покинет, а значит невозможно будет аутентифицироваться без физически подключённого YubiKey. Двигаемся дальше.

YubiKey предоставляет интерфейс PKCS #11, а SSH умеет подгружать специфическую динамическую библиотеку, которая и будет отвечать за взаимодействие по интерфейсу PKCS #11 c YubiKey. И нам останется лишь сгенерировать ключи, добавить их на сервер, и наслаждаться секьюрным решением!

Весь процесс проделывал с:

  • YubiKey 5C NFC;
  • macOS 14.5 Sonoma.

Подготовка

Нам понадобится взаимодействовать с YubiKey для дальнейшей генерации ключей. Для этого понадобится установить две утилиты: Yubico PIV Tool и Yubikey Manager.

macOS

На macOS для этого можно использовать brew:

brew install yubico-piv-tool yubico-yubikey-manager

И важно скопировать динамическую библиотеку, которая понадобится нашему SSH позже:

sudo cp /opt/homebrew/Cellar/yubico-piv-tool/2.3.1/lib/libykcs11.2.3.1.dylib /usr/local/lib/libykcs11.dylib

Обратите внимание, что в моём случае версия yubico-piv-tool была 2.3.1. Замените номер версии на тот, который у вас.

Первоначальная настройка YubiKey

В этой части мы установим PIN и PUK коды, и сгенерируем "management key" для безопасного взаимодействия с YubiKey.

Если всё это вы уже настроили, то можете перейти к следующему шагу.

  1. Мы будем работать с командой ykman. Она поставляется вместе с Yubikey Manager, поэтому для удобства можем прописать alias:
alias ykman="/Applications/YubiKey\ Manager.app/Contents/MacOS/ykman"
  1. Далее установим PIN и PUK код
    1. PIN код – тот, который вы будете вводить при использовании YubiKey
    2. PUK код – тот, который нужно будет ввести, если вы забудете PIN и израсходует попытки ввода (да, они ограничены)
ykman piv access change-pin
ykman piv access change-puk
  1. Последнее что остаётся – сгенерировать management key, который мы будем использовать далее при заполнении PIV слотов. Строго говоря его генерация необязательна (вроде), но без неё у меня далее ничего не работало. Поэтому запускаем команду
ykman piv access change-management-key --generate --protect

Генерация ключей

Приватный ключ

Для подписи дальнейших шагов нужно сгенерировать ключ следующей командой:

yubico-piv-tool --key -s 9a -AECCP384 -a generate --pin-policy=once --touch-policy=always -o public.pem

Эта команда сгенерирует приватный ключ прямо на YubiKey, и сохранит на вашем компьютере публичный ключ в файл public.pem.

Вы также можете поправить некоторые опции:

  • --pin-policy – политика ввода PIN кода. Возможные значения:
    • never – никогда не вводить пин-код, достаточно подключённого YubiKey;
    • always – вводить пароль при каждом использовании;
    • once – вводить пароль единожды для каждой сессии. Сессия – период между подключением и отключением YubiKey.
  • --touch-policy – политика требования касания сенсорной кнопки YubiKey. Возможные значения:
    • never – никогда не требоваться касания:
    • always – всегда требовать касание;
    • cached – не требовать касание в течение 15 секунд после последнего (удобно, когда нужно залогиниться в несколько мест сразу).

Подробнее про опции можете почитать в официальной документации.

PIV сертификат

Стандарт PIV требует использование сертификата. Поскольку выше мы предпочли сгенерировать приватный ключ прямо на YubiKey, то нам достаточно запустить одну команду:

yubico-piv-tool --key -a verify-pin -a selfsign-certificate -s 9a --subject "/CN=SSH key/" --valid-days=3650 -i public.pem -o cert.pem

И сертификат окажется в слоте 9a на YubiKey.

Публичный SSH ключ

И остаётся последнее: получить публичный SSH ключ, чтобы затем добавить его на сервере:

ssh-keygen -D /usr/local/lib/libykcs11.dylib -e

Команда выведет публичный ключ, который нужно добавить в ~/.ssh/authorized_keys на вашем сервере.

И после этого можно пытаться залогиниться:

ssh -o "PKCS11Provider /usr/local/lib/libykcs11.dylib" user@remote

Обратите внимание на библиотеку. Именно её мы скопировали по этому пути в шаге "Подготовка"

Здесь вы можете столкнуться с проблемой, что SSH не сможет "спросить" у вас пин-код. Если такое случится, то вам нужно установить скрипт этого самого окна, чтобы SSH в него "перенаправил" запрос пин-кода. Самое простое: установить brew install michaelroosz/ssh/libsk-libfido2-install (и пусть вас не смущает FIDO2, в комплекте автор оставил нужный нам скрипт), и затем прописать переменные окружения в вашем ~/.zshrc или ~/.bash_profile:

export SSH_ASKPASS=/opt/homebrew/bin/ssh-askpass
export DISPLAY=":0"

Желательно это делать в самом верху файла, если у вас установлен автоматический ssh-agent. Тогда он будет использовать эту конфигурацию.

Пара советов

Рекомендую прописать PKCS11Provider в вашем ~/.ssh/config, чтобы не нужно было писать эту опцию каждый раз руками:

Host *
    PKCS11Provider /usr/local/lib/libykcs11.dylib

Вы также можете настроить переиспользование установленного SSH соединения между несколькими сессиями, чтобы не касаться каждый раз аппаратного ключа:

Host bitbucket.org
    ControlMaster auto
    ControlPath ~/.ssh/S.%r@%h:%p
    ControlPersist 10m

Ссылки

Обязательно смотрите сам ролик про мою попытку безопасно работать с SSH: Как использовать SSH ПРАВИЛЬНО | YubiKey, FIDO2, PIV и правила использования SSH ключей.

Статьи, видео и инструкции не появилось бы без следующих материалов:

  1. PIV Walk-Through в официальной документации
  2. Вновь официальная документация по ykman
  3. Великолепная инструкция от человека с ником m3nu, которая легла в основу этой статьи