На всякий: в общем-то описанное ранее все работает и даже не вызывает раздражения, но только если ваша работа не связана с регулярными походами по многим ssh серверам. В реальности регулярное ожидание “прикоснитесь к токену” начинает раздражать уже на втором десятке коннектов. А если запустить какой-нибудь ансибл плейбук, так сидишь и настукиваешь по токену, пока плейбук пройдет по серверам. А потом, где-то на середине, опять начинаешь, ибо сессия протухла. В общем, бесит неимоверно.
После гуглежа выяснилось, что у юбиков для fido2 нет опции “не требовать прикосновения Н времени”. Для gpg есть, а для fido – нет. Боль и печаль. Поэтому самый простой способ купировать это поведение – это использовать controlpath в ssh.
Для ssh это лечится добавлением в .ssh/config
следующих строк:
ControlMaster auto
ControlPath ~/.ssh/master-%r@%h:%p.socket
ControlPersist 120m
Теперь, стоит вам зайти на любой хост, как любой последующий вход в течении двух часов будет происходить по уже установленной сессии. Никаких касаний и прочего не будет. Для ансибла делаем аналогично:
$ cat .ansible.cfg
[defaults]
[ssh_connection]
ssh_args=-C -o ControlPath=~/.ssh/master-%r@%h:%p.socket -o ControlMaster=auto -o ControlPersist=120m
Теперь что ssh, что ansible будут использовать одни и те же пути, что приводит к повышению производительности. Но боль “коснись 100500 раз” просто загоняется вглубь. Что при первом запуске, что при последующих – все тоже самое. Опять гуглю. Выходит, что мимо gpg хоть так, хоть так не пройти. Ладно, у меня есть gpg!
$ gpg -K
...
sec rsa4096 2017-09-11 [SC]
F60000F98C6BC1B31FCAE943D9C4611813E9F51E
uid [ultimate] Viacheslav Kaloshin <kiltum@kiltum.tech>
ssb rsa4096 2017-09-11 [E]
Ох, аж с 2017 живет и есть пить-не просит, это хорошо. Так как у нас нынче не моден RSA, то добавляю 3 ключа ed25519:
$ gpg --quick-add-key F60000F98C6BC1B31FCAE943D9C4611813E9F51E ed25519 sign never
...
$ gpg --quick-add-key F60000F98C6BC1B31FCAE943D9C4611813E9F51E cv25519 encr never
...
$ gpg --quick-add-key F60000F98C6BC1B31FCAE943D9C4611813E9F51E ed25519 auth never
...
$ gpg -K
...
sec rsa4096 2017-09-11 [SC]
F60000F98C6BC1B31FCAE943D9C4611813E9F51E
uid [ultimate] Viacheslav Kaloshin <kiltum@kiltum.tech>
ssb rsa4096 2017-09-11 [E]
ssb ed25519 2025-03-04 [S]
ssb cv25519 2025-03-04 [E]
ssb ed25519 2025-03-04 [A]
В принципе, для ssh можно добавить только последний ключ, для auth. Но я решил танцевать по-максимуму. Так, если верить докам, то сейчас у меня уже должена появиться возможность проэкспортить ssh ключ
$ gpg --export-ssh-key F60000F98C6BC1B31FCAE943D9C4611813E9F51E
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIImOGsDlDGh27/geO2YAf+lHcQAANqjjASvNhqY0Dp1H openpgp:0x0629B65F
Да, появилось. Это не может не радовать. Быстренько добавляю в стартап скрипты следующие строки, попутно вынося все, что было с ssh-agent
export GPG_TTY="$(tty)"
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)
gpgconf --launch gpg-agent
И добавляю поддержку ssh в gpg-agent
echo enable-ssh-support >> $HOME/.gnupg/gpg-agent.conf
Открываю соседний терминал и смотрю
$ ssh-add -L
The agent has no identities.
Вот на тебе по всей морде, а не ssh ключ! Обидно, гуглю дальше. Оказывается, gpg-agent слишком секурный и просто так никому ничего не покажет. Ему надо конкретно указать, какой ключ нужен. Для этого смотрим ид ключей и добавляем в спец-файлик
$ gpg -K --with-keygrip
/Users/vvkaloshin/.gnupg/pubring.kbx
------------------------------------
sec rsa4096 2017-09-11 [SC]
F60000F98C6BC1B31FCAE943D9C4611813E9F51E
Keygrip = 5F821C94AA751454412CE7887AD0026C75AC3E54
uid [ultimate] Viacheslav Kaloshin <kiltum@kiltum.tech>
ssb rsa4096 2017-09-11 [E]
Keygrip = 282D042F0CA040CF13C881FBBCD190D4FF3B895E
ssb ed25519 2025-03-04 [S]
Keygrip = 0D336DFDE44B04C2135022A5E486A4610C0F80EA
ssb cv25519 2025-03-04 [E]
Keygrip = EE62D0C4FE020623BC0372ED44196435A269A045
ssb ed25519 2025-03-04 [A]
Keygrip = AE9CE2AC2E83722BE5F0508C7D131E91CD5FA317
$ echo AE9CE2AC2E83722BE5F0508C7D131E91CD5FA317 >> .gnupg/sshcontrol
$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIImOGsDlDGh27/geO2YAf+lHcQAANqjjASvNhqY0Dp1H (none)
Ура! Заработало! Можно раскидать публичный ключик по серверам и попробовать. Лично у меня заработало…
И работало некоторое время, пока опять не начало клянчить пароль, но на этот раз от gpg. Ну это лечится гораздо проще:
$ cat .gnupg/gpg-agent.conf
...
default-cache-ttl 34560000
max-cache-ttl 34560000
Итого, оно работает. Но где тут yubikey? А с ним оказалось еще проще. Надо просто перенести ключик из внутренней базы gpg в токен.
ВНИМАНИЕ! Сделайте бекап каталога .gnupg
! Он понадобится для второго токена
Для начала выбираем ключ
gpg --edit-key kiltum@kiltum.tech
gpg> key 1
sec rsa4096/D9C4611813E9F51E
created: 2017-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* rsa4096/B2698444DC05C50F
created: 2017-09-11 expires: never usage: E
ssb ed25519/406890D12CB9E70B
created: 2025-03-04 expires: never usage: S
ssb cv25519/973D20344A973490
created: 2025-03-04 expires: never usage: E
ssb ed25519/24C65C290629B65F
created: 2025-03-04 expires: never usage: A
[ultimate] (1). Viacheslav Kaloshin <kiltum@kiltum.tech>
gpg> key 4
sec rsa4096/D9C4611813E9F51E
created: 2017-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb* rsa4096/B2698444DC05C50F
created: 2017-09-11 expires: never usage: E
ssb ed25519/406890D12CB9E70B
created: 2025-03-04 expires: never usage: S
ssb cv25519/973D20344A973490
created: 2025-03-04 expires: never usage: E
ssb* ed25519/24C65C290629B65F
created: 2025-03-04 expires: never usage: A
[ultimate] (1). Viacheslav Kaloshin <kiltum@kiltum.tech>
gpg> key 1
sec rsa4096/D9C4611813E9F51E
created: 2017-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/B2698444DC05C50F
created: 2017-09-11 expires: never usage: E
ssb ed25519/406890D12CB9E70B
created: 2025-03-04 expires: never usage: S
ssb cv25519/973D20344A973490
created: 2025-03-04 expires: never usage: E
ssb* ed25519/24C65C290629B65F
created: 2025-03-04 expires: never usage: A
[ultimate] (1). Viacheslav Kaloshin <kiltum@kiltum.tech>
Обратите внимание на звездочку около ssb – команда key триггерит выбор ключа, а не отменяет последний выбор! И наконец, записываю ключ в yubi
gpg> keytocard
Please select where to store the key:
(3) Authentication key
Your selection? 3
sec rsa4096/D9C4611813E9F51E
created: 2017-09-11 expires: never usage: SC
trust: ultimate validity: ultimate
ssb rsa4096/B2698444DC05C50F
created: 2017-09-11 expires: never usage: E
ssb ed25519/406890D12CB9E70B
created: 2025-03-04 expires: never usage: S
ssb cv25519/973D20344A973490
created: 2025-03-04 expires: never usage: E
ssb* ed25519/24C65C290629B65F
created: 2025-03-04 expires: never usage: A
[ultimate] (1). Viacheslav Kaloshin <kiltum@kiltum.tech>
Note: the local copy of the secret key will only be deleted with "save".
gpg> save
Вроде ничего не произошло страшного, кроме запроса admin кода, верно? Проверяю
[vvkaloshin@sc-mac-00565 ~]$ gpg -K
/Users/vvkaloshin/.gnupg/pubring.kbx
------------------------------------
sec rsa4096 2017-09-11 [SC]
F60000F98C6BC1B31FCAE943D9C4611813E9F51E
uid [ultimate] Viacheslav Kaloshin <kiltum@kiltum.tech>
ssb rsa4096 2017-09-11 [E]
ssb ed25519 2025-03-04 [S]
ssb cv25519 2025-03-04 [E]
ssb> ed25519 2025-03-04 [A]
Теперь у ключика, который в yubi, появился символ >. Дескать, он во внешней штуке. Так и должно быть. Но у меня есть второй yubi, в него бы тоже этот ключик засунуть… Как быть? А очень просто: убиваем gpg-agent, восстанавливаем бекап .gnupg, вставляем второй ключ и повторяем операцию с записью ключа. Один-в-один, без всяких изменений.
И теперь барабанная дробь! Проверяю
$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIImOGsDlDGh27/geO2YAf+lHcQAANqjjASvNhqY0Dp1H cardno:23_059_666
$ ssh-add -L
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIImOGsDlDGh27/geO2YAf+lHcQAANqjjASvNhqY0Dp1H cardno:23_059_689
Выше я, абсолютно ничего не делая, просто поменял токен. gpg-agent опять оказался достаточно разумным, чтобы разрулить эту ситуацию. Теперь у меня есть аж два варианта работы с этим ключем: либо с помощью юбиков, либо восстановить .gnupg из бекапа и забить на юбики. Ключ не изменится! А что самое главное, ключ защищен аж в двух местах: пароль на gpg и пин на юбике. Оба хоть и кешируются (тут удобство для меня), но при перезагрузке/смене ключа спрашиваются (тут радуется внутренний безопасник).
Что необходимо сделать следующим? Во-первых, положить бекап .gnupg в сухое место. Во-вторых, пройтись по всяким серверам и сервисам и добавить новый ssh ключ. И наконец, самое больное: пройтись по всяким серверам и сервисам и заменить публичный pgp ключ. Причина простая и прозаическая: мы добавили новых ключей и всякие git (вы же пользуете подпись в git?) стали автоматом использовать свежее и более защищенное. Пруф:
$ git log --show-signature -1
commit 37ad3b5134621b1df18644b10884b8d17f2879f9 (HEAD -> main, origin/main, origin/HEAD)
gpg: Signature made Tue Mar 4 14:12:19 2025 MSK
gpg: using EDDSA key 12D3317E74826BD633976A76406890D12CB9E70B
gpg: Good signature from "Viacheslav Kaloshin <kiltum@kiltum.tech>" [ultimate]
Вообще зря я вас пугал болью (смаил). Это делается просто:
$ gpg --armor --export
-----BEGIN PGP PUBLIC KEY BLOCK-----
mQINBFm2d2MBEACy9YyMqPeEZEIgndjhyYOOz61WXBZtyrOaeNXlfRy2HjZZ9os2
....
=KxVu
-----END PGP PUBLIC KEY BLOCK-----
И вот этот вот текст вы суете во всем места, где просят GPG public key.
Где были проблемы? На моем пути была только одна: если у вас в gpg стоит pinentry не графический (читай: просто pinentry или pinentry-ncurses), то при попытке добавления другого, старого и проверенного ключа я получал облом.
$ ssh-add .ssh/backup/id_ed25519
Enter passphrase for .ssh/backup/id_ed25519:
Could not add identity ".ssh/backup/id_ed25519": agent refused operation
Лечится это странной командой
$ echo UPDATESTARTUPTTY | gpg-connect-agent
OK
$ ssh-add .ssh/backup/id_ed25519
Enter passphrase for .ssh/backup/id_ed25519:
Identity added: .ssh/backup/id_ed25519 (kiltum@kiltum.tech)
На всякий: удаляются такие ключи из базы gpg тоже не сложно:
$ gpg-connect-agent 'keyinfo --ssh-list' /bye
S KEYINFO AE9CE2AC2E83722BE5F0508C7D131E91CD5FA317 D - - - P - - S
S KEYINFO 716AA423769B73317BBA874ECFD11765948B5EFD D - - - P - - S
OK
$ gpg-connect-agent "delete_key --force 716AA423769B73317BBA874ECFD11765948B5EFD" /bye
OK