Безсерверные платформы ускоряют разработку, но вместе с ними мы тащим целый зоопарк плагинов: от полезных «обёрток» для деплоя до инструментов для локального запуска, упаковки слоёв и автогенерации ролей. В нормальный день они экономят часы, а в плохой — становятся идеальной площадкой для атаки на цепочку поставок. Ниже — объяснение, как работает сценарий serverless plugin injection, почему он опасен, где именно находятся слабые места и что делать, чтобы не ловить «призраков» в продакшене.
Что такое serverless plugin injection простыми словами
Плагины для serverless-экосистемы — это расширения, которые автоматически исполняются в процессе сборки и деплоя. Они регистрируют «хуки» на этапах вроде before:package:createDeploymentArtifacts
или after:deploy:deploy
(терминология может отличаться, суть — одинаковая). Если в цепочку попадает вредоносный или скомпрометированный плагин, он получает доступ к переменным окружения, учётным данным CI, конфигурациям функций и может незаметно модифицировать то, что уходит в облако. Точку риска создаёт сам факт автоматического исполнения — разработчикам не нужно явно вызывать вредоносный код, он сработает «по расписанию».
Чтобы понимать механизмы, полезно держать в голове модель угроз цепочки поставок: разработчик → менеджер зависимостей → плагины/расширения → инфраструктура сборки → аккаунт облака. Этот контур разбирается многими практиками безопасной разработки, например в OWASP SAMM и NIST SSDF, которые рекомендуют формализовать контроль зависимостей и сборочных артефактов.
Где именно ломается защита: типовые точки входа
Serverless-проекты уязвимы не из-за магии, а из-за архитектуры процессов: много автоматизации, много доверия к стороннему коду и богатые разрешения у CI. Ниже — основные точки, где «впрыскивают» плагины.
- Плагины Serverless Framework — подключаются в
serverless.yml
, тянутся из npm и исполняются через хуки. Официальная документация прямо описывает модель расширений и хуков, что важно для оценки рисков (справка по плагинам). - Lambda Layers/Extensions — слои и расширения AWS могут содержать бинарники, перехватывающие сетевые вызовы, логи и метрики. Их проще «подсунуть» через автоматическую упаковку слоёв в плагине. AWS поддерживает подписывание артефактов функций и слоёв через AWS Signer, это стоит включать в базовую гигиену (AWS Lambda Code Signing).
- Azure Functions Extensions/NuGet — расширения подтягиваются через
extensions.csproj
и nuget-feed; подмена feed или зависимостей позволяет внедрить пост-build скрипты (документация по расширениям). - GCP Cloud Functions/Run зависимости — npm/pip/poetry/gradle, где supply chain риски аналогичны, а ci-скрипты нередко выполняют произвольные шаги до/после сборки (зависимости GCF).
- Инструменты локального запуска — «offline»/«emulator» плагины, которые имеют доступ к .env и секретам для локальной отладки; заражение здесь часто переносится в CI через кэш и lock-файлы.
Как выглядит атака от начала до конца
Разберём правдоподобный сценарий, который встречается в разных вариациях в реальных командах.
- Подмена зависимостей плагина. Атакующий публикует одноимённый пакет с типографической ошибкой (typosquatting) или компрометирует аккаунт автора. Новый релиз выходит «минорным» обновлением, чтобы автоматом подтянулся в CI.
- Автовыполнение в хук. Вредонос добавляет хук
before:deploy:deploy
и незаметно внедряет дополнительный Lambda Layer, меняет переменные окружения, включает сетевой прокси или загружает секреты (AWS_ACCESS_KEY_ID, SLACK_WEBHOOK и т.д.). - Закрепление. Плагин прописывает невидимый ресурс (например, отдельную роль/политику IAM или «временную» функцию-ретранслятор), чтобы вы пережили откат версии.
- Экфильтрация и lateral movement. Через расширение/слой проксируется трафик, собираются токены сервисов и метаданные, а затем злоумышленник двигается к соседним аккаунтам, бакетам и очередям.
Снаружи вы видите «зелёный» деплой. Внутри — изменённые артефакты и тихая телеметрия наружу. Именно поэтому в безсерверных проектах важно не только тестировать код функций, но и контролировать «мета-код» — плагины, шаблоны, слои и CI-шаги.
Признаки компрометации: на что смотреть в первую очередь
Хорошая новость: многие следы можно заметить, если знать, где искать. Ниже — список индикаторов и мест проверки.
- Drift в IaC/конфигурации: в
serverless.yml
появились новые плагины или «опциональные» настройки, которых не было в MR/PR. - Неожиданные Layers/Extensions: у функций стали появляться дополнительные слои, изменились handler’ы, появились сторонние «observability» расширения без тикетов.
- Сетевые аномалии: лямбды, у которых раньше не было исходящего трафика в Интернет (VPC egress=0), внезапно «стучатся» на домены, не связанные с бекендом.
- Дрейф прав: у IAM-ролей функций возникают новые
iam:PassRole
,lambda:UpdateFunctionCode
или доступы к KMS, которых не согласовывали. - CI-логи: в логах сборки и деплоя появились дополнительные шаги/скрипты («postinstall», «prepare», «prepack»), которых нет в репозитории.
Практика: демонстрационный «ловкий» плагин
Чтобы понимать механику, достаточно взглянуть на упрощённый пример. Пусть у нас есть проект на Serverless Framework с таким фрагментом конфигурации:
plugins:
- serverless-offline
- serverless-layer-packer
- serverless-my-helper # выглядит как мелочь
Внутри serverless-my-helper
разработчик (или злоумышленник) регистрирует хук:
// index.js плагина
class MyHelper {
hooks = {
'before:deploy:deploy': this.injectLayer.bind(this)
};
async injectLayer() {
const env = process.env;
// доступ к токенам, переменным окружения CI и т.п.
// изменение serverless.service.provider.layers, добавление env
}
}
module.exports = MyHelper;
Если этот пакет прилетит из внешнего реестра без закреплённых версий и без аудита, вы получите «неучтённый код», который выполнится в самом центре жизненного цикла деплоя. Именно на это и рассчитан plugin injection.
Профилактика: базовый технический минимум
Здесь нет серебряной пули, но есть набор практик, который резко снижает вероятность и эффект атаки. Начинаем с очевидного, но обязательного.
- Жёсткие версии и lock-файлы. Включите «fail-on-update» при дрейфе
package-lock.json
/pnpm-lock.yaml
, используйте разрешённые диапазоны версий только через ревью. - Частные прокси-реестры. Проксируйте npm/pip/nuget через приватный кэш (Verdaccio, Nexus, Artifactory) с allow-list для плагинов и автозапретом «неизвестных» пакетов.
- Подпись и верификация артефактов. Для функций/слоёв включите подпись (AWS Signer для Lambda) и верификацию на стороне деплоя; для контейнеров и ZIP используйте Sigstore/cosign.
- Происхождение билдов (SLSA). Опишите минимальный целевой уровень SLSA и храните provenance; это не бюрократия, а способ быстро отследить, откуда взялся артефакт.
- SBOM и политика зависимостей. Генерируйте SBOM (CycloneDX, SPDX), фиксируйте её рядом с артефактом, блокируйте деплой при неожиданном появлении новых пакетных имён.
- Чистый CI. Запрещайте сетевой egress step’ам, где он не нужен; используйте ephemeral runners; исключите
npm install --no-frozen-lockfile
в продакшн-пайплайне. - Минимальные права ролей. IAM-ролям функций не нужны права на управление самими функциями. Разделите «роль выполнения» и «роль деплоя».
- Изоляция исходящего трафика в рантайме. Для AWS Lambda — VPC-изоляция и egress через контролируемый NAT/прокси, для Cloud Functions/Run — Cloud NAT/Serverless VPC Access с egress-политиками.
Политики и процессы: как не утонуть в исключениях
Технологии работают только при поддержке процессов. Ниже — набор простых правил, которые помогут команде не спорить каждый раз с нуля.
- Реестр разрешённых плагинов. Ведение списка «approved plugins» с указанием версии, владельца и обоснования. Любое новое имя — только через тикет и ревью.
- Регулярный «паспорт» функций. Раз в две недели формируйте отчёт: «какие слои/расширения/переменные у каких функций» и подписывайте его ответственным.
- Правило «одно изменение — один MR». Обновление плагина не должно ехать вместе с бизнес-логикой. Так легче откатывать и анализировать риск.
- Блокировка прод-среды по времени. Деплои в рабочее время и только при доступности всей дежурной цепочки (Dev, Sec, Ops), чтобы не обсуждать критичное в одиночку ночью.
Быстрый план внедрения контроля (пошагово)
Если хочется начать «с понедельника», берём следующий маршрут — он реалистичен для типичного проекта.
- Неделя 1: включить «frozen lockfile» во всех прод-пайплайнах; настроить приватный прокси-реестр; собрать список текущих плагинов и слоёв.
- Неделя 2: добавить генерацию SBOM (CycloneDX для npm/poetry/maven) и простое правило: если SBOM поменялась — деплой требует ручного подтверждения.
- Неделя 3: включить подпись артефактов (AWS Signer или cosign для контейнеров/ZIP) и валидацию на этапе деплоя.
- Неделя 4: обрезать egress в CI и у функций, которым он не нужен; внедрить отчёт по изменившимся слоям/расширениям.
- Неделя 5+: внедрить политику «approved plugins», проиграть tabletop-учения: как команда реагирует на компрометацию плагина.
Инструменты и сервисы, которые реально помогают
Выбор зависит от стека, но уместно упомянуть несколько полезных направлений.
- Управление зависимостями: приватный npm-прокси (Verdaccio/Nexus/Artifactory), политика «only approved scopes».
- Анализ SBOM: CycloneDX CLI, Syft/Grype, Dependency-Track — автоматическая проверка дрейфа и уязвимостей.
- Подпись и provenance: Sigstore/cosign, in-toto, policy-enforcement в CI и на стадии деплоя.
- Автообновления под контролем: Renovate/Dependabot с правилами «no auto-merge for plugins», отчётами и батчингом патч-обновлений.
- Контроль рантайма: egress-контроль (NAT + egress-ACL), логирование DNS, alert на «новые» домены из функций.
Как проверить себя: мини-чек-лист
Если времени мало, пройдитесь по этому списку — он помогает быстро понять, насколько вы близки к «взрослой» модели управления плагинами.
- Lock-файлы обязательны, сборка падает при несоответствии.
- Плагины/слои идут только из приватного прокси-реестра.
- Есть список «approved plugins» и процесс добавления новых.
- Каждый деплой сопровождается SBOM и подписью артефакта.
- CI не имеет исходящего трафика без явной необходимости.
- Функции без интернет-нужды — без egress в Интернет.
- Срабатывает алерт при появлении нового слоя/расширения у функции.
FAQ: коротко о типичных возражениях
«Но у нас быстрый релизный цикл, мы не можем тормозить деплой на каждой обнове плагина».
Ответ: батчите обновления, держите два окна в неделю для «поставки пакетов», используйте «canary-проект» для теста обновлений плагинов до продакшена.
«Подпись артефактов — это слишком сложно».
Ответ: начните с минимальной схемы — подпись только прод-артефактов и валидация на деплое. AWS Lambda поддерживает встроенную проверку подписей (док-во).
«Вредоносный плагин всё равно сможет уйти в сеть».
Ответ: не сможет, если у CI нет egress, а функции — в приватных подсетях с управляемым NAT и egress-ACL. Делайте сеть «по умолчанию закрытой».
Итоги
Serverless plugin injection — не экзотика, а закономерный эффект нашей любви к автоматизации. Хорошая новость в том, что защита укладывается в понятные шаги: фиксируйте происхождение артефактов, ограничивайте источники зависимостей, режьте исходящий трафик там, где он не нужен, и относитесь к плагинам как к коду с тем же уровнем недоверия, что и к любому внешнему компоненту. Тогда плагины снова станут тем, чем должны быть — ускорителями, а не «тайными дверями» в продакшен.