Workload Identity
В апреле 2021 атакующий модифицировал Codecov bash uploader — скрипт, который CI-сервисы тысяч компаний запускали для загрузки coverage reports. Изменение было крошечным: добавили curl, который отправлял на адрес атакующего дамп переменных окружения. А в этих переменных у большинства конвейеров лежали долгоживущие токены к AWS, GCP и GitHub. Подменённый скрипт больше двух месяцев собирал переменные окружения у более чем двадцати тысяч клиентов Codecov, а дальше атакующие автоматически перебрали собранные креды и проникли в сотни клиентских сетей. Один скрипт в чужом сервисе. Компрометация разошлась по всей отрасли. Этот инцидент и стал спусковым крючком для массового перехода к федерации OIDC в CI/CD: GitHub Actions выкатил её поддержку через полгода, остальные подтянулись. Workload Identity бьёт в корень проблемы. Долгоживущий общий секрет для нечеловеческого субъекта — раннера CI, пода, Lambda, скрипта — это учётные данные, которые обязательно утекут: они лежат в десятках мест, ротируются редко, кочуют между средами. На их место встаёт криптографическая идентичность, привязанная к самой нагрузке, со сроком жизни в минуты и часы и без единого секрета на диске. SPIFFE здесь стандарт, SPIRE — его эталонная реализация, IRSA у AWS и Workload Identity у GCP и Azure — облачные варианты, федерация OIDC — мост между провайдерами идентичности. Прямой сосед — Secrets Management, и граница чёткая: тот лист управляет общими секретами, этот делает большинство из них ненужными.
Что должен уметь
Заголовок раздела «Что должен уметь»Главный навык на уровне L5 — спроектировать модель аутентификации между сервисами для всего стека. Это не «настроим IRSA для одного сервиса», а решение для каждого сервиса в кластере, каждого запуска CI, каждой бессерверной функции, каждой задачи по расписанию. Без единой модели вырастает зоопарк: половина сервисов на IRSA, половина на вечных ключах AWS, CI на OIDC, Lambda на политике ресурса. Каждое исключение — потенциальное место утечки. Единая модель сжимает поверхность атаки в разы.
L3
- Понимает разницу между идентичностью человека (учётная запись, SSO, MFA) и идентичностью нагрузки (сервисный аккаунт, машинные учётные данные, короткоживущий токен).
- Использует облачный механизм для своего сервиса (IRSA на EKS, Workload Identity на GKE, Managed Identity в Azure) вместо вечных ключей доступа.
L4
- Настраивает федерацию OIDC для CI/CD (GitHub Actions OIDC → AWS, GCP или Azure; GitLab JWT → AWS) и убирает долгоживущие учётные данные из секретов репозитория.
- Различает SPIFFE ID, SVID (X.509 или JWT), trust bundle и attestation; читает спецификацию SPIFFE, чтобы понимать, как выдача идентичности работает под капотом.
- Настраивает mTLS между сервисами через идентичность нагрузки (Istio плюс SPIFFE SVID, идентичность Linkerd, ручная связка со SPIRE) — аутентификация между сервисами без общих секретов.
L5
- Проектирует стратегию для всей организации: SPIRE (несколько облаков и платформ) против облачного механизма (только внутри одного облака, зато без эксплуатации); отдельная модель для нагрузок, живущих сразу в нескольких облаках.
- Внедряет политику подтверждения: какая нагрузка какую идентичность получает. На уровне пода (сервисный аккаунт Kubernetes), на уровне ноды (метаданные инстанса), на уровне сборки (идентичность привязана к конкретному артефакту из CI).
- Стыкует это с Supply Chain Security: идентичность нагрузки внутри сборки по SLSA. Подписанный артефакт плюс подписанная нагрузка дают сквозную цепочку доверия.
L6+
- Проектирует федерацию доверия для нескольких кластеров, облаков и организаций: связанные серверы SPIRE, федерация между доменами доверия, обмен JWT SVID между партнёрами.
- Принимает стратегические решения: SPIRE на своих серверах или управляемый сервис (HashiCorp HCP Boundary, AWS Roles Anywhere для нагрузок вне EC2), покупать инфраструктуру идентичности или строить, как связать её с уже существующей PKI.
Материалы
Заголовок раздела «Материалы»Стандарты и спецификации
Заголовок раздела «Стандарты и спецификации»- SPIFFE Specification (CNCF graduated). Канонический документ: SPIFFE ID format (
spiffe://trust-domain/path), SVID (SPIFFE Verifiable Identity Document — X.509 или JWT), trust bundle distribution, attestation framework. - OpenID Connect Federation 1.0 + OAuth 2.0 Token Exchange (RFC 8693). Технические основы OIDC federation; token exchange — как cloud принимает OIDC token от CI и выдаёт STS credentials.
- Heather Adkins et al. — Building Secure and Reliable Systems (O’Reilly, 2020), глава 5 (Design for Understanding) и глава 6 (Design for a Changing Landscape). Взгляд Google на ALTS (Application Layer Transport Security) — их внутренний механизм идентичности нагрузок и концептуальная основа SPIFFE.
Статьи и доклады
Заголовок раздела «Статьи и доклады»- Codecov bash uploader compromise (April 2021) + Bloomberg coverage. Главный кейс — см. ниже.
- GitHub Blog — Secure deployments with OpenID Connect (Nov 2021). Объявление поддержки OIDC в GitHub Actions — событие отраслевого масштаба.
- AWS Blog — IAM Roles Anywhere (July 2022). Расширение механизма на нагрузки за пределами AWS через якорь доверия X.509.
- SPIFFE и SPIRE выпущены из инкубатора CNCF (CNCF, сентябрь 2022). Формальная веха, после которой стандарт можно спокойно предлагать в проде: оба проекта в статусе graduated с августа 2022.
- NIST SP 800-204D — Strategies for the Integration of Software Supply Chain Security in DevSecOps CI/CD Pipelines (NIST, 2024). Раздел 4 — про идентичность нагрузок в контексте конвейера.
Инструменты
Заголовок раздела «Инструменты»- SPIRE (CNCF graduated). Эталонная реализация SPIFFE. Ставится на свои серверы, работает где угодно: Kubernetes, Nomad, виртуалки, бессерверные функции. По моим наблюдениям, её берут там, где облаков несколько или инфраструктура гибридная и облачный вариант не подходит, — и там, где zero-trust прописан в стратегии.
- AWS IRSA (IAM Roles for Service Accounts) — workload identity для EKS pods через OIDC provider кластера. Стандарт для тех, кто целиком в AWS и на EKS.
- AWS IAM Roles Anywhere — расширение IAM roles на non-AWS workloads через якорь доверия X.509 (виртуалки в Azure, серверы на своём железе, IoT).
- GCP Workload Identity (для GKE) + Workload Identity Federation (для внешних нагрузок через OIDC). Стандарт для тех, кто живёт в GCP.
- Azure Workload Identity для AKS, Federated Identity Credentials для external. Дополняют Managed Identity, которая работает только для ресурсов самой Azure.
- Service mesh с identity: Istio (SPIFFE-compatible SVIDs, mTLS by default), Linkerd (proprietary identity, mTLS by default), Cilium (mutual authentication поверх SPIFFE-идентичностей). По моим наблюдениям, Linkerd чаще берут за простоту установки, Istio — за глубину управления, расплачиваясь сложностью эксплуатации.
- Поддержка OIDC в CI/CD: GitHub Actions (разрешение
id-token: writeплюс политика доверия на стороне облака), GitLab CI (JWT черезid_tokens), CircleCI (токены OIDC), Bitbucket Pipelines. На 2024–2025 годы это стандарт для выкаток в облако, а старые вечные ключи в CI — накопленный долг по безопасности. - HashiCorp Boundary — идентичность нагрузок вместе с управлением доступом; подход другой, через авторизацию воркера по запросу. Полезен там, где на машину ходит человек.
- Athenz (изначально Yahoo, сейчас под Linux Foundation) — ветеран темы, появившийся раньше SPIFFE. Реже выбирают для green-field, но встречается там, где инфраструктура строилась вокруг стека Yahoo.
Best practices
Заголовок раздела «Best practices»Главный публичный кейс — Codecov bash uploader (апрель 2021), описанный в начале листа. Урок не в том, что Codecov плохие. Урок в том, что переменная окружения в CI с вечным ключом AWS — это учётные данные, которые утекут. Любой чужой скрипт в конвейере, любая компрометация цепочки поставок, любая оплошность с логированием — и токен уже у атакующего, причём заметить это вы, скорее всего, не сможете: обращения с ним выглядят как обычные вызовы API из вашего же CI, с вашего же адреса и в ваше рабочее время. Федерация OIDC убирает этот класс утечек целиком: в окружении CI нет постоянных учётных данных, есть короткоживущий JWT на десять минут, выпущенный ровно под один запуск. Красть его бессмысленно: он протухнет раньше, чем до него дойдут руки. Это первое, что я бы внедрял в любой команде, которая катит в облако, даже если больше из workload identity не делать ничего.
Отсюда первое правило, и оно не обсуждается: федерация OIDC для CI/CD. Долгоживущие облачные ключи в secrets.AWS_ACCESS_KEY_ID — это унаследованный долг по безопасности, а не «пока и так работает». Связка GitHub Actions OIDC с AWS STS, GCP STS или федерацией Azure настраивается за вечер на облако и окупается одной предотвращённой утечкой того же класса, что у Codecov. Если в репозитории до сих пор лежит AWS_SECRET_ACCESS_KEY, чинить я начал бы с него.
Второе — выбор реализации. Для нагрузок внутри одного облака встроенный вариант (IRSA, GCP Workload Identity, Azure Workload Identity) выигрывает у всего остального. Эксплуатировать нечего, интеграция с IAM провайдера глубокая. SPIRE — больше движущихся частей, зато единая модель идентичности поверх AWS, GCP, своего железа и бессерверных функций сразу. Тащить его в одно облако незачем. Игнорировать там, где облаков несколько, — тоже.
Третье правило неочевидное. Вопрос «кому выдать идентичность» опаснее вопроса «как её выдать». Слабая политика подтверждения — скажем, когда любой под в служебном namespace получает идентичность критичного сервиса — по последствиям равна звёздочке в правах RBAC. Минимум — привязка к сервисному аккаунту, namespace и получателю токена. Уровень ноды и привязка к конкретной сборке — это уже защита в глубину.
Граница с Secrets Management чёткая и важная. Я регулярно вижу путаницу: «у нас Vault, нам не нужен workload identity». Vault даёт управление общими секретами: централизацию, ротацию, аудит. Workload identity делает большинство этих секретов ненужными: вместо «pod достаёт DB password из Vault через app role» — «pod получает SPIFFE SVID, DB принимает client cert». Это не «или/или». Vault остаётся нужен там, где секрет ничем не заменить: сторонний API без mTLS, старая система, которая умеет только пароль. Но если сервис проектируется сегодня и его зависимости говорят по mTLS, идентичность выигрывает: меньше операционной возни и меньше мест, откуда может утечь.
Service mesh — короткий путь к workload identity для тех, кто в Kubernetes. Istio и Linkerd дают идентичность и mTLS из коробки. Pod получает SPIFFE SVID или mesh identity без единой правки в коде приложения, а mTLS включается на уровне меша — то есть команда приходит к workload identity, вообще не притрагиваясь к SPIRE. Платить приходится операционной сложностью: sidecar на каждый pod, отдельный control plane, заметно более муторная отладка. На полусотне микросервисов это окупается, на пяти — overkill.
Политика подтверждения — место, где безопасность встречается с эксплуатацией. В SPIRE это работает так: агент на ноде доказывает серверу, что нагрузка — именно та, за которую себя выдаёт. Доказывает по метаданным пода, по хешу бинарника или по конкретному AMI для EC2. Политика решает, какая комбинация атрибутов даёт какой SPIFFE ID. Слабое правило вроде «любая нагрузка в этом namespace получает идентичность критичного сервиса» означает, что доступ к критичному получит любой под оттуда. Жёсткое — хеш бинарника плюс конкретный сервисный аккаунт плюс метка ноды — безопаснее, но ломается на каждом законном изменении. Донастройка политики это операционная работа, которую большинство команд недооценивает; закладывайте на неё время сразу.
Адрес издателя OIDC публичный, ключ подписи — нет. Частое заблуждение звучит так: «OIDC безопасен, там же криптография». Криптография гарантирует только подлинность подписи издателя, а всё остальное решает политика доверия на стороне облака. И если она разрешает любой репозиторий, любую ветку и любого автора, федерация честно выдаст учётные данные каждому, кто умеет сформировать запрос. Условие должно быть жёстким: конкретный репозиторий, конкретная ветка или окружение, конкретный workflow. Шаблон политики от AWS — нормальная стартовая точка, но дальше его правят под себя.
Связанные листья
Заголовок раздела «Связанные листья»- Secrets Management — идентичность нагрузок делает большинство общих секретов ненужными; соседний лист управляет тем, что заменить ею нельзя.
- Access Control & IAM — это слой идентичности для машин; авторизация IAM строится поверх и решает, кому что позволено.
- Supply Chain Security — идентичность внутри сборки, связка «подписанный артефакт — тот, кто его собрал», — часть модели SLSA.
- CI/CD — федерация OIDC в конвейере; одноразовые раннеры вместе с идентичностью нагрузки убирают целый класс проблем безопасности в CI.
- Threat Modeling — она меняет модель угроз для вызовов между сервисами: границы доверия смещаются с сетевого периметра к криптографической идентичности.
- Networking — mTLS поверх идентичности нагрузки заменяет защиту по сетевому периметру; это и есть движение к zero-trust.
- Compliance Frameworks — инвентарь сервисных аккаунтов и access review по каждому сервису — типичные требования аудита; идентичность нагрузок упрощает сбор доказательств.
- Infrastructure as Code — конфигурация идентичности (привязки IRSA, политики доверия, правила подтверждения SPIRE) — такой же артефакт IaC, как и любая другая настройка IAM.
Открытые вопросы
Заголовок раздела «Открытые вопросы»Публичных разборов федерации SPIRE в проде мало, и почти все они не идут дальше блог-поста. Adobe, Pinterest и Bloomberg что-то публиковали, но деталей там скудно. Если ваша команда держит её в проде — расскажите, опыт редкий.
- Идентичность нагрузок между облаками для команд, которым не подходит ни SPIRE (слишком много возни), ни облачный механизм (одного облака попросту нет), — это дыра в инструментах. Есть HCP Boundary и Aembit, но управляемых предложений пока мало.
- Идентичность для бессерверных функций (Lambda, Cloud Functions) — паттерны в духе IRSA есть, но короткий жизненный цикл нагрузки усложняет подтверждение: долгоживущему агенту там негде жить.
Отдельно стоит идентичность на границе сети и в IoT. Там свой набор ограничений: связь рвётся, устройства слабые, счёт узлов идёт на миллионы. SPIFFE формально применим, но устоявшихся практик я не вижу.
Глубоко не разбирался и с постквантовой идентичностью — переводом X.509 SVID на алгоритмы, устойчивые к квантовым атакам. Сейчас это мало для кого приоритет, но через несколько лет станет.