Skip to content

Глава 7. Рабочие нагрузки и SPIFFE/SPIRE

В Главе 5 мы построили фундамент идентичности для людей: IdP, OIDC, фишинго-устойчивая MFA. В Главе 6 — защитили привилегированный доступ через PAM и динамические секреты. Но люди — лишь малая часть участников сети. На каждого пользователя приходятся десятки сервисов, контейнеров, CI/CD-пайплайнов и API-интеграций, каждый из которых тоже нуждается в идентичности. Эта глава — о небиологических идентичностях (NHI) и о том, как SPIFFE/SPIRE решает проблему идентификации рабочих нагрузок в мультиоблачной среде.


Зачем: масштаб проблемы NHI

NIST SP 800-207 (Section 2, Tenet 1) определяет: «Все источники данных и вычислительные сервисы считаются ресурсами». Это значит, что не только пользователи, но и сервисы, контейнеры, функции — все участники обмена данными должны иметь проверяемую идентичность.

Источник: NIST SP 800-207, Section 3

Небиологические идентичности (NHI)

NHI (Non-Human Identities) — это все цифровые идентичности, которые работают без непосредственного участия человека:

  • Сервисные учётные записи — для приложений, обращающихся к базам данных и API
  • API-ключи и токены — AWS Access Keys, GitHub PAT, OAuth client credentials
  • SSH-ключи — для автоматизации и Git-операций
  • Цифровые сертификаты — X.509/TLS, mTLS, code signing
  • CI/CD-токены — GitHub Actions, GitLab CI, Jenkins credentials
  • RPA-боты — учётные данные для робототехнической автоматизации
  • AI-агенты — новый класс NHI: агенты, обращающиеся к API, базам данных и сервисам

Источники: Microsoft Security: What Are Non-Human Identities, Okta: What Are Non-Human Identities

Масштаб: NHI vs люди

По данным отраслевых исследований, NHI значительно превышают по количеству человеческие идентичности:

ИсточникСоотношение NHI:HumanГод
CyberArk State of Machine Identity Security80:12025
CSA / Astrix Security Survey20:1 (Fortune 500)2024
Entro Security NHI Risk Report144:1H1 2025

Источники: CyberArk: Machine Identities Outnumber Humans by More Than 80 to 1, CSA: State of Non-Human Identity Security, Entro Security H1 2025 Report

Почему NHI — растущий вектор атак

NHI отличаются от человеческих идентичностей по трём критическим параметрам:

1. Отсутствие MFA. Сервисная учётная запись не может пройти второй фактор аутентификации. Если её секрет скомпрометирован — доступ получен немедленно.

2. Долгоживущие секреты. По данным GitGuardian State of Secrets Sprawl 2025, 70% секретов, утечённых в публичные GitHub-репозитории в 2022 году, остаются валидными в 2025. В 2024 году обнаружено 23.77 млн новых захардкоженных секретов в публичных репозиториях (+25% YoY).

Источник: GitGuardian State of Secrets Sprawl 2025

3. Отсутствие lifecycle management. По данным CSA / Oasis Security (2025), 79% ИТ-специалистов считают себя не готовыми к предотвращению атак через NHI. Только 15% организаций уверены в полноте инвентаризации NHI.

Источник: CSA: 79% of IT Pros Feel Ill-Equipped to Prevent NHI Attacks

OWASP NHI Top 10 (2025)

OWASP опубликовал первый Top 10 рисков для NHI в 2025 году. Три из десяти рисков напрямую связаны с управлением секретами:

#РискСуть
NHI1Improper OffboardingNHI не деактивируются при выводе из эксплуатации
NHI2Secret LeakageУтечка ключей в код, логи, чат-платформы
NHI5Overprivileged NHIИзбыточные привилегии за пределами функциональных требований
NHI7Long-Lived SecretsСтатические секреты без ротации
NHI10Human Use of NHIРазработчики используют сервисные учётные записи для ручных задач

Полный список: OWASP NHI Top 10

Решение перечисленных проблем требует принципиально другого подхода к идентификации рабочих нагрузок — криптографической идентичности вместо статических секретов. Именно это предлагает стандарт SPIFFE.


