Используем TPM для хранения SSH-ключей

Ранее мы уже писали об использовании 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 бит.

Литература

При написании данной статьи использовалась литература из следующих источников:

4 commentary to post

  1. В Debian данная инструкция тоже работает за исключением имен пакетов и пути к библиотеке.

    Имена пакетов: libtpm2-pkcs11-1 и libtpm2-pkcs11-tools.
    Путь к библиотеке: /usr/lib/x86_64-linux-gnu/libtpm2_pkcs11.so.1.

  2. Будет ли это работать с ключами ed25519?

    1. Тип поддерживаемых ключей зависит исключительно от реализации TPM-чипа.

      Установленная в моём ноутбуке модель поддерживает лишь NIST P-256 и RSA, причём длиной не более 2048 бит.

Обсуждение закрыто.