ssh-agent
SSH-agent является частью OpenSSH. По своей сути, это менеджер ключей для SSH. Ssh-agent хранит ключи и сертификаты в памяти, незашифрованные и готовые к использованию ssh. Это избавляет от необходимости вводить пароль каждый раз, когда происходит подключение к серверу. Агент работает в фоновом режиме, отдельно от ssh, и обычно запускается при первом запуске ssh.
Агент SSH хранит секретные ключи в безопасности, а именно:
- не записывает никакой информации о ключах на диск;
- не позволяет экспортировать ключи.
Секретные ключи, хранящиеся в Агенте, могут использоваться только для одной цели: подписания сообщения.
Как оно работает
Пара SSH ключей, используется только для аутентификации во время первоначального соединения. Например, вот так, проверяется ключ пользователя во время SSH-соединения, с точки зрения сервера:
- Клиент предоставляет серверу публичный ключ.
- Сервер генерирует и отправляет короткое случайное сообщение, прося клиента подписать его с помощью приватного ключа.
- Клиент просит агента SSH подписать сообщение и пересылает результат обратно на сервер.
- Сервер проверяет подпись, используя публичный ключ клиента.
- Теперь у сервера есть доказательство того, что клиент владеет приватным ключом.
Позже в процессе соединения генерируется набор новых, эфемерных и симметричных ключей, которые используются для шифрования трафика сеанса SSH. Эти ключи могут даже не длиться весь сеанс; событие rekey
происходит через регулярные промежутки времени.
Протокол агента
SSH использует сокет домена Unix для общения с агентом по протоколу SSH agent.
Протокол агента может выполнять несколько основных операций:
- Добавить обычную пару ключей (публичный и расшифрованный приватный ключи)
- Добавить ограниченную пару ключей (публичный и расшифрованный приватный ключи)
- Добавить ключ (обычный или ограниченный) из смарт-карты (только публичный ключ)
- Удалить ключ
- Вывод списка ключей, хранящихся в агенте
- Подпись сообщения ключом, хранящимся в агенте
- Блокировка или разблокировка всего агента с помощью пароля
Что такое ограниченный ключ? Обычно это ключ, который либо имеет ограниченный срок службы, либо требует явного подтверждения пользователя при его использовании.
Команда ssh-add
это шлюз к агенту SSH. ssh-add
выполняет все эти операции, кроме подписи. Когда запускается ssh-add без каких-либо параметров, он будет сканировать домашний каталог на наличие некоторых стандартных ключей и добавлять их в ваш агент. По умолчанию ищет в:
~/.ssh/id_rsa
~/.ssh/id_ed25519
~/.ssh/id_dsa
~/.ssh/id_ecdsa
Example
Рассмотрим базовые примеры использования ssh-agent.
Создание ключа
ssh-keygen -t rsa -b 2048 -f /home/username/.ssh/test-key -C "Testing key" -P P@$$w0rd Generating public/private rsa key pair. Your identification has been saved in /home/username/.ssh/test-key Your public key has been saved in /home/username/.ssh/test-key.pub The key fingerprint is: SHA256:0LIvmlovgP120mV1GsmNgp0woBXI2y89fgPtdVvxyyc Testing key The key's randomart image is: +---[RSA 2048]----+ | . .+o | | oo o. | | .o o=.o + | | . . .++ * o . | | o o..So + o | |. o . =.+ o . . .| | o.+.*.. . o. .| | .=++.+ . Eo.| | .oo+.. . ..| +----[SHA256]-----+
Описание опций:
-t
– тип RSA-b
– длина ключа в битах (по-умолчанию 3072 для RSA)-f
– путь к файлу ключа (по-умолчанию будет~/.ssh/id_rsa
)-C
– комментарий к ключу (по-умолчанию будет username@hostname)-P
– пароль для доступа к ключу
Проверка пароля
Что бы проверить пароль ключа – используем -f
для указания ключа, и -y
для вывода информации о ключе, поэтому запросит пароль:
ssh-keygen -y -f /username/setevoy/.ssh/test-key Enter passphrase: ssh-rsa AAAAB***gud2vedL/V Testing key
Смена пароля
Если известен старый пароль, его можно изменить:
ssh-keygen -p -f ~/.ssh/test-key Enter old passphrase: Key has comment 'Testing key' Enter new passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved with the new passphrase.
Копирование ключа на сервер
Скопировать ключ можно вручную, получив его публичную часть:
cat .ssh/test-key.pub ssh-rsa AAAAB***gud2vedL/V Testing key
И скопировав содержимое в файл ~/.ssh/authorized_keys
на удалённом хосте.
Другой вариант – используя утилиту ssh-copy-id
, которая, по сути, выполнит всё то же самое, но при этом ещё и проверит права доступа на каталоги и файлы (самая частая проблема при использовании SSH-ключей для аутентификации):
ssh-copy-id -i ~/.ssh/test-key.pub target@host /usr/bin/ssh-copy-id: INFO: Source of key(s) to be installed: "/home/username/.ssh/test-key.pub" /usr/bin/ssh-copy-id: INFO: attempting to log in with the new key(s), to filter out any that are already installed /usr/bin/ssh-copy-id: INFO: 1 key(s) remain to be installed -- if you are prompted now it is to install the new keys target@host's password: Number of key(s) added: 1
И пробуем подключиться, используя этот ключ:
ssh target@host -i ~/.ssh/test-key
ssh-add
Теперь у нас ключ для аутентификации на сервере, и ключ закрыт паролем.
При каждом обращении к серверу –- придётся вводить пароль заново – Enter passphrase for key '/home/username/.ssh/test-key':
. Что бы избежать этого – добавим ключ в ssh-agent, используя ssh-add
. Но для начала, проверим, что агент запущен:
ps aux | grep ssh-agent username 1186 0.0 0.0 7968 1080 ? Ss May05 0:00 /usr/bin/ssh-agent -s
Самая частая ошибка при использовании агента – когда к нему невозможно подключиться, и ssh-add сообщает:
ssh-add
Could not open a connection to your authentication agent.
Первым делом проверяем SSH_AGENT_PID
(или $SSH_AUTH_SOCK
, т.к. запросы от ssh-add
выполняются через сокет, заданный в этой переменной):
test -z $SSH_AGENT_PID; echo $? 0
Переменная пустая. Для чистоты эксперимента – убиваем запущенные демоны агента:
sudo killall ssh-agent
И запускаем заново:
eval $(ssh-agent -s) Agent pid 15317
-s
используем для создания переменных, т.к. не все будут запускать из bash, а eval
– что бы сразу выполнить экспорт переменных (export SSH_AUTH_SOCK
) из output самого ssh-agent.
Проверяем ещё раз:
test -z $SSH_AGENT_PID; echo $? 1
И ssh-add
:
ssh-add -l The agent has no identities.
Тут всё готово.
Добавление ключа
ssh-add /home/username/.ssh/test-key Enter passphrase for /home/username/.ssh/test-key: Identity added: /home/username/.ssh/test-key (Testing key)
Проверка ключей в агенте
Для проверки загруженных в агент ключей, используется опция -l
:
ssh-add -l 2048 SHA256:0LIvmlovgP120mV1GsmNgp0woBXI2y89fgPtdVvxyyc Testing key (RSA)
Или -D
для удаления всех ключей:
ssh-add -D All identities removed.
Автоматическое добавление в ssh-agent
Что бы ssh (и git, например) всегда добавляли ключ в ssh-agent без явного ручного вызова ssh-add
– добавим AddKeysToAgent
в ~/.ssh/config
, указав yes, confirm или ask (подробнее SSH_ASKPASS):
head -1 ~/.ssh/config AddKeysToAgent yes
Проверяем – сейчас ключей в агенте нет:
ssh-add -l The agent has no identities.
Выполняем подключение, вводим пароль ключа:
ssh -i .ssh/test-key target@host
Отключаемся, проверяем ключи в агенте:
logout Connection to host closed. ssh-add -l 2048 SHA256:0LIvmlovgP120mV1GsmNgp0woBXI2y89fgPtdVvxyyc Testing key (RSA)
Далее, при повторном подключении – ключ уже будет взят из агента, и пароль вводить не потребуется.
Запуск ssh-agent и несколько консолей
Одна из основных проблем, это то, что при запуске новой bash-сесии – там не будет переменной $SSH_AUTH_SOCK
, и ssh-клиент не сможет получить доступ к ключу. Например, при вызове ssh-add в новом терминале получим уже упомянутую ошибку Could not open a connection to your authentication agent
:
ssh-add -l Could not open a connection to your authentication agent.
Вариантов много, например самый простой – добавить в ~/.bashrc:
if [ -z "$SSH_AUTH_SOCK" ] ; then eval `ssh-agent -s` ssh-add /home/username/.ssh/test-key fi
Но тогда для каждой сессии bash будет запускаться новый агент (а также, при старте сессии будет запрашиваться парольная фраза для test-key
), что не очень удобно.
Ещё один вариант – создать systemd unit-файл и запускать ssh-agent как сервис.
Создаем структуру для пользовательского юнита
mkdir -p ~/.config/systemd/user/ssh-agent.service
Далеe, создадим файл .config/systemd/user/ssh-agent.service
со следующим содержимым^
[Unit] Description=SSH key agent [Service] Type=simple Environment=SSH_AUTH_SOCK=%t/ssh-agent.socket ExecStart=/usr/bin/ssh-agent -D -a $SSH_AUTH_SOCK [Install] WantedBy=default.target
В .bashrc
добавим переменную:
export SSH_AUTH_SOCK="${XDG_RUNTIME_DIR}/ssh-agent.socket" # Проверяем echo $SSH_AUTH_SOCK
Добавляем юнит в автозагрузку и промеряем
systemctl --user enable ssh-agent systemctl --user start ssh-agent systemctl --user status ssh-agent # Либо systemctl --user enable --now ssh-agent
Проверяем
ssh-add -l The agent has no identities.
Все ок. Теперь добавляем ключи
ssh-add .ssh/test-key