ssh-agent — это фоновая программа, которая держит ваши разблокированные приватные ключи в памяти и подписывает ими запросы аутентификации, так что парольную фразу ключа вы вводите один раз за сессию, а не один раз на подключение. ssh-add — это команда, которая загружает в него ключи.
Вы поступили правильно и поставили на SSH-ключ парольную фразу — и теперь набираете её в пятый раз до обеда. Решение существует десятилетиями: SSH-агент. Разблокируйте ключ один раз, и каждое последующее подключение аутентифицируется молча. Нюанс в том, что это «один раз» работает, только если агент действительно запущен, ваша оболочка может его найти, а ключ загружен — три отдельные вещи, и у каждой свой способ подвести. Это практический гайд: запуск агента в каждой ОС, управление им через ssh-add, автоматизация всего этого и разбор двух ошибок, на которые приходится почти вся возня с агентом.
Что такое агент, в один абзац
ssh-agent — это небольшой фоновый процесс, который держит ваши расшифрованные приватные ключи в памяти — и никогда на диске. Когда сервер бросает вам вызов, ssh передаёт этот вызов агенту, агент подписывает его ключом из памяти, и обратно уходит только подпись — сам ключ никогда не покидает агент, никогда не попадает в сеть и остаётся зашифрованным на диске. Один запрос парольной фразы, чтобы загрузить ключ, и дальше каждое подключение обслуживается из памяти. Вот и вся модель в голове: агент — это служба подписи, а не хранилище ключей, из которого кто-то читает; он охраняет секрет и всегда выдаёт только подписи. (Это же свойство — и подвох с точки зрения безопасности, которому в конце посвящён отдельный раздел.)
На Windows? Сначала прочитайте руководство для Windows
Если вы попали сюда из-за error connecting to agent: No such file or directory, это сообщение специфично для Windows: оно приходит от ssh из Git Bash / MSYS2, и исправления тоже оттуда — служба OpenSSH Authentication Agent, собственный агент Git Bash и ошибка 1058. Все они разобраны в статье ssh-agent в Windows. Всё, что ниже, — это кроссплатформенный рабочий процесс ssh-agent и ssh-add, и ошибки, которые он расшифровывает, — родные для клиента OpenSSH: Could not open a connection to your authentication agent и The agent has no identities.
Запуск агента по ОС
Linux — eval "$(ssh-agent -s)"
На десктопе при входе в систему агент у вас почти наверняка уже есть — либо systemd-служба пользователя, либо GNOME Keyring в этой роли — с SSH_AUTH_SOCK, экспортированным на всю сессию. Проверьте через ssh-add -l. Если никто не отвечает (обычное дело при голом входе по SSH, в контейнерах или на минимальных серверах), запустите его вручную:
eval "$(ssh-agent -s)"
eval здесь важен. ssh-agent -s только печатает переменные SSH_AUTH_SOCK и SSH_AGENT_PID; именно eval устанавливает их в вашей текущей оболочке, чтобы ssh нашёл сокет. Запустить ssh-agent без обёртки и недоумевать, почему ничего не изменилось, — самый частый способ «запустить» агент, которого не видит ни один инструмент.
macOS — launchd запускает его за вас
launchd поднимает агент за вас при входе — запускать нечего. Специфичный для macOS выигрыш — интеграция с Keychain, о ней ниже.
Запуск ssh-agent в Windows
Современные Windows поставляются со службой OpenSSH Authentication Agent, но она настроена на ручной запуск и по умолчанию не работает. Включите её один раз из PowerShell с правами администратора:
Set-Service ssh-agent -StartupType Automatic
Start-Service ssh-agent
После этого ssh-add работает в любом терминале — PowerShell, cmd или клиенте Windows OpenSSH под Git Bash — и агент переживает перезагрузки. Одна ловушка: Git for Windows приносит свои ssh и ssh-agent, и внутри Git Bash тот ssh, что у вас в PATH, может оказаться именно им, разговаривающим с отдельным агентом. Если ssh-add -l расходится между Git Bash и PowerShell, направьте Git на системный клиент, чтобы оба делили один агент:
git config --global core.sshCommand "C:/Windows/System32/OpenSSH/ssh.exe"
Полное руководство — служба, Git Bash и загрузка ключей при входе — в статье ssh-agent в Windows.
Управление через ssh-add
Загрузить ключ: ssh-add ~/.ssh/id_ed25519
ssh-add # load the default keys (id_ed25519, id_rsa, …)
ssh-add ~/.ssh/id_ed25519 # load a specific key (prompts for the passphrase once)
Без пути ssh-add загружает ключи с именами по умолчанию из ~/.ssh; укажите путь, чтобы загрузить конкретный ключ. В любом случае он один раз спросит парольную фразу и затем держит расшифрованный ключ в памяти.
Посмотреть, что загружено: ssh-add -l
ssh-add -l # list fingerprints of loaded keys
ssh-add -L # print the full public keys
ssh-add -d ~/.ssh/id_ed25519 # remove one key
ssh-add -D # remove all keys
ssh-add -l — первая диагностика при любой проблеме со входом: если нужного ключа нет в этом списке, агент не сможет им подписать, как бы правильно ни выглядело всё остальное.
Задать таймаут ssh-agent: ssh-add -t
Два флага стоит превратить в привычку:
-tзадаёт время жизни.ssh-add -t 3600 ~/.ssh/id_ed25519загружает ключ на один час; после этого агент его забывает, и следующее использование снова запросит фразу. Ключ, который лежит разблокированным в памяти трёхнедельного аптайма, — это ключ, годный к использованию ещё долго после того, как вы о нём перестали думать.-cтребует подтверждения. Каждый запрос на подпись вызывает локальное окно, прежде чем агент ответит. Слегка раздражает, ровно то, что нужно для ценных ключей.
Сделайте это автоматическим: AddKeysToAgent
Ручной ритуал ssh-add исчезает с одной строкой в ~/.ssh/config (на английском):
Host *
AddKeysToAgent yes
Теперь первый ssh, которому нужен ключ, один раз спросит парольную фразу и попутно загрузит ключ в агент. Отдельной команды помнить не нужно — запрос просто перестаёт повторяться. Можно задать и время жизни (AddKeysToAgent 1h), чтобы получить поведение -t без флага.
macOS: пережить перезагрузки через Keychain. По умолчанию агент забывает ключи при перезапуске. macOS может хранить парольную фразу в вашем login keychain, чтобы ключи перезагружались без повторного ввода:
ssh-add --apple-use-keychain ~/.ssh/id_ed25519
и в ~/.ssh/config:
Host *
AddKeysToAgent yes
UseKeychain yes
После этого вопрос о парольной фразе при входе отвечает Keychain, и вы больше его не видите — при этом файл ключа на диске остаётся зашифрованным.
Две ошибки, на которые натыкаются все
Could not open a connection to your authentication agent — ssh-add не может найти агент. Либо ни один не запущен, либо запущен, но у этой оболочки не выставлен SSH_AUTH_SOCK. Решение — запуск по ОС выше: строка eval "$(ssh-agent -s)" на Linux (сначала проверьте, не предоставляет ли агент уже ваша десктоп-сессия — запуск второго агента на каждый терминал лишь разбрасывает загруженные ключи по процессам), запуск службы на Windows. Вы также встретите это в cron-задачах и CI, где ни одна сессия входа не экспортировала переменную.
The agent has no identities. — обратная проблема: агент в порядке, но ничего не загружено. ssh-add вашего ключа. Если он был загружен и пропал — истекло время жизни -t или агент перезапустился, а это ровно то, для чего существуют AddKeysToAgent yes и Keychain на macOS.
И третий случай: агент выглядит безупречно — ssh-add -l показывает ключ, — но сервер всё равно отвечает Permission denied (publickey). Это уже не проблема агента; пройдитесь по чек-листу publickey — не тот пользователь, не тот предлагаемый ключ, права на authorized_keys.
Разблокированный агент — это живой доступ
Агент никогда не отдаёт ключ — но его сокет это оракул подписи: он подписывает для всякого, кто до него достаёт, и не спрашивает, кто просит. На вашей собственной машине это нормально — сокет лежит в приватном каталоге вашего пользователя, который можете читать только вы. Опасность в форме «запутанного заместителя» (confused deputy): когда сокет становится доступен тому, кому вы этого не предполагали — проброшенному агенту на общем бастионе или недоверенному процессу, запущенному от вашего пользователя, — такое нечто может аутентифицироваться как вы на каждом сервере, до которого достают ваши ключи, ни разу не увидев самого ключа. То, что ключ не утекает, — лишь половина гарантии; контроль над тем, кто может его использовать, — вторая половина, и именно поэтому гигиена агента стоит небольших усилий.
- Задавайте ключам время жизни (
-tили время жизни уAddKeysToAgent), чтобы простаивающий агент сам остывал. - Блокируйте агент, отходя от машины:
ssh-add -xзапирает его паролем,ssh-add -Xотпирает;ssh-add -Dпросто сбрасывает всё. - Используйте
-cдля ключей, которые достают до продакшена. - Не пробрасывайте агент по умолчанию.
ssh -A— проброс SSH-агента (ssh agent forwarding) — открывает живое использование ваших ключей на удалённом хосте, так что любой, у кого там есть root, может подписывать от вашего имени на всю длину вашей сессии. Этот пункт заслуживает отдельного чтения: проброс агента удобен и опасен (на английском).
Как это делает Termalin
Termalin встраивает весь этот рабочий процесс целиком, со сточенными острыми краями. Его ключ-агент разблокирует ваши ключи один раз и подписывает от вашего имени — без службы ОС, которую надо включать, без строки eval, без сокета на каждую оболочку, который можно потерять. Кэширование парольной фразы идёт с таймаутом повторной блокировки по умолчанию — это привычка ssh-add -t, которую за вас соблюдают, а не которую вы помните. А поскольку он говорит на стандартном протоколе ssh-agent, git и ваши уже имеющиеся инструменты командной строки подписывают через него без изменений — он заменяет ритуал, а не ваш набор инструментов.
Termalin — бесплатный кроссплатформенный SSH-клиент, встроенный агент которого разблокирует ваши ключи один раз и перезапирает их по таймеру — скачайте его или прочитайте, как он безопасно обращается с ключами.