ssh-agent

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

Рассмотрим базовые примеры использования 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

Теперь у нас ключ для аутентификации на сервере, и ключ закрыт паролем.

При каждом обращении к серверу –- придётся вводить пароль заново – 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 (и 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)

Далее, при повторном подключении – ключ уже будет взят из агента, и пароль вводить не потребуется.

Одна из основных проблем, это то, что при запуске новой 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
  • ssh-agent.txt
  • Последнее изменение: 2022/05/12 16:27
  • admin