Назад в блог

Агентные атаки на облако: что JADEPUFFER показал о сервисных учётках

Агентный атакующий удалил 100+ хранилищ Azure за семь минут через утёкший service principal. Разбираем атаку Storm-3168 и защиту машинных учёток от атакующего на машинной скорости.

Иллюстрация к материалу: Агентные атаки на облако: что JADEPUFFER показал о сервисных учётках

25 сентября 2026 года Microsoft опубликовала разбор атак группировки Storm-3168 — той же, что Sysdig ранее описал под именем JADEPUFFER и назвал первой задокументированной агентной вымогательской операцией. Цифры из отчёта стоит прочитать дважды. Сначала — пятнадцать с половиной часов тихой разведки и более трёхсот успешных операций чтения через скомпрометированный service principal. Затем, через 70 секунд после последнего запроса инвентаризации, — разрушительная фаза: больше ста попыток удалить учётные записи хранилищ за семь минут, удалённые Key Vault, Function App и план App Service. Уцелело только то, что было закрыто блокировками ресурсов, настроенными заранее.

Учётные данные одного из двух service principal’ов сотрудник пострадавшей организации раньше выложил в публичный issue на GitHub. Issue потом отредактировали, но секрет остался в истории правок.

В этой атаке нет ничего технически нового: утёкший секрет, избыточные права, отсутствие защиты от удаления. Новое — скорость и терпение. Агентный атакующий не устаёт за пятнадцать часов разведки и не медлит, когда переходит к удалению. Разберём, что именно произошло, почему привычные меры реагирования рассчитаны на другую скорость и какие контроли работают против атакующего, который действует как автоматизированная система.

Что произошло: хронология Storm-3168

Хронология по отчёту Microsoft:

  1. Начальный доступ. Client ID, client secret и tenant ID первого service principal’а были опубликованы открытым текстом в публичном issue на GitHub. Редактирование issue не помогло: секрет оставался доступен в публичной истории правок. Microsoft не смогла точно установить способ начального доступа, но называет утечку через репозиторий вероятным источником. Параллельно инфраструктура группировки сканировала Azure App Service по известным чувствительным путям — админкам WordPress, PHP-CGI, endpoint’у проверки кода LangFlow.
  2. Разведка. В начале июня первый service principal 15,5 часа перечислял ресурсы: подписки, группы ресурсов, хранилища, веб-приложения, блокировки, службы восстановления. Больше трёхсот успешных операций чтения.
  3. Вторая учётка. Через 90 минут второй service principal за пять секунд перечислил виртуальные машины и группы ресурсов в двух подписках. Позже он пытался прочитать хранилища конфигурации App Service.
  4. Разрушение. Через 70 секунд после последней операции инвентаризации началось удаление. За семь минут — больше ста попыток удалить учётные записи хранилищ, большинство успешных. Удалены один Key Vault, одна Function App и один план App Service. Были попытки удалить базы Azure SQL и блокировки Site Recovery и Azure Backup.
  5. Сбор ключей. Примерно через полчаса после разрушительной фазы — более 150 попыток вызвать ListKeys для учётных записей хранилищ, из них больше тридцати успешных.

Что уцелело: учётные записи хранилищ, защищённые блокировками ресурсов Azure и защитой от удаления на уровне хранилища; базы SQL (запросы на удаление не прошли из-за неподдерживаемой версии API); блокировки Site Recovery и Backup — несколько попыток их снять провалились.

Почему это называют агентной атакой

Слово «агентная» здесь означает не то, что атаку провёл какой-то конкретный продукт, а то, как она выглядит в журналах. Microsoft и Sysdig относят JADEPUFFER к операциям, где разведку и выполнение ведёт автоматизированный агент с языковой моделью, а не скрипт с фиксированной последовательностью и не человек за консолью. Признаки, которые отличают такую атаку:

  • Длинная и методичная разведка. Человек, получивший облачный ключ, обычно делает несколько запросов и переходит к цели. Агент может часами перебирать все типы ресурсов, не теряя внимания.
  • Адаптивность. В отличие от скрипта, агент реагирует на ответы API: пробует другой путь, если запрос не прошёл, переключается на другую учётку, ищет блокировки и пытается их снять.
  • Машинная скорость на финале. Решение о разрушении принимается, и через 70 секунд идут вызовы удаления — без паузы, которая нужна человеку.

Для защиты это значит одно: окно между первым подозрительным событием и необратимым ущербом сжимается с часов до минут. Если ваш процесс реагирования предполагает, что дежурный увидит алерт, разберётся и отзовёт ключ, — к этому моменту хранилищ уже не будет.

Урок 1: утёкший секрет остаётся утёкшим

