Ранее мы уже писали об использовании TPM для автоматической разблокировки LUKS. В данной статье мы подробно рассмотрим возможность безопасного хранения SSH-ключей внутри TPM чипа версии 2.0.
Введение
Классическое хранение ключей в виде файлов внутри каталога ~/.ssh является очень небезопасным, т.к. любое приложение с доступом к домашнему каталогу пользователя сможет их оттуда извлечь и, в случае подбора пароля, получить доступ к соответствующим серверам.
В качестве более безопасной альтернативы можно использовать аппаратные токены, либо TPM 2.0. При этом ключи будут сгенерированы непосредственно внутри данных устройств и сохранены в не экспортируемом виде, т.е. злоумышленник в случае компрометации приложения не сможет их сохранить и передать куда-либо.
О TPM
TPM (Trusted Platform Module) — это специальный криптопроцессор, внутри которого генерируются и надёжно хранятся без возможности извлечения ключи шифрования.
Для работы с SSH-ключами нам потребуется компьютер или ноутбук, оснащённый чипом TPM версии 2.0 (или выше).
Проверка функциональности
Убедимся, что в устройстве имеется подходящий TPM модуль:
test -c /dev/tpm0 && echo OK || echo FAIL
Если в ответ выведено сообщение об успехе, то можем продолжать. В противном случае при его отсутствии приобретём и установим TPM версии 2.0, либо активируем в UEFI BIOS устройства.
Предварительная настройка
Если мы используем доверенный программный модуль впервые, перейдём в UEFI BIOS устройства, на страницу управления TPM-модулем, затем очистим его, т.к. без этого мы не сможем переключиться в режим администрирования для добавления новых ключей.
Внимание! Все ключи полнодискового шифрования Windows 10/11 или LUKS при этом будут уничтожены, поэтому потребуется ввод основного пароля или кода восстановления, а затем повторная настройка.
Установка необходимых пакетов
Установим необходимые утилиты и библиотеки для работы с TPM:
sudo dnf install tpm2-pkcs11 tpm2-pkcs11-tools tpm2-tools
Настройка прав доступа
Доступом к TPM обладают исключительно участники группы tss, поэтому добавим свою учётную запись в неё:
sudo usermod -a -G tss $(whoami)
Произведём перезагрузку или новый вход в систему для принятия изменений.
Создание нового SSH-ключа в TPM
Добавим новый слот в пользовательское хранилище TPM:
tpm2_ptool init
Спустя некоторое время, что зависит от производительности криптопроцессора, утилита сообщит номер слота, который был создан. При первом использовании он будет равен 1.
Сгенерируем новый ключ и добавим его в созданный слот:
tpm2_ptool addtoken --pid=1 --label='MySSHKey' --userpin='PIN' --sopin='PUK' tpm2_ptool addkey --label='MySSHKey' --userpin='PIN' --algorithm='rsa2048'
Описание используемых параметров командной строки:
- label — пользовательская метка слота (допускаются только латинские буквы и цифры без пробелов);
- userpin — PIN-код, который будет запрашиваться SSH-агентом при использовании ключа (также может содержать только латинские буквы и цифры). Допускается не указывать его вообще, передав пустую строку. В таком случае он не будет запрашиваться;
- sopin — PUK-код или пароль, который может быть использован в случае утери основного PIN-кода для его смены;
- algorithm — алгоритм генерации ключа. Поддерживаются классические RSA-2048 (значение rsa2048), а также на базе эллиптической кривой NIST P-256 (значение ecc256).
Экспортируем публичный ключ в файл:
ssh-keygen -D /usr/lib64/pkcs11/libtpm2_pkcs11.so -e | tee ~/.ssh/tpm_rsa.pub
Добавим его в ~/.ssh/authorized_keys на требуемых серверах, а также загрузим в настройки аккаунта на GitHub, GitLab, BitBucket и т.д.
Импорт существующего ключа в TPM
В качестве альтернативы рассмотрим и способ с выгрузкой существующего RSA или ECC ключа из файла в TPM.
Импортируем закрытый ключ из ~/.ssh/id_rsa:
tpm2_ptool import --label='MySSHKey' --userpin='PIN' --privkey='~/.ssh/id_rsa' --passin='KEY_FILE_PASSWORD' --algorithm='rsa'
Описание используемых параметров командной строки:
- label — пользовательская метка слота (допускаются только латинские буквы и цифры без пробелов);
- userpin — PIN-код, который будет запрашиваться SSH-агентом при использовании ключа (также может содержать только латинские буквы и цифры). Допускается не указывать его вообще, передав пустую строку. В таком случае он не будет запрашиваться;
- privkey — полный путь на диске к файлу импортируемого ключа;
- passin — пароль для расшифровки файла импортируемого ключа (при отсутствии не указывается);
- algorithm — алгоритм импортируемого ключа. Поддерживаются RSA (значение rsa) или NIST P (значение ecc).
Прямое использование ключей
Проверка подключения
Для проверки работы однократно подключимся к SSH-серверу с использованием ключа из TPM:
ssh -I /usr/lib64/pkcs11/libtpm2_pkcs11.so user@example.org
Частные серверы
Откроем файл конфигурации клиента OpenSSH ~/.ssh/config и добавим новый хост:
Host example HostName example.org Port 22 User user PKCS11Provider /usr/lib64/pkcs11/libtpm2_pkcs11.so PreferredAuthentications publickey
Подключимся штатным способом по имени хоста:
ssh example
Публичные серверы
В качестве примера настроим подключение с использованием TPM к GitHub. Для этого добавим в конец ~/.ssh/config следующий текст:
Host github.com Hostname github.com Port 22 User git PKCS11Provider /usr/lib64/pkcs11/libtpm2_pkcs11.so PreferredAuthentications publickey
Автоматическое использование ключей
Этот способ самый простой и надёжный, т.к. работает с уже запущенным SSH-агентом используемой рабочей среды и не требует изменения конфигурации клиентов OpenSSH.
Ручное добавление
Добавим созданный, либо импортированный ключ в ssh-agent:
ssh-add -s /usr/lib64/pkcs11/libtpm2_pkcs11.so
Если был задан PIN-код, введём его.
Автоматическое добавление при входе в систему
Воспользуемся руководством из нашей статьи по разблокировке SSH-ключей при входе в систему, лишь незначительно изменив команду запуска. Мы не будем целиком копировать её, ограничившись лишь парой готовых примеров для самых распространённых конфигураций.
Пример для KDE Plasma 5 с использованием связки ключей KDE Wallet для хранения PIN-кода:
[Unit] Description=Add SSH keys from TPM After=plasma-kwallet-pam.service [Service] Type=oneshot ExecStart=/usr/bin/ssh-add -s /usr/lib64/pkcs11/libtpm2_pkcs11.so Environment="SSH_ASKPASS=/usr/bin/ksshaskpass" [Install] WantedBy=graphical-session.target
Пример для любой DE при отсутствии необходимости ввода PIN-кода:
[Unit] Description=Add SSH keys from TPM [Service] Type=oneshot ExecStart=/usr/bin/ssh-add -s /usr/lib64/pkcs11/libtpm2_pkcs11.so [Install] WantedBy=graphical-session.target
Заключение
Итак, мы сгенерировали ключи внутри TPM-чипа и настроили его использование в клиенте OpenSSH.
Количество доступных слотов под ключи ограничено и зависит исключительно от установленного доверенного программного модуля.
Из-за ограничений аппаратных реализаций TPM, многие модули поддерживают RSA-ключи длиной не более 2048 бит.
Литература
При написании данной статьи использовалась литература из следующих источников:
В Debian данная инструкция тоже работает за исключением имен пакетов и пути к библиотеке.
Имена пакетов: libtpm2-pkcs11-1 и libtpm2-pkcs11-tools.
Путь к библиотеке: /usr/lib/x86_64-linux-gnu/libtpm2_pkcs11.so.1.
Да, работать должно в любом дистрибутиве с опакеченой библиотекой tpm2-pkcs11.
Будет ли это работать с ключами ed25519?
Тип поддерживаемых ключей зависит исключительно от реализации TPM-чипа.
Установленная в моём ноутбуке модель поддерживает лишь NIST P-256 и RSA, причём длиной не более 2048 бит.