- Что такое и зачем нужен SSH Agent
- Включение в Linux (debian/ubuntu)
- Включение в Macos
- Особенности gpg-agent
- Базовые сценарии и операции
- Как остановить/запустить/перезапустить агент
- Просмотр списка ключей в агенте
- Добавление ключа в агент
- Добавление ключа с TTL=60 секунд
- Добавление ключа с включенным подтверждением
- Удаление ключа из агента
- Очистить закешированные пароли
- Модификация параметров ключа в агенте
- Модификация TTL по умолчанию
- Работа агента ломается после второй одновременной сессии этого же пользователя
- История изменений
Что такое и зачем нужен SSH Agent¶
SSH Agent (SSH Агент) хранит в памяти компьютера закрытые SSH-ключи. Когда SSH-клиент (/usr/bin/ssh
в линуксе и макоси, например) пытается подключиться к серверу при помощи ключа, она сначала делает запрос к SSH Agent и делегирует ему криптографическую операцию с закрытым ключом, который никогда не покидает пределы агента.
Без SSH Agent SSH-клиент напрямую читает ключи с диска, в линуксе и макоси они лежат в каталоге ~/.ssh
, если ключ зашифрован, то клиент спрашивает соответствующую парольную фразу. SSH Agent импортирует ключи к себе в хранилище и требует задать новую парольную фразу для доступа к ключу. Агент запоминает, когда клиент запрашивал ключ и может потребовать ввести парольную фразу и/или показать дополнительный диалог с подтверждением.
В linux и macos по умолчанию стоит /usr/bin/ssh-agent
из openssh, однако он малофунциональный и сложный в настройке. Вместо него можно использовать агент из комплекта gnupg (gpg-agent
), он умеет не только PGP-ключами управлять, но и выполнять функцию SSH Агента. У gpg-agent есть два преимущества: он настраивается, а также позволяет задавать пароли для шифрования ключей в памяти.
Включение в Linux (debian/ubuntu)¶
Сначала отключаем автоматический старт ssh-agent, для этого открываем редактором файл /etc/X11/Xsession.options
и комментируем/удаляем строчку:
use-ssh-agent
Устанавливаем нужные пакеты:
$ sudo apt install gpg-agent pinentry-qt
Выбираем GUI pinentry (это диалоги, которые вы будете видеть при работе с ключами, например, для запроса парольной фразы к ключу) вместо дефолтного консольного приложения:
$ sudo update-alternatives --set pinentry /usr/bin/pinentry-qt
gpg-agent стартует автоматически в X-сессии, дополнительно никакие скрипты писать для старта не нужно. Однако по умолчанию в GPG Agent поддержка SSH-ключей выключена, для включения нужно сделать так:
$ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
Всё, теперь после рестарта X-сессии у вас будет использоваться gpg-agent вместо ssh-agent.
Включение в Macos¶
Речь идёт о MacOS 10.12 (Sierra) и выше.
Вы можете получить GPG двумя способами: через brew или установкой пакета GPG Suite. Каждый из них устанавливает все нужные для работы программы и работают они в принципе одинаково, однако в GPG Suite удобнее реализована настройка через GUI. Я не рекомендую устанавливать сразу оба, так как они конфликтуют за пути установки.
Установка через brew¶
$ brew install gnupg pinentry-mac
Установка GPG Suite¶
Заходите на сайт https://gpgtools.org, скачивайте оттуда .dmg-файл и устанавливайте как обычное приложение.
Включение автозапуска агента¶
gpg-agent автоматически не стартует, поэтому нужно добавить в систему его автозапуск, я написал конфиг для launchd, вот команда, которая его скачивает в корректный каталог:
$ mkdir ~/Library/LaunchAgents
$ curl -L https://raw.githubusercontent.com/sigsergv/dotfiles/master/mac/gnupg/gpg-agent.daemon.plist \
-o ~/Library/LaunchAgents/gpg-agent.daemon.plist
Теперь запускаем:
$ launchctl load -F ~/Library/LaunchAgents/gpg-agent.daemon.plist
И убеждаемся, что действительно работает:
$ pgrep -lf gpg-agent
15092 gpg-agent --homedir /Users/sigsergv/.gnupg --use-standard-socket --daemon
$
Если команда ничего не выводит, значит, вы что-то сделали не так.
Поддержка SSH включается точно так же, как и для linux:
$ echo enable-ssh-support >> ~/.gnupg/gpg-agent.conf
Замена ssh-agent на gpg-agent¶
В прошлой версии статьи я использовал сложный метод через выключение/включение SIP и полное жёсткое отключение штатного ssh-agent, но есть не такой радикальный и гораздо более безопасный способ.
Изначально в макоси запущен встроенный ssh-agent и для него глобально выставляется переменная окружения SSH_AUTH_SOCK. В новых версиях макоси поменять её значение просто так невозможно, поэтому мы пойдём другим путём — в процессе входа пользователя просто перезапишем файл-сокет исходного ssh-agent и превратим его в симлинк, указывающий на сокет gpg-agent. Эту идею и соответствующий скрипт я взял из отличной статьи Stick with security: YubiKey, SSH, GnuPG, macOS.
Вам нужно скачать plist-конфиг gpg-agent-socket-override.plist с моего гитхаба и положить в каталог ~/Library/LaunchAgents
, вот команда, которая всё это делает:
$ curl -L https://raw.githubusercontent.com/sigsergv/dotfiles/master/mac/gnupg/gpg-agent-socket-override.plist \
-o ~/Library/LaunchAgents/gpg-agent-socket-override.plist
Загружаем этот конфиг:
$ launchctl load -F ~/Library/LaunchAgents/gpg-agent-socket-override.plist
И проверяем, что всё запустилось:
$ launchctl list | grep gpg-agent-socket-override
- 0 gpg-agent-socket-override
$ ls -lah $SSH_AUTH_SOCK
lrwxr-xr-x 1 sigsergv wheel 35B 1 май 10:21 /private/tmp/com.apple.launchd.ekWVW4zD9n/Listeners -> /Users/sigsergv/.gnupg/S.gpg-agent.ssh
Для гарантии перезагружаемся.
❈ ❈ ❈
По умолчанию GPG Suite сохраняет пароль к расшифрованному ключу в системном Keychain, визуально это проявляется как отсутствие диалога запроса ключа. Это можно отключить в настройках: System Settings → GPG Suite → Store in macOS Keychain.
Также, похоже, GPG Suite игнорирует настройки времени кеширования ключа из файла ~/.gnupg/sshcontrol
и всегда использует значение из собственного глобального конфига (System Settings → GPG Suite → Remember for XXXX seconds).
Особенности gpg-agent¶
Отличия gpg-agent от ssh-agent:
- можно выбирать, какие конкретно ключи хранить в агенте и они там будут храниться после перезагрузки;
- для каждого ключа можно отдельно задать время жизни доступа к нему и дополнительное подтверждение на использование;
- у gpg-agent есть дополнительный уровень защиты — пароль на доступ к ключу;
- сразу есть GUI для контроля доступа без необходимости колдовать с переменными окружения и сторонними пакетами.
Если у вас в /etc/ssh/ssh_config
или ~/.ssh/config
не включена опция AddKeysToAgent, то ключи сами в агент не попадут. Идентификаторы одобренных для агента ключей сохраняются в ~/.gnupg/sshcontrol
. Их можно туда добавлять вручную или через ssh-add
.
Например, если вы хотите для ключа ~/.ssh/id_rsa-TEST
использовать агент, то можно сделать так:
$ /usr/bin/ssh-add ~/.ssh/id_rsa-TEST
Сначала ssh спросит парольную фразу для ключа, после чего появится диалог, где нужно выбрать пароль для шифрования ключа в агенте, обычно это простая короткая фраза (НЕ пароль к оригинальному ключу!):
Этот пароль (а не оригинальную парольную фразу!) нужно будет ввести, когда сторонняя программа затребует ключ:
Идентификатор добавленного ключа сохраняется в файле ~/.gnupg/sshcontrol
в виде блока такого формата:
# RSA key added on: 2017-12-13 14:07:27
# Fingerprints: MD5:0c:01:91:7c:49:40:f8:7c:74:64:74:bd:7e:c8:7a:e9
# SHA256:hnOuTZzfe2ak10Jd6bl60kE9yAUqw34KinJ3H4opNbs
3BC01B6F0043256039006294F76C45139B703DBF 0
~/.gnupg/sshcontrol
— это текстовый файл. Строки с # в начале считаются комментариями (то есть игнорируются системой). Все остальные строки должны иметь такой формат:
┌─────────────────────────── идентификатор ключа
│ ┌── TTL кеширования в секундах
────────────────┴─────────────────────── ┴
3BC01B6F0043256039006294F76C45139B703DBF 0
TTL кеширование — это время в секундах после ввода пароля, в течение которого запрос ключа не потребует пароля снова. Если указать 0, будет использоваться TTL по умолчанию.
Это значение по умолчанию формируется следующим образом:
- если в
~/.gnupg/gpg-agent.conf
указан аргументmax-cache-ttl-ssh
, то значение будет сверху ограничено указанным. Если аргумент не указан, то TTL будет ограничен двумя часами независимо от значенияdefault-cache-ttl-ssh
или TTL, указанного вsshcontrol
;- если в
~/.gnupg/gpg-agent.conf
указан аргументdefault-cache-ttl-ssh
, то оно будет использовано. Если аргумента нет, то по умолчанию будет 30 минут.И здесь важно отметить, что если вы в файле
sshcontrol
укажете TTL ключа выше максимального, то всё равно будет использовано максимальное значение. Поэтому для срока жизни больше двух часов обязательно нужно указать аргументmax-cache-ttl-ssh
в файле~/.gnupg/gpg-agent.conf
с бо́льшим значением.
Перед идентификатором можно указать восклицательный знак (!) такой ключ будет выключен, это по сути то же самое, что и комментирование этой строчки через #.
Также можно для ключа указать набор флагов (третьим полем после TTL, оно опциональное):
┌───────────────────────────── идентификатор ключа
│ ┌──── TTL кеширования в секундах (0 — не кешировать)
│ │ ┌── флаги (пока только confirm)
────────────────┴─────────────────────── ┴ ┴──────
3BC01B6F0043256039006294F76C45139B703DBF 0 confirm
На данный момент поддерживается только один флаг — confirm
, если он выставлен, то перед каждым обращением к ключу (даже если оно в пределах действующего TTL) будет показываться дополнительный диалог с подтверждением:
Базовые сценарии и операции¶
Я очень советую не использовать автоматическое добавление ключей в агент. Для
/usr/bin/ssh
и других программ, использующих/usr/bin/ssh
(это git, например), рекомендую посмотреть файлы/etc/ssh/ssh_config
и~/.ssh/config
удалить оттуда упоминания параметра AddKeysToAgent. Дальше все нужные ключи добавлять только вручную.
Программа ssh-add
из комплекта openssh-client
обращается к текущему агенту по стандартному протоколу, поэтому её можно использовать вместе с gpg-agent
. Так что примеры ниже могут пригодиться и для ssh-agent тоже.
Также помните, что в некоторых системах менеджер паролей может запомнить пароль для расшифровки ключа, поэтому я настоятельно советую эту фичу отключить, не ставить галочку «Запомнить пароль», ну или как минимум самые критичные ключи добавлять только с флагом confirm, чтобы вы явно разрешали каждое использование ключа.
Как остановить/запустить/перезапустить агент¶
gpg-agent работает как демон, поэтому для его запуска или остановки нужно использовать специальные команды. Это демон текущей десктопной сессии, а не системы в целом.
Вообще,
Для линукса:
# остановить
gpgconf --kill gpg-agent
# запустить
/usr/bin/gpg-agent --daemon
# перезапустить
gpgconf --kill gpg-agent
/usr/bin/gpg-agent --daemon
Для макоси (подразумевается, что агент настроен по этому руководству):
# остановить
$ launchctl unload ~/Library/LaunchAgents/gpg-agent.daemon.plist
# запустить
$ launchctl load ~/Library/LaunchAgents/gpg-agent.daemon.plist
# перезапустить
$ launchctl unload ~/Library/LaunchAgents/gpg-agent.daemon.plist
$ launchctl load ~/Library/LaunchAgents/gpg-agent.daemon.plist
Если вы обновили GPG Suite, то нужно будет запустить агент снова, так как в процессе апгрейда, процесс агента прибивается.
Просмотр списка ключей в агенте¶
Эта команда показывает список отпечатков ключей:
$ ssh-add -l
2048 SHA256:hnOuTZzfe2ak10Jd6bl60kE9yAUqw34KinJ3H4opNbs /home/sigsergv/.ssh/id_rsa-TEST (RSA)
2048 SHA256:OV0fErCIpclIvjl8hCaFmdgfJmGYmdYNOhUus1i7GUg /home/sigsergv/.ssh/id_rsa-cc (RSA)
Чтобы показать публичные ключи, используйте такую команду:
$ ssh-add -L
ssh-rsa AAAAB3NzaC1yc2E...a+oGmV /home/sigsergv/.ssh/id_rsa-TEST
ssh-rsa AAAAB3NzaC...x8t05UA8N /home/sigsergv/.ssh/id_rsa-cc
В конце каждой строчки показывает имя файла, которое было указано при добавлении ключа в команде ssh-add.
Для просмотра можно также пользоваться командой gpg-агента:
$ gpg-connect-agent 'KEYINFO --ssh-list' /bye
S KEYINFO 63ABF6149911C8987A1E849851E80BDFA727FE0F D - - 1 P - 600 Sc
S KEYINFO 75EDE7E2FAE5BD4336DB38328B23D71E8143855D D - - - P - 3600 Sc
OK
Добавление ключа в агент¶
$ ssh-add ~/.ssh/id_rsa-TEST
Enter passphrase for /home/sigsergv/.ssh/id_rsa-TEST:
Identity added: /home/sigsergv/.ssh/id_rsa-TEST (/home/sigsergv/.ssh/id_rsa-TEST)
Добавление ключа с TTL=60 секунд¶
$ ssh-add -t 60 ~/.ssh/id_rsa-TEST
Enter passphrase for /home/sigsergv/.ssh/id_rsa-TEST:
Identity added: /home/sigsergv/.ssh/id_rsa-TEST (/home/sigsergv/.ssh/id_rsa-TEST)
Lifetime set to 60 seconds
Данный вызов не модифицирует существующий ключ в ~/.gnupg/sshcontrol
! Для изменения параметров смотрите раздел Модификация параметров ключа в агенте.
GPG Suite игнорирует этот параметр.
Добавление ключа с включенным подтверждением¶
$ ssh-add -c ~/.ssh/id_rsa-TEST
Enter passphrase for /home/sigsergv/.ssh/id_rsa-TEST (will confirm each use):
Identity added: /home/sigsergv/.ssh/id_rsa-TEST (/home/sigsergv/.ssh/id_rsa-TEST)
The user must confirm each use of the key
Данный вызов не модифицирует существующий ключ в ~/.gnupg/sshcontrol
! Для изменения параметров смотрите раздел Модификация параметров ключа в агенте.
Удаление ключа из агента¶
В ssh-add есть параметр -d, однако для gpg-agent он не сработает, то есть вы можете выполнить команду, но она ничего не сделает. Для полного удаления нужно пользоваться командами агента. К сожалению, нормальной процедуры или GUI для этого нет и нужно пользоваться несколькими консольными командами.
Сначала посмотрим список хранимых ключей:
$ ssh-add -l
2048 SHA256:hnOuTZzfe2ak10Jd6bl60kE9yAUqw34KinJ3H4opNbs /Users/sigsergv/.ssh/id_rsa-TEST (RSA)
2048 SHA256:MApXMQ8qUqBd4yfbA07RSh+VLT+ARsg5k8fbY72LVCc /Users/sigsergv/.ssh/id_rsa-XYZ (RSA)
2048 SHA256:8X/7LtWAFl962369KYW9ADgNCiPDUE7ilwI9QWXrBxk /Users/sigsergv/.ssh/id_rsa-SECURE (RSA)
Хотим удалить первый, для него ssh-add показывает SHA256 равный hnOuTZzfe2ak10Jd6bl60kE9yAUqw34KinJ3H4opNbs, открываем файл ~/.gnupg/sshcontrol
и находим его там:
# RSA key added on: 2017-12-23 21:04:21
# Fingerprints: MD5:0c:01:91:7c:49:40:f8:7c:74:64:74:bd:7e:c8:7a:e9
# SHA256:hnOuTZzfe2ak10Jd6bl60kE9yAUqw34KinJ3H4opNbs
3BC01B6F0043256039006294F76C45139B703DBF 600 confirm
Агент использует keygrip ключа для его идентификации, это тоже хеш-сумма, но другая. Для нашего ключа keygrip — это 3BC01B6F0043256039006294F76C45139B703DBF. Именно эту строку будем использовать для удаления (команда может несколько раз запросить подтверждение действия):
$ gpg-connect-agent 'DELETE_KEY 3BC01B6F0043256039006294F76C45139B703DBF' /bye
OK
Убедимся, что всё получилось:
$ ssh-add -l
2048 SHA256:MApXMQ8qUqBd4yfbA07RSh+VLT+ARsg5k8fbY72LVCc /Users/sigsergv/.ssh/id_rsa-TEST2 (RSA)
2048 SHA256:8X/7LtWAFl962369KYW9ADgNCiPDUE7ilwI9QWXrBxk /Users/sigsergv/.ssh/id_rsa-INSECURE (RSA)
Ключа в списке нет, всё нормально. И дальше вручную удалите упоминания ключа из ~/.gnupg/sshcontrol
.
Очистить закешированные пароли¶
Чтобы очистить закешированные пароли к ключам, можно перезагрузить агент такой командой:
$ gpg-connect-agent reloadagent /bye
Модификация параметров ключа в агенте¶
Откройте файл ~/.gnupg/sshcontrol
в любом текстовом редакторе и поправьте что нужно, описание формата я давал выше. Вы можете изменить TTL, включить/выключить подтверждение, удалить ключ.
gpg-agent монитори изменения в этом файле и они применяются сразу после сохранения.
Модификация TTL по умолчанию¶
Откройте файл ~/.gnupg/gpg-agent.conf
и поменяйте (или задайте, если его там нет) значение параметра default-cache-ttl-ssh
(в секундах).
Обратите внимание, что значение TTL в любом случае не может быть выше значения параметра max-cache-ttl-ssh
, по умолчанию это 7200 секунд (два часа). Если вы хотите, чтобы TTL был больше этого значения, нужно добавить этот параметр в файл ~/.gnupg/gpg-agent.conf
с нужным значением.
Работа агента ломается после второй одновременной сессии этого же пользователя¶
Если запустить вторую сессию с этим же пользователем (например, через RDP), то старая отваливается. Починить можно так:
$ pkill -f gpg-agent
$ gpg-connect-agent /bye
$ pkill -f gpg-agent
$ rm -rf $(dirname $SSH_AUTH_SOCK)/*
История изменений¶
- 2017-12-13 — оригинальная статья
- 2021-05-01 — новый и более эффективный способ замены штатного ssh-agent на gpg-agent в макоси
- 2024-06-10 — исправление ошибок и добавление информации о новых настройках
- 2024-09-20 — добавлены уточнения об особенностях работы GPG Suite (он не использует время кеширования ключа из sshcontrol)