Стандарт SPIFFE

SPIFFE (Secure Production Identity Framework for Everyone) — открытый стандарт, определяющий формат идентичности для рабочих нагрузок и API для её получения. Проект под эгидой CNCF (graduated, September 2022).

Источник: CNCF: SPIFFE and SPIRE Graduate

Спецификации

Стандарт включает следующие ключевые документы, поддерживаемые в GitHub-репозитории SPIFFE:

ДокументНазначение
SPIFFE IDФормат идентификатора рабочей нагрузки
X509-SVIDX.509-сертификат как носитель идентичности
JWT-SVIDJWT-токен как носитель идентичности
Trust Domain and BundleДомен доверия и набор корневых ключей
Workload APIgRPC API для получения SVID
Workload EndpointКак найти агент идентичности на узле
SPIFFE FederationПротокол федерации между доменами доверия

Спецификации поддерживаются как живые документы в GitHub — без традиционного семантического версионирования.

Источник: SPIFFE Specifications

SPIFFE ID

Формат: spiffe://<trust-domain>/<path>

spiffe://production.example.org/ns/payments/sa/api-server
  │          │                     │
  scheme     trust domain          path (идентифицирует рабочую нагрузку)
  • Scheme: spiffe:// — RFC 3986-совместимый URI
  • Trust domain: authority component; регистронезависимый; максимум 255 байт
  • Path: регистрозависимый; уникально идентифицирует рабочую нагрузку внутри домена доверия
  • Сегменты пути: только [a-zA-Z0-9._-], без пустых сегментов, .. или завершающего /

Источник: SPIFFE-ID Specification

SVID: два формата

SVID (SPIFFE Verifiable Identity Document) — криптографический документ, подтверждающий идентичность рабочей нагрузки. Стандарт определяет два формата:

X.509-SVIDJWT-SVID
ФорматX.509-сертификатJSON Web Token
SPIFFE ID вSubject Alternative Name (URI SAN)Claim sub
Обязательные поляРовно один URI SAN, Key Usagesub, aud, exp, iat
ПрименениеmTLS между сервисамиL7-прокси, ситуации с разрывом TLS
ПреимуществаНет replay-атак, native mTLSПрозрачность через L7-балансировщики
ОграниченияТребует TLS-соединениеПодвержен replay (aud + exp смягчают)

Спецификация рекомендует X.509-SVID как основной формат. JWT-SVID — для случаев, когда L7-прокси или балансировщик разрывает TLS-соединение.

Источники: X509-SVID Spec, JWT-SVID Spec

Домен доверия (Trust Domain)

Домен доверия соответствует корню доверия системы. Все идентичности внутри одного домена разделяют общий корень доверия — SPIFFE Bundle (набор корневых CA-сертификатов и/или ключей подписи JWT).

Типичная организация имеет несколько доменов доверия:

spiffe://production.example.org/...   — production-среда
spiffe://staging.example.org/...      — staging
spiffe://ci.example.org/...           — CI/CD-инфраструктура

Федерация между доменами позволяет рабочим нагрузкам из разных доменов аутентифицировать друг друга.

Источник: SPIFFE Trust Domain and Bundle

Workload API

Стандартизированный gRPC API, через который рабочие нагрузки получают свои SVID и trust bundles.

Ключевые свойства:

  • Доступен через Unix Domain Socket (не TCP) — только локальные процессы на узле
  • TLS не требуется на сокете — рабочая нагрузка может не иметь корня доверия до bootstrapping
  • Клиент находит сокет через переменную окружения SPIFFE_ENDPOINT_SOCKET
  • Рабочая нагрузка не хранит никаких секретов — идентичность доставляется через API

Источник: SPIFFE Workload API


SPIRE: эталонная реализация

SPIRE (SPIFFE Runtime Environment) — эталонная реализация стандарта SPIFFE. Проект CNCF (graduated). Используется в production Bloomberg, ByteDance, GitHub, Netflix, Pinterest, Uber и др.