Самая тиражируемая цитата из отчёта — рекомендация считать скомпрометированными учётные данные, которые хоть раз были опубликованы, даже если исходное место потом отредактировали или удалили. Это знают все, но регулярно нарушают по трём причинам.

Редактирование создаёт иллюзию исправления. Сотрудник замечает секрет в issue, удаляет строку и считает вопрос закрытым. У GitHub, GitLab и большинства трекеров есть история правок, кеши, уведомления по почте и вебхуки, которые уже отправили исходный текст.

Ротация болезненна. Если секрет service principal’а прописан в десятке конфигов и пайплайнов, его замена — проект на день. Поэтому её откладывают.

Никто не сканирует issues. Сканеры секретов обычно настроены на код и коммиты. Комментарии, описания задач, вики и чаты остаются вне покрытия.

Что делать:

  • включить сканирование секретов не только для репозиториев, но и для issues, merge request’ов, вики и, по возможности, корпоративных чатов;
  • описать в регламенте: любая публикация секрета вне хранилища — инцидент с обязательной ротацией в течение часов, а не задача в бэклоге;
  • сделать ротацию дешёвой: секрет хранится в одном месте, потребители получают его оттуда, а не из копий. Как это устроить для агентов, мы описывали в статье «Ротация секретов для AI-агентов».

Урок 2: у машинной учётки не должно быть прав на всё

Service principal с правами на удаление учётных записей хранилищ, Key Vault и Function App в нескольких подписках — это фактически администратор облака без MFA. Такие учётки появляются потому, что выдать роль Contributor на подписку проще, чем разбираться, какие операции нужны интеграции.

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

  • Инвентаризация машинных учёток. Для каждого service principal’а, сервисного аккаунта, токена интеграции — владелец, назначение, перечень ресурсов, срок жизни. Учётки без владельца — первые кандидаты на отключение.
  • Разделение чтения и разрушения. Интеграция, которой нужно читать метрики, не должна иметь delete ни на что. Операции удаления выносятся в отдельные учётки или в процессы с подтверждением.
  • Ограничение области. Роль на конкретную группу ресурсов, а не на подписку. Отдельная учётка на каждое окружение.
  • Короткоживущие учётные данные. Federated credentials и workload identity вместо долгоживущих client secret там, где это поддерживается. Утёкший токен, который живёт час, гораздо менее полезен атакующему, чем секрет, живущий два года.

Подробнее об управлении такими учётками — в статье «Non-human identity для AI-агентов», о выдаче прав на время — в статье «JIT-доступ для AI-агентов».

Урок 3: защита от удаления должна стоять до инцидента

Самый практичный вывод из отчёта: уцелели ровно те ресурсы, на которых заранее стояли блокировки. Ни один алерт не успел бы их спасти — их спасла конфигурация.

Для Azure это блокировки ресурсов уровня CanNotDelete, защита учётных записей хранилищ от удаления, soft delete и защита от очистки для Key Vault, неизменяемое хранение для бэкапов, отдельные права на управление блокировками. У других облаков есть аналоги: защита от удаления для баз и бакетов, object lock, отдельные учётки для резервного копирования.

Принципы:

  • Блокировки на всём, что нельзя восстановить. Хранилища с данными, хранилища ключей, базы, хранилища бэкапов.
  • Права на снятие блокировок — у другой учётки. Storm-3168 пытался снять блокировки Site Recovery и Backup. Если учётка, которая может удалять ресурсы, может и снимать блокировки, защита сводится к одному лишнему вызову.
  • Бэкапы вне досягаемости основной учётки. Отдельная подписка или аккаунт, неизменяемое хранение, другие учётные данные.
  • Регулярная проверка восстановления. Защищённый бэкап, который никто не пробовал восстановить, — гипотеза, а не защита.

О резервном копировании агентной инфраструктуры — в статье «Бэкап и DR агентной инфраструктуры».

Урок 4: детектирование должно успевать за разведкой

Пятнадцать часов разведки — это окно, в котором атаку можно было остановить. Сигналы, которые давала атака:

  • service principal, который обычно делает несколько типовых запросов, внезапно перечисляет все типы ресурсов во всех подписках;
  • обращения с IP-адресов, не связанных с инфраструктурой организации;
  • массовые вызовы ListKeys и операций с Key Vault;
  • запросы к блокировкам и службам восстановления от учётки, которая с ними никогда не работала.

Microsoft перечисляет в отчёте классы алертов Defender, которые срабатывали на этих этапах: подозрительные операции Resource Manager через прокси, необычные операции с Key Vault, доступ с известных вредоносных адресов, признаки эксфильтрации.

