SSH, PGP, TOTP в Yubikey 5
Что такое Yubikey
Это аппаратный ключ безопасности, который поддерживает протокол универсальной двухфакторной аутентификации, одноразовые пароли и асимметричное шифрование. Если вы добавите его, допустим, в аккаунт на Гитхабе, то для входа в свой аккаунт, понадобится ввести логин/пароль и коснуться кнопки юбикей.
Год назад я приобрел Yubikey, чтобы использовать его в качестве второго фактора для аккаунтов Google, Github и других, которые работают с U2F. Однако я для себя выяснил, что Yubikey обладает куда более расширенным функционалом. Большая часть из нижеописанных действий актуальна для работы и без Yubikey, однако преимущество в портативности будет потеряно.
Все действия описаны для Yubikey 5 и Ubuntu 21.04.
SSH-ключи
Многие знакомы с такой простой операцией, как подключение по SSH. У нас в TOT Systems имеется собственный менеджер паролей, и чтобы подключиться к удаленной машине, нужно зайти в него, скопировать логин, адрес и пароль.
Проблема паролей в том, что их можно подобрать, поэтому для авторизации по SSH часто используют RSA-ключи. Ключ состоит из двух частей — открытой и закрытой. Открытая часть должна быть на удалённой машине, а закрытая часть у пользователя в надёжном месте, т.е. приватный ключ никому показывать нельзя. Кто-то считает надежным местом облако или флешку — места, из которых теоретически можно достать этот самый ключ. Преимущество Yubikey в том, что приватный ключ из него извлечь не получится — даже пользователь его не знает.
Для работы нам понадобятся OpenSSH версии 8.2 и библиотека libfido2. Вместо привычного RSA-файла с приватным ключом давайте создадим ключ прямо на Yubikey с алгоритмом Ed25519.
Вставляем Yubikey в USB-порт и вводим команду с опцией resident, которая означает, что приватный ключ всегда будет храниться на Yubikey, а непосредственно в компьютере находится резидентный ключ, который без аппаратного ключа бесполезен:
$ ssh-keygen -t ed25519-sk -O resident
user@pc:~$ ssh-keygen -t ed25519-sk -O resident
Generating public/private ed25519-sk key pair.
You may need to touch your authenticator to authorize key generation.
Enter PIN for authenticator:
Enter file in which to save the key (/home/user/.ssh/id_ed25519_sk):
Enter passphrase (empty for no passphrase):
Enter same passphrase again:
Your identification has been saved in /home/user/.ssh/id_ed25519_sk
Your public key has been saved in /home/user/.ssh/id_ed25519_sk.pub
The key fingerprint is:
SHA256:ztpJ8rTSlo07BQ0LyL6hI2X9/CE9fTdy0EQZhAnxc74 user@pc
The key's randomart image is:
+[ED25519-SK 256]-+
| . . oo =+o |
| o . . .o o |
| o . + oo. |
| o + o . .+. |
| o . = .So .. |
|. o . +o+ o o +. |
| . . .+=B . +E. |
| .BBo. |
| .o*o |
+----[SHA256]-----+
Сначала нас попросят ввести пин-код от Yubikey. Если до этого вы не настраивали свой юбикей, то User PIN по-умолчанию — 123456, а Admin PIN — 12345678.
После ввода User PIN кнопка юбикей начнет мигать — нажимаем на неё. Выбираем место для сохранения ключей (предлагаю не менять директорию). Далее 2 раза вводим фразу-пароль для этого ключа.
В директории ~/.ssh появятся два файла: id_ed25519_sk.pub
, который является обычным публичным ключом, и id_ed25519_sk
, который является резидентным ключом и ссылается на приватный ключ в Yubikey.
Теперь добавим публичный ключ на SSH-сервер, к которому мы хотим подключиться. Для этого заходим на сервер как обычно с помощью пароля, переходим в папку ~/.ssh
и находим в ней файл authorized_keys
, а если его нет, то создаём. В этот файлик копируем содержимое нашего публичного ключа. Пробуем авторизоваться:
user@pc:~$ ssh user@192.168.0.12
Enter passphrase for key '/home/user/.ssh/id_ed25519_sk':
Confirm user presence for key ED25519-SK SHA256:ztpJ8rTSlo07BQ0LyL6hI2X9/CE9fTdy0EQZhAnxc74
Welcome to Ubuntu 21.04 (GNU/Linux 5.11.0-25-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
0 updates can be applied immediately.
*** System restart required ***
Last login: Sat Jul 24 20:12:35 2021 from 192.168.0.47
Нас попросят ввести фразу-пароль от ключа, а затем нажать на кнопку Yubikey — успешно авторизуемся. При этом возможность авторизоваться по паролю никуда не пропала.
Если предварительно вынуть юбикей из USB-порта и попробовать авторизоваться, то после ввода парольной фразы от ключа у нас будет ошибка и нам будет предложено ввести пароль от сервера.
Сгенерировать ключи и хранить их на компьютере можно и без Yubikey, но в таком случае возникает потребность в переносе приватного ключа между компьютерами, на которых необходим доступ к серверу. Преимущество Yubikey в том, что ключи всегда хранятся на нём, и при работе на другом компьютере можно легко получить резидентный и публичный ключи.
К примеру, импортируем ключи с юбикея на новый компьютер. Запускаем терминал в папке ~/.ssh
:
$ ssh-keygen -K
Вводим пин-код, парольную фразу и получаем два файла: id_ed25519_sk_rk
(резидентный ключ) и id_ed25519_sk_rk.pub
(публичный ключ). Переименовываем id_ed25519_sk_rk
в id_ed25519_sk
. Успешно авторизуемся на новом компьютере.
SSH-ключ и U2F на примере Github
С помощью SSH-ключа можно клонировать репозиторий на гитхабе. Для этого добавляем публичный ключ в аккаунт на гитхабе. Теперь попробуем клонировать репозиторий по SSH:
user@pc:~/Документы$ git clone git@github.com:oleguka/Store.git
Клонирование в «Store»…
Enter passphrase for key '/home/user/.ssh/id_ed25519_sk':
Confirm user presence for key ED25519-SK SHA256:ztpJ8rTSlo07BQ0LyL6hI2X9/CE9fTdy0EQZhAnxc74
remote: Enumerating objects: 30, done.
remote: Counting objects: 100% (30/30), done.
remote: Compressing objects: 100% (19/19), done.
remote: Total 30 (delta 0), reused 30 (delta 0), pack-reused 0
Получение объектов: 100% (30/30), 55.69 KiB | 670.00 KiB/s, готово.
Нас попросят ввести парольную фразу, а также коснуться кнопки юбикея. Вуаля — репозиторий клонирован. Теперь можно проверить, будет ли клонирован репозиторий без юбикея. Вытаскиваем его из USB-порта и попытаемся клонировать другую репу.
user@pc:~/Документы$ git clone git@github.com:oleguka/Cookie.git
Клонирование в «Cookie»…
Enter passphrase for key '/home/user/.ssh/id_ed25519_sk':
Confirm user presence for key ED25519-SK SHA256:ztpJ8rTSlo07BQ0LyL6hI2X9/CE9fTdy0EQZhAnxc74
sign_and_send_pubkey: signing failed for ED25519-SK "/home/user/.ssh/id_ed25519_sk": invalid format
git@github.com: Permission denied (publickey).
fatal: Не удалось прочитать из внешнего репозитория.
Удостоверьтесь, что у вас есть необходимые права доступа
и репозиторий существует.
Клонировать репу не получается.
Поддержка U2F для SSH-ключей на данный момент реализована только в гитхабе. Если у вас используется gitlab, то использовать ключ с юбикея, к сожалению, не получится.
GPG
Теперь поговорим про GPG — программу с ассиметричным шифрованием. С её помощью можно шифровать, подписывать данные, а также авторизовываться по SSH на серверах. Давайте подпишем коммит с помощью gpg.
Для работы с Yubikey Нужно установить scdaemon:
$ sudo apt install scdaemon
При выводе списка ключей gpg по умолчанию показывает ключи без id — только их отпечаток. Предлагаю это исправить, поскольку для дальнейших действий удобно использовать именно id ключей. Для этого в папке ~/.gnupg
создаем конфиг gpg.conf
, а в нём пишем одну строчку — keyid-format long
.
Перед созданием RSA-ключа и сабключей поменяем их размер на 4096 бит.
Для этого перейдём в меню смарт-карты.
user@pc:~$ gpg --card-edit
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006134534820000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 13453482
Name of cardholder: Oleg Tolstykh
Language prefs ...: ru
Salutation .......: Mr.
URL of public key : https://github.com/otolstykh.gpg
Login data .......: olegulka
Signature PIN ....: не требуется
Key attributes ...: rsa2048 rsa2048 rsa2048
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 5
KDF setting ......: off
Signature key ....: [none]
Encryption key....: [none]
Authentication key: [none]
General key info..: [none]
Появилась основная информация о нашей карте. Видим, что длина ключа 2048 — переключаемся в админ-режим:
gpg/card> admin
и отредактируем длину ключа на 4096:
gpg/card> key-attr
Изменение атрибутов ключа на карте: Ключа для подписи
Выберите тип ключа:
(1) RSA
(2) ECC
Ваш выбор? 1
Какой размер ключа Вам необходим? (2048) 4096
Изменение атрибутов ключа на карте: Ключа для шифрования
Выберите тип ключа:
(1) RSA
(2) ECC
Ваш выбор? 1
Какой размер ключа Вам необходим? (2048) 4096
Изменение атрибутов ключа на карте: Ключа для удостоверения личности
Выберите тип ключа:
(1) RSA
(2) ECC
Ваш выбор? 1
Какой размер ключа Вам необходим? (2048) 4096
Теперь перейдём к созданию ключей. В самом начале у нас спросят, делать ли резервную копию ключа шифрования. Также спросят срок жизни ключей. Отредактировать этот срок можно в любой момент.
gpg/card> generate
Сделать вне карты архивную копию ключа шифрования? (Y/n) n
Выберите срок действия ключа.
0 = не ограничен
= срок действия ключа - n дней
w = срок действия ключа - n недель
m = срок действия ключа - n месяцев
y = срок действия ключа - n лет
Срок действия ключа? (0) 0
Срок действия ключа не ограничен
Все верно? (y/N) y
GnuPG должен составить идентификатор пользователя для идентификации ключа.
Ваше полное имя: Oleg Tolstykh
Адрес электронной почты: otolstykh@yandex.ru
Примечание: Yubikey
Вы выбрали следующий идентификатор пользователя:
"Oleg Tolstykh (Yubikey) "
Сменить (N)Имя, (C)Примечание, (E)Адрес; (O)Принять/(Q)Выход? O
gpg: ключ 60D70CA6AFBAB10F помечен как абсолютно доверенный
gpg: создан каталог '/home/user/.gnupg/openpgp-revocs.d'
gpg: сертификат отзыва записан в '/home/user/.gnupg/openpgp-revocs.d/306836E54FE0FF47B9277BDB60D70CA6AFBAB10F.rev'.
открытый и секретный ключи созданы и подписаны.
Проверяем, что ключ сгенерировался и отображается на карте:
gpg/card> list
Reader ...........: 1050:0407:X:0
Application ID ...: D2760001240103040006134534820000
Application type .: OpenPGP
Version ..........: 3.4
Manufacturer .....: Yubico
Serial number ....: 13453482
Name of cardholder: Oleg Tolstykh
Language prefs ...: ru
Salutation .......: Mr.
URL of public key : https://github.com/otolstykh.gpg
Login data .......: olegulka
Signature PIN ....: не требуется
Key attributes ...: rsa4096 rsa4096 rsa4096
Max. PIN lengths .: 127 127 127
PIN retry counter : 3 0 3
Signature counter : 4
KDF setting ......: off
Signature key ....: 3068 36E5 4FE0 FF47 B927 7BDB 60D7 0CA6 AFBA B10F
created ....: 2021-07-29 07:27:33
Encryption key....: E1CB FF3A 8F81 8B63 59A7 068C F92E 2F31 6078 5D40
created ....: 2021-07-29 07:27:33
Authentication key: 8493 6F5D 23D0 8D09 D918 BEE6 9C3A 3873 BA8A 4CC1
created ....: 2021-07-29 07:27:33
General key info..:
pub rsa4096/60D70CA6AFBAB10F 2021-07-29 Oleg Tolstykh (Yubikey)
sec> rsa4096/60D70CA6AFBAB10F создан: 2021-07-29 годен до: никогда
номер карты: 0006 13453482
ssb> rsa4096/9C3A3873BA8A4CC1 создан: 2021-07-29 годен до: никогда
номер карты: 0006 13453482
ssb> rsa4096/F92E2F3160785D40 создан: 2021-07-29 годен до: никогда
номер карты: 0006 13453482
Выводим содержимое публичного ключа в терминал:
user@pc:~$ gpg --armor --export 60D70CA6AFBAB10F
Или экспортируем публичный ключ в файл, а затем добавляем его в свой аккаунт в гитлабе:
user@pc:~$ gpg --output .gnupg/yubikey.asc --armor --export
Теперь создадим глобальный конфиг файл ~/.gitconfig
с содержимым:
[user]
name = otolstykh
email = otolstykh@yandex.ru
signingkey = 60D70CA6AFBAB10F
[commit]
gpgsign = true
Или если у вас IDEA версии 2021.2 и выше, то вы можете прямо в её настройках выбрать ключ для подписи коммитов — Settings | Version Control | Git | Configure GPG Key
После этого ваши коммиты будут подписаны:
Допустим, мы хотим воспользоваться нашими ключами на новом компьютере. Для этого на карте нужно указать url публичного ключа. Для этого переходим к редактированию карты и в админ-режиме редактируем url:
gpg/card> url
URL для получения открытого ключа: https://github.com/otolstykh.gpg
Для гитхаба url нашего ключа выглядит так. Для гитлаба аналогично. Вы можете хранить публичный ключ на любом сервере публичных ключей.
Теперь на новом компьютере вводим команду fetch
gpg/card> fetch
gpg: запрос ключа из 'https://github.com/otolstykh.gpg'
gpg: ключ 60D70CA6AFBAB10F: импортирован открытый ключ "Oleg Tolstykh (Yubikey) "
gpg: Всего обработано: 1
gpg: импортировано: 1
Далее повысим уровень доверия к ключу командой trust:
user@home:~$ gpg --edit-key 60D70CA6AFBAB10F
gpg> trust
sec rsa4096/60D70CA6AFBAB10F
создан: 2021-07-29 годен до: никогда назначение: SC
номер карты: 0006 13453482
доверие: неизвестно достоверность: неизвестно
ssb rsa4096/9C3A3873BA8A4CC1
создан: 2021-07-29 годен до: никогда назначение: A
номер карты: 0006 13453482
ssb rsa4096/F92E2F3160785D40
создан: 2021-07-29 годен до: никогда назначение: E
номер карты: 0006 13453482
[ неизвестно ] (1). Oleg Tolstykh (Yubikey)
Укажите, насколько Вы доверяете данному пользователю в вопросах проверки
достоверности ключей других пользователей (проверяет паспорт,
сверяет отпечатки ключей из разных источников и т.п.)
1 = Не знаю или не буду отвечать
2 = НЕ доверяю
3 = Доверяю ограниченно
4 = Полностью доверяю
5 = Абсолютно доверяю
m = вернуться в главное меню
Ваше решение? 5
Вы действительно хотите сделать этот ключ абсолютно доверенным? (y/N) y
sec rsa4096/60D70CA6AFBAB10F
создан: 2021-07-29 годен до: никогда назначение: SC
номер карты: 0006 13453482
доверие: абсолютное достоверность: неизвестно
ssb rsa4096/9C3A3873BA8A4CC1
создан: 2021-07-29 годен до: никогда назначение: A
номер карты: 0006 13453482
ssb rsa4096/F92E2F3160785D40
создан: 2021-07-29 годен до: никогда назначение: E
номер карты: 0006 13453482
[ неизвестно ] (1). Oleg Tolstykh (Yubikey)
Учтите, что показанная достоверность ключа может быть неверной,
пока Вы не перезапустите программу.
Всё, теперь мы можем подписывать коммиты, шифровать файлы с помощью одного ключа, который всегда хранится на Yubikey, и если юбикей не вставлен в порт компьютера, то сделать это нельзя.
TOTP
И последнее, о чем я хочу рассказать — это использование Yubikey для генерации одноразовых кодов, причём коды будут храниться, разумеется, на Yubikey. В этом случае не нужно думать о бэкапе кодов в приложении при смене смартфона или переустановке системы. Однако нужно будет пользоваться приложением от Yubikey, которые есть для iOS/Android. У меня версия Yubikey c обычным USB-портом и NFC. Чтобы добавить код или считать список всех кодов, достаточно поднести юбикей к NFC считывателю смартфона. Таким образом я добавил все сервисы, которыми пользуюсь и в которых нет поддержки U2F, однако добавить второй фактор в Яндексе у меня не получилось, так как они используют Двухфакторную аутентификацию, которой удобно пользоваться (на самом деле не так удобно), и коды для Яндекса возможно генерировать только в их приложении.
В заключение. Лично мне безумно удобно использовать Yubikey для личных и рабочих целей, особенно в формате рабочий/домашний компьютер — пользуюсь и радуюсь :)