Источник: CNCF SPIRE Project Page, SPIRE GitHub

Архитектура

SPIRE состоит из двух основных компонентов: Server и Agent.

SPIRE Server — центральный компонент:

КомпонентФункция
Certificate Authority (CA)Подписывает X.509-SVID и JWT-SVID
Data StoreХранит registration entries и аттестованные узлы. Поддерживает SQLite 3 (default), MySQL, PostgreSQL
Registration APIУправление записями о рабочих нагрузках и их селекторами
Node Attestor (server)Валидирует аттестационные данные от агентов
Upstream AuthorityПлагин для делегирования подписи внешнему PKI (Vault, AWS ACM PCA, другой SPIRE Server)

SPIRE Agent — запускается на каждом узле (DaemonSet в Kubernetes):

КомпонентФункция
Workload APIgRPC API на Unix Domain Socket для локальных рабочих нагрузок
Node Attestor (agent)Предоставляет аттестационные данные серверу для подтверждения идентичности узла
Workload AttestorИдентифицирует рабочую нагрузку по PID (k8s, unix, docker плагины)
SVID CacheКеширует SVID и trust bundles, обновляет до истечения срока

Источник: SPIRE Concepts

Аттестация узлов (Node Attestation)

Node Attestation — механизм, которым SPIRE Agent доказывает свою идентичность SPIRE Server при первом подключении. Каждый метод использует платформенно-специфичные доказательства:

ПлагинПлатформаКак работает
k8s_psatKubernetesAgent предъявляет Projected Service Account Token; Server валидирует через TokenReview API
aws_iidAWS EC2Agent получает Instance Identity Document (подписан AWS); Server проверяет подпись
gcp_iitGCP GCEAgent получает Instance Identity Token; Server валидирует
azure_msiAzure VMAgent получает Managed Service Identity token; Server валидирует и извлекает Tenant/Principal ID
join_tokenЛюбаяОдноразовый токен, созданный на сервере. Простой, но не автоматизированный
x509popЛюбая (PKI)Agent доказывает владение X.509-сертификатом, выданным вне SPIRE

Плагин k8s_sat (legacy Service Account Tokens) удалён в SPIRE 1.12.0 — используйте только k8s_psat. Полный список built-in плагинов включает также azure_imds, sshpop, tpm_devid и др. — см. документацию SPIRE.

Источники: k8s_psat Plugin, Configuring SPIRE

Аттестация рабочих нагрузок (Workload Attestation)

Когда рабочая нагрузка обращается к Workload API, SPIRE Agent идентифицирует её по PID процесса, затем преобразует PID в набор селекторов через плагины workload attestor.

Kubernetes Workload Attestor — наиболее распространённый в контейнерных средах:

СелекторПримерОписание
k8s:nsk8s:ns:productionNamespace
k8s:sak8s:sa:payments-apiService Account
k8s:pod-labelk8s:pod-label:app:paymentsPod label (key:value)
k8s:container-namek8s:container-name:apiИмя контейнера
k8s:container-imagek8s:container-image:myregistry/app:v1Образ конкретного контейнера

Важное различие: k8s:container-image сопоставляется только с контейнером, обратившимся к SPIRE, тогда как k8s:pod-image — с любым контейнером в поде.

Unix Workload Attestor — для процессов вне контейнеров:

СелекторПримерОписание
unix:uidunix:uid:1000User ID
unix:userunix:user:nginxUsername
unix:pathunix:path:/usr/bin/nginxПуть к бинарнику
unix:sha256unix:sha256:3a6eb079...SHA256 бинарника

Источники: k8s Workload Attestor, Unix Workload Attestor

Как рабочие нагрузки получают SVID

SPIRE предоставляет несколько способов доставки SVID в рабочую нагрузку:

МетодОписаниеМодификация приложения
SPIFFE CSI DriverBind mount Unix-сокета через CSI volumeТолько volume mount
spiffe-helperSidecar, записывающий сертификаты на дискНет (sidecar пишет файлы)
Envoy SDSSPIRE Agent нативно поддерживает Envoy Secret Discovery ServiceКонфигурация Envoy
go-spiffe SDKПрограммный доступ через библиотекуИзменение кода (Go)

