EnglishРусский Map

Риски проброса SSH-агента

title
Риски проброса SSH-агента
type
concept
summary
Почему ssh -A (и ForwardAgent) дают целевому хосту возможность аутентифицироваться от вашего имени везде, куда есть доступ у загруженных ключей
tags
ssh, security, lateral-movement
created
2026-05-21
updated
2026-05-21
lang
ru
source_updated
2026-05-21
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

ssh-agent - это локальный демон, который хранит расшифрованные закрытые ключи после ssh-add. SSH-клиент обращается к нему через доменный сокет Unix ($SSH_AUTH_SOCK) для подписи проверочных запросов при аутентификации. Проброс агента (флаг -A или ForwardAgent yes в ~/.ssh/config) транслирует этот сокет на SSH-сервер: теперь удалённый хост может запрашивать у локального агента подпись проверок от своего имени.

Это удобно - цепочка ssh user@hop, а затем ssh user@next работает без копирования закрытых ключей по промежуточным узлам - и опасно: root на целевом хосте (или любой, у кого есть доступ к файлу проброшенного сокета) может использовать агент для аутентификации на любом ресурсе, куда дают доступ загруженные ключи оператора. Сами закрытые ключи злоумышленник не видит, но ему это и не требуется: достаточно по требованию просить агент поставить подпись.

Схема атаки

  1. Оператор выполняет ssh -A user@target, имея id_rsa_prod, загруженный в агент.
  2. Атакующий с правами root на target перебирает сокеты /tmp/ssh-*/agent.* и находит сокет оператора.
  3. Задаёт SSH_AUTH_SOCK на этот путь и выполняет ssh-add -l, чтобы увидеть список загруженных ключей.
  4. Выбирает хост назначения (ssh-add -l показывает комментарии к ключам, где часто указаны имена хостов) и выполняет ssh prod-bastion.corp - агент подписывает запрос, аутентификация проходит успешно.

Оператор этого не видит. Проброшенный сокет живёт ровно столько, сколько длится SSH-сессия, но этого времени более чем достаточно. У Хелтона есть подробный разбор в Zero Effort Private Key Compromise, для этой вики ещё не изученный.

Почему операторы всё равно это делают

Без -A работа через цепочку хостов вынуждает копировать ключи на каждый промежуточный узел. Это ещё хуже: постоянные файлы ключей оседают на машинах, которые оператор не контролирует. Проброс агента оказывается меньшим из двух зол, если альтернатива - разбрасывать ключи.

Более безопасные альтернативы

  • -J / ProxyJump - для типичного сценария "мне нужно попасть на внутренний хост, а не работать на промежуточном". Прокладывает маршрут через промежуточный узел, вообще не раскрывая на нём ключи. Аутентификация на каждом участке по-прежнему происходит на стороне клиента, но сокет агента остаётся локальным. Именно для этого чаще всего ошибочно используют -A.
  • Отдельные пары ключей под каждый хост - ломают предположение, что "один ключ открывает всё". Скомпрометированный агент даёт доступ только к тем ключам, которые загружены прямо сейчас.
  • Запрос подтверждения (ssh-add -c) - заставляет агент запрашивать подтверждение перед каждой операцией подписи. Неудобно, но исключает скрытое неконтролируемое использование.
  • Ключи с ограниченным сроком действия (ssh-add -t <seconds>) - ключи автоматически выгружаются из агента по истечении времени; в сочетании с -c дают эшелонированную защиту.
  • ephemeral-credentials - короткоживущие SSH-сертификаты от CA (Vault, smallstep, EC2 Instance Connect) полностью снимают проблему долгоживущих ключей.

Обнаружение

Директива Match в ~/.ssh/config позволяет ограничить ForwardAgent yes только теми конкретными хостами, где границы доверия действительно проверены оператором, оставляя значение по умолчанию no для всех остальных. Смена поведения по умолчанию - включение по явному разрешению (opt-in вместо opt-out) - самый дешёвый способ снизить риски.

См. также

  • ssh-port-forwarding - ортогональные режимы -L/-R/-D/-J, которые работают с трафиком, а не с учётными данными
  • ssh-port-forwarding-cheatsheet - шпаргалка Хелтона для red team, где описан этот риск
  • ephemeral-credentials - структурное решение проблемы долгоживущих SSH-ключей
  • long-lived-keys - аргументация Людвига о том, почему ротация ключей не решает проблему
  • credential-compartmentalization - тот же принцип применительно к разным типам учётных данных