Чтобы эти сигналы превратились в остановку атаки, нужно:

  • базовое поведение для каждой машинной учётки — какие операции, с каких адресов, в каком объёме она выполняет обычно;
  • правила на отклонение, а не только на сигнатуры: перечисление ресурсов в десять раз выше нормы — событие высокой важности;
  • автоматическое сдерживание. При высоком уровне уверенности учётка отключается автоматически, а не ждёт дежурного. Да, это иногда остановит легитимную интеграцию. Цена простоя интеграции на час несопоставима с ценой удалённых хранилищ.

Как связать журналы машинных учёток и агентов с SOC — в статьях «SIEM для AI-агентов» и «UEBA для AI-агентов».

Сценарий: та же атака против хорошо настроенного облака

Проиграем Storm-3168 против компании, которая выполнила рекомендации.

Утечка. Разработчик вставляет в issue лог с client secret. Сканер секретов, подключённый к трекеру, срабатывает через несколько минут. Регламент требует ротации; поскольку секрет хранится централизованно, ротация занимает минуты. Атакующий, нашедший секрет через сутки, получает ошибку аутентификации.

Предположим, ротация опоздала. Учётка — интеграция мониторинга с ролью Reader на одну группу ресурсов. Разведка видит ограниченный набор ресурсов, операций удаления нет вообще.

Предположим, учётка оказалась избыточной. Через час массового перечисления ресурсов с незнакомого адреса правило поведенческой аналитики отключает учётку. Разведка прерывается.

Предположим, и это не сработало. Атакующий начинает удаление. Хранилища с данными, Key Vault и базы закрыты блокировками, права на снятие которых есть только у отдельной учётки администратора с MFA. Удаляются тестовые ресурсы. Бэкапы в отдельной подписке, неизменяемые.

Каждый уровень может не сработать, но атакующему нужно пройти все. В реальной атаке у пострадавшей организации, судя по отчёту, частично сработал только последний — блокировки на части ресурсов.

Как это настроить: блокировки и отключение учётки командами

Блокировки и экстренное отключение лучше подготовить заранее в виде готовых команд, а не искать в документации во время инцидента. Пример для Azure CLI: блокировка от удаления на группу ресурсов с данными и на конкретный Key Vault.

# блокировка от удаления на всю группу ресурсов с данными
az lock create --name protect-data \
  --resource-group rg-prod-data \
  --lock-type CanNotDelete \
  --notes "Снятие только через change request"

# soft delete и защита от очистки для хранилища ключей
az keyvault update --name kv-prod-main \
  --resource-group rg-prod-data \
  --enable-purge-protection true

# список всех блокировок в подписке — для регулярной сверки
az lock list --output table

Права на Microsoft.Authorization/locks/delete стоит выдать отдельной роли и только людям с MFA, а не учёткам интеграций. Тогда учётка, которой достаточно Contributor для работы, всё равно не сможет снять блокировку.

Для экстренного сдерживания — заранее проверенный набор команд, который дежурный может выполнить за минуту:

# 1. отозвать все client secret скомпрометированного приложения
az ad app credential list --id <APP_ID> --query "[].keyId" -o tsv \
  | xargs -I{} az ad app credential delete --id <APP_ID> --key-id {}

# 2. отключить вход для service principal
az ad sp update --id <APP_ID> --set accountEnabled=false

# 3. посмотреть, что учётка успела сделать за последние сутки
az monitor activity-log list --caller <APP_ID> --offset 24h \
  --query "[].{time:eventTimestamp, op:operationName.value, status:status.value}" -o table

Порядок важен: сначала отозвать учётные данные и отключить вход, потом разбираться. Отчёт о Storm-3168 показывает, что между сменой фазы и разрушением прошло 70 секунд — разбор журналов до отключения может стоить данных. Обратите внимание и на то, что уже выданные токены доступа живут до истечения срока, поэтому для полного сдерживания нужно ещё убрать назначения ролей учётки.

Плейбук первых тридцати минут

Когда сигнал всё же сработал, порядок действий для скомпрометированной машинной учётки выглядит так:

  1. Минуты 0–5: сдерживание. Отключить учётку и отозвать секреты, удалить назначения ролей. Не ждать подтверждения от владельца интеграции — его уведомляют параллельно.
  2. Минуты 5–10: проверка второй учётки. Storm-3168 использовал две. Найти другие машинные учётки, которые обращались к тем же ресурсам с тех же адресов, и проверить их активность.
  3. Минуты 10–20: оценка ущерба. По журналу активности — какие ресурсы удалены, какие ключи прочитаны. Каждый прочитанный ключ хранилища ротировать: атакующий уже может иметь доступ к данным в обход учётки.
  4. Минуты 20–30: восстановление. Проверить soft delete и восстановить удалённые ресурсы, где это возможно; запустить восстановление из бэкапов для остального.
  5. После: причина. Найти, откуда утёк секрет, проверить историю правок публичных источников, заменить долгоживущие секреты на короткоживущие.

Общий плейбук для инцидентов, связанных с агентами, — в статье «Инцидент-респонс для AI-агентов».