SPIFFE CSI Driver (рекомендуемый для Kubernetes) — монтирует Unix Domain Socket Workload API в контейнер рабочей нагрузки. Устраняет необходимость в hostPath volumes в pod-спецификациях рабочих нагрузок (hostPath часто запрещён политиками безопасности). Сам CSI Driver использует hostPath для связи с SPIRE Agent, но это ограничено инфраструктурным компонентом.

yaml
# Pod с доступом к Workload API через CSI Driver
apiVersion: v1
kind: Pod
metadata:
  name: my-workload
spec:
  serviceAccountName: payments-api
  containers:
  - name: app
    image: myregistry/payments-api:v1
    volumeMounts:
    - name: spiffe-workload-api
      mountPath: /spiffe-workload-api
      readOnly: true
    env:
    - name: SPIFFE_ENDPOINT_SOCKET
      value: unix:///spiffe-workload-api/spire-agent.sock
  volumes:
  - name: spiffe-workload-api
    csi:
      driver: "csi.spiffe.io"
      readOnly: true

Источники: SPIFFE CSI Driver, Working with SVIDs


Идентичность рабочих нагрузок в облаках

Каждый облачный провайдер предлагает собственный механизм идентификации рабочих нагрузок. Все три сходятся к OIDC-федерации, но различаются в деталях.

AWS: IAM Roles и Roles Anywhere

IAM Roles for Service Accounts (IRSA) — для EKS:

  • EKS-кластер предоставляет OIDC-провайдер
  • Kubernetes ServiceAccount аннотируется ARN IAM-роли
  • Pod получает projected service account token и обменивает его через STS на временные AWS-учётные данные

EKS Pod Identity (рекомендуется для новых EKS-кластеров):

  • AWS-managed контроллер и агент
  • Прямой маппинг pod → IAM role без обновления trust policy
  • Только для EKS (не для self-managed Kubernetes)

IAM Roles Anywhere — для рабочих нагрузок вне AWS:

  • Регистрация CA как trust anchor
  • Рабочая нагрузка предъявляет X.509-сертификат от этого CA
  • Вызывает CreateSession API, подписанный приватным ключом сертификата
  • Получает временные STS-учётные данные

Источники: AWS IRSA, IAM Roles Anywhere

GCP: Workload Identity Federation

Workload Identity Federation — позволяет внешним рабочим нагрузкам получать доступ к GCP API без статических service account keys:

  1. Создать Workload Identity Pool и Provider (OIDC или SAML 2.0)
  2. Настроить attribute mapping (внешние claims → GCP-атрибуты)
  3. Внешняя рабочая нагрузка обменивает свой токен через GCP Security Token Service (STS)
  4. STS возвращает краткосрочный OAuth 2.0 access token

Workload Identity Federation for GKE — упрощённая версия для GKE-подов, получающих GCP-идентичность через projected service account tokens.

Источники: GCP Workload Identity Federation, GKE Workload Identity

Azure: Managed Identity и Workload Identity

Managed Identity — для Azure-ресурсов:

  • System-assigned: привязана к жизненному циклу ресурса
  • User-assigned: независимый жизненный цикл, может использоваться несколькими ресурсами
  • Azure управляет получением, ротацией и отзывом токенов автоматически

Workload Identity Federation (Microsoft Entra) — для рабочих нагрузок вне Azure:

  • Federated Identity Credentials создают доверие между Entra ID и внешними OIDC-провайдерами
  • Поддержка GitHub Actions, Kubernetes, других облаков
  • Ожидаемый audience: api://AzureADTokenExchange

Источники: Azure Managed Identities, Entra Workload Identity Federation

Сравнение: SPIFFE vs облачные механизмы