При чём здесь ваши собственные AI-агенты

Отчёт описывает атакующего агента, но выводы напрямую касаются агентов, которых компании запускают сами. Внутренний агент для DevOps-задач, которому выдали service principal с широкими правами, — это та же учётка, только с большим количеством способов утечки: секрет лежит в конфиге агента, в переменных окружения CI, иногда — в контексте модели, откуда его можно извлечь prompt injection’ом.

Что меняется, если агент ваш:

  • Агент не должен получать секрет облака вообще. Он вызывает инструменты, а инструменты обращаются к облаку от имени служебной учётки, секрет которой хранится вне агента. Тогда в контексте модели и в логах нет ничего, что можно украсть. Подробнее — в статье «Доступ AI-агента к инфраструктуре».
  • Разрушительные операции — только с подтверждением. Агенту можно разрешить перезапуск сервиса, но удаление ресурса должен подтверждать человек. См. «Human-in-the-loop для AI-агентов».
  • Лимиты на объём операций. Агент, который за минуту отправил сто запросов на удаление, — либо скомпрометирован, либо зациклился. В обоих случаях его нужно остановить автоматически. См. «Лимиты и квоты для AI-агентов».

Чеклист: защита облака от агентного атакующего

  • Сканирование секретов охватывает код, issues, MR/PR, вики и чаты.
  • Любой опубликованный секрет ротируется в течение часов, независимо от того, удалена ли публикация.
  • Для каждой машинной учётки известны владелец, назначение и область прав.
  • Учётки интеграций не имеют прав на удаление, если это не их прямая задача.
  • Где возможно, используются federated credentials вместо долгоживущих секретов.
  • На хранилищах данных, ключей, базах и бэкапах стоят блокировки от удаления.
  • Права на снятие блокировок и управление бэкапами отделены от рабочих учёток.
  • Бэкапы хранятся отдельно и неизменяемо, восстановление проверяется регулярно.
  • Для машинных учёток есть базовое поведение и правила на отклонения.
  • Автоматическое отключение учётки при высокоуверенных признаках атаки.
  • Собственные AI-агенты не получают облачные секреты в контекст или окружение.

Вопросы и ответы

Что такое JADEPUFFER и Storm-3168? Это одна и та же группировка: Sysdig описал её под именем JADEPUFFER и назвал первой задокументированной агентной вымогательской операцией, Microsoft отслеживает её как Storm-3168. В сентябре 2026 года Microsoft опубликовала разбор атак группировки на Azure.

Как атакующие получили доступ? Microsoft не смогла точно установить способ начального доступа, но учётные данные одного из двух service principal’ов были раньше опубликованы сотрудником организации в публичном issue на GitHub и оставались доступны в истории правок.

Почему не помогло удаление секрета из issue? Публичная история правок сохранила исходный текст. Любой секрет, который был опубликован хотя бы на минуту, нужно считать скомпрометированным.

Что спасло часть ресурсов? Заранее настроенные блокировки ресурсов и защита учётных записей хранилищ от удаления. Попытки снять блокировки Site Recovery и Backup не удались.

Чем агентная атака опаснее обычной? Не новыми техниками, а скоростью и настойчивостью: агент может часами вести разведку без усталости и перейти к разрушению за секунды после решения. Окно для ручного реагирования сокращается до минут.

Как защититься, если у нас не Azure? Принципы те же для любого облака: сканирование секретов, наименьшие привилегии для машинных учёток, защита от удаления для критичных ресурсов, изолированные неизменяемые бэкапы, поведенческая аналитика и автоматическое сдерживание.

Где здесь Codenik

Codenik — управляемый слой доступа для AI-агентов и MCP-инструментов. Агенты вызывают инструменты через Codenik, а секреты систем хранятся в Codenik и не попадают ни в контекст модели, ни в конфиги на ноутбуках, ни в переменные окружения агента — значит, их нельзя случайно вставить в issue или вытащить из агента. Права на инструменты выдаются под роль и задачу, разрушительные операции можно закрыть подтверждением человека, а каждый вызов пишется в журнал, который можно отправить в SIEM. Codenik не заменяет блокировки ресурсов и защиту бэкапов в облаке, но убирает самый частый источник утечки — долгоживущий секрет в руках агента.

Короткий вывод

JADEPUFFER — это напоминание, что атакующий тоже автоматизирует работу. Против него не работают меры, которые рассчитаны на человеческую скорость: «заметим и отзовём». Работают меры, которые действуют до инцидента и без участия человека: секреты, которые не утекают и быстро ротируются, узкие права машинных учёток, блокировки на всём необратимом, бэкапы вне досягаемости и автоматическое отключение учётки, которая ведёт себя не так, как всегда.

Источники и дальнейшее чтение