АспектSPIFFE/SPIREAWS IRSA / Pod IdentityGCP WIFAzure Managed ID / WIF
ОбластьМультиоблако, on-premТолько AWSТолько GCPТолько Azure
Формат идентичностиX.509-SVID + JWT-SVIDJWT (STS)JWT (OAuth 2.0)JWT (Entra token)
mTLSНативный (X.509-SVID)НетНетНет
Не-K8s нагрузкиVM, bare metal, IoTEC2 Instance ProfileVM + WIF PoolsVM + Managed Identity
Открытый стандартДа (CNCF graduated)ПроприетарныйПроприетарныйПроприетарный
Кросс-облакоFederation APIТребует внешний OIDCПоддержка внешних OIDCПоддержка внешних OIDC

Ключевой вывод: облачные провайдеры сходятся к OIDC для федерации идентичностей. SPIRE включает OIDC Discovery Provider, который транслирует SPIFFE-идентичности в облачные системы — обеспечивая единый слой идентичности для всех платформ.

Источник: SPIRE OIDC Discovery Provider


Федерация между доменами доверия

Федерация позволяет рабочим нагрузкам в разных доменах доверия аутентифицировать друг друга. Каждый домен публикует свой SPIFFE Bundle через bundle endpoint.

Протокол федерации

Два профиля аутентификации bundle endpoint:

ПрофильАутентификацияПрименение
https_webСтандартный WebPKI (CA-signed certificate)Простая настройка
https_spiffeSPIFFE-аутентификация, требует endpoint_spiffe_idБолее строгая безопасность

Конфигурация федерации в SPIRE Server

hcl
# server.conf — SPIRE Server domain-a.example
server {
    trust_domain = "domain-a.example"
    # ...
}

federates_with "domain-b.example" {
    bundle_endpoint_url = "https://spire-server-b.example:8443"
    bundle_endpoint_profile "https_spiffe" {
        endpoint_spiffe_id = "spiffe://domain-b.example/spire/server"
    }
}

При обмене trust bundles приватные ключи не передаются — только публичные корневые сертификаты CA. Это фундаментальное отличие от VPN или shared secrets.

Источники: SPIFFE Federation Spec, Deploying Federated SPIRE


Lab: SPIRE на Kubernetes

В этой лабораторной работе мы развернём SPIRE на локальном Kubernetes-кластере (kind), зарегистрируем рабочую нагрузку и получим для неё X.509-SVID.

Предварительные требования

Шаг 1: Создание кластера

bash
# Создаём kind-кластер с двумя worker-нодами
cat <<EOF | kind create cluster --name spire-lab --config=-
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
- role: worker
- role: worker
EOF

Шаг 2: Установка SPIRE через Helm

bash
# Установка CRD (обязательно первым шагом)
helm upgrade --install --create-namespace -n spire-system \
  spire-crds spire-crds \
  --repo https://spiffe.github.io/helm-charts-hardened/

# Установка SPIRE stack
helm upgrade --install -n spire-system spire spire \
  --repo https://spiffe.github.io/helm-charts-hardened/ \
  --set global.spire.clusterName=spire-lab \
  --set global.spire.trustDomain=lab.example.org \
  --wait

Helm chart развёртывает: SPIRE Server (StatefulSet), SPIRE Agent (DaemonSet), SPIFFE CSI Driver, Controller Manager, OIDC Discovery Provider.

Источник: SPIRE Helm Charts Installation

Шаг 3: Проверка компонентов

bash
# Все поды SPIRE должны быть Running
kubectl -n spire-system get pods

# Ожидаемый вывод:
# spire-server-0                         1/1     Running
# spire-agent-xxxxx                      1/1     Running   (на каждой ноде)
# spire-spiffe-csi-driver-xxxxx          2/2     Running
# spire-spiffe-oidc-discovery-provider-  1/1     Running
# spire-controller-manager-xxxxx         1/1     Running

# Проверка здоровья SPIRE Server
kubectl exec -n spire-system spire-server-0 -- \
  /opt/spire/bin/spire-server healthcheck

Шаг 4: Автоматическая регистрация через ClusterSPIFFEID

SPIRE Controller Manager позволяет автоматически регистрировать рабочие нагрузки через CRD:

yaml
# clusterspiffeid-default.yaml
apiVersion: spire.spiffe.io/v1alpha1
kind: ClusterSPIFFEID
metadata:
  name: lab-workloads
spec:
  spiffeIDTemplate: >-
    spiffe://{{ .TrustDomain }}/ns/{{ .PodMeta.Namespace }}/sa/{{ .PodSpec.ServiceAccountName }}
  namespaceSelector:
    matchLabels:
      spire-enabled: "true"
bash
# Применяем CRD
kubectl apply -f clusterspiffeid-default.yaml

# Помечаем namespace для автоматической регистрации
kubectl create namespace workloads
kubectl label namespace workloads spire-enabled=true

Источник: ClusterSPIFFEID CRD

Шаг 5: Развёртывание тестовой рабочей нагрузки

yaml
# test-workload.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: test-workload
  namespace: workloads
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: test-workload
  namespace: workloads
spec:
  replicas: 1
  selector:
    matchLabels:
      app: test-workload
  template:
    metadata:
      labels:
        app: test-workload
    spec:
      serviceAccountName: test-workload
      containers:
      - name: client
        image: ghcr.io/spiffe/spire-agent:latest
        command: ["sleep", "infinity"]
        volumeMounts:
        - name: spiffe-workload-api
          mountPath: /spiffe-workload-api
          readOnly: true
        env:
        - name: SPIFFE_ENDPOINT_SOCKET
          value: unix:///spiffe-workload-api/spire-agent.sock
      volumes:
      - name: spiffe-workload-api
        csi:
          driver: "csi.spiffe.io"
          readOnly: true
bash
kubectl apply -f test-workload.yaml
kubectl -n workloads wait --for=condition=ready pod -l app=test-workload --timeout=60s

Шаг 6: Получение и проверка SVID

bash
# Получение X.509-SVID
kubectl exec -n workloads \
  $(kubectl get pod -n workloads -l app=test-workload \
    -o jsonpath='{.items[0].metadata.name}') \
  -c client -- \
  /opt/spire/bin/spire-agent api fetch x509 \
  -socketPath /spiffe-workload-api/spire-agent.sock

# Ожидаемый вывод:
# Received 1 svid after X.XXXs
#
# SPIFFE ID:    spiffe://lab.example.org/ns/workloads/sa/test-workload
# SVID Valid After:  2026-02-10 12:00:00 +0000 UTC
# SVID Valid Until:  2026-02-10 13:00:00 +0000 UTC    ← TTL = 1 час

# Просмотр registration entries
kubectl exec -n spire-system spire-server-0 -- \
  /opt/spire/bin/spire-server entry show

Шаг 7: Очистка

bash
kind delete cluster --name spire-lab

Что мы получили

  1. Автоматическая идентификация — рабочая нагрузка получила SPIFFE ID spiffe://lab.example.org/ns/workloads/sa/test-workload без хранения секретов
  2. Краткосрочные сертификаты — X.509-SVID с TTL 1 час, автоматическая ротация
  3. Аттестация — SPIRE убедился, что рабочая нагрузка запущена в правильном namespace с правильным ServiceAccount
  4. CSI Driver — безопасная доставка Workload API без hostPath volumes

В Главе 12 мы покажем, как SPIRE интегрируется с Istio для автоматического mTLS между сервисами. В Главе 22 — как федерация SPIRE объединяет идентичности AWS EKS и GCP GKE.


Итоги

Проблема NHIРешение SPIFFE/SPIRE
Статические секретыКриптографическая идентичность (X.509/JWT SVID) — нет паролей и API-ключей
Долгоживущие credentialsКраткосрочные SVID (SPIRE defaults: 1 час X.509, 5 минут JWT; настраивается)
Нет ротацииАвтоматическое обновление через Workload API до истечения срока
Нет аттестацииИдентичность подтверждается свойствами платформы (K8s SA, AWS Instance, PID), а не shared secret
Vendor lock-inОткрытый стандарт CNCF, федерация между облаками через bundle endpoints
Отсутствие governanceСтандартизированный формат SPIFFE ID: spiffe://trust-domain/path — аудируемый и единообразный

Опубликовано под лицензией CC BY-SA 4.0