English translation is not available yet. Showing Russian content.
Как вы управляете секретами (API keys для LLM) в Kubernetes?
Краткий тезис
Управление секретами (API‑keys, токены доступа) в Kubernetes требует строгой изоляции от кода и конфигураций. Основной подход — использование Secrets Operator|External Secrets Operator (ESO) для синхронизации ключей из внешнего хранилища (Vault, Secrets Manager|Secrets Manager|AWS Secrets Manager|Secrets Manager) напрямую в Kubernetes Secrets. Никогда не храните ключи в values.yaml, ConfigMap или в репозитории кода. Ротация секретов, разграничение доступа с помощью RBAC и аудит всех запросов — обязательные элементы безопасности.
1. Проблема: почему API‑keys — особая зона риска в Kubernetes
API‑keys для LLM (например, OpenAI, Anthropic) — это критичные учётные данные. Если они скомпрометированы, злоумышленник может:
- генерировать ответы от вашего имени, тратя ваш бюджет;
- получить доступ к приватным данным, если LLM используется в приложении.
В Kubernetes стандартный объект Secret хранит данные в base64 — это не шифрование, только кодирование. Без дополнительных мер любой, у кого есть доступ к etcd или права get secret, может прочитать ключи.
Черновик подсказывает:
- Не хранить секреты в values.yaml или в коде.
- Использовать External Secrets Operator.
- Ротация через ESO.
- Доступ через RBAC.
- Аудит.
Расширим каждый пункт.
2. Инструменты для управления секретами в Kubernetes
| Инструмент | Описание | Плюсы | Минусы |
|---|---|---|---|
| External Secrets Operator (ESO) | Синхронизирует секреты из внешнего провайдера (Vault, AWS, GCP, Azure) в Kubernetes Secrets. | Бесплатный, облачный/on‑prem, автоматическая ротация, CRD. | Требуется настройка провайдера. |
| Secrets Store CSI Driver | Монтирует секреты как volume в Pod. | Нет копирования секретов в etcd, можно использовать с любым провайдером. | Сложнее в настройке, не все приложения поддерживают чтение из файлов. |
| Vault Agent Injector | Инжектирует sidecar, который разворачивает секреты в Pod. | Интеграция с Vault, динамические секреты. | Vendor‑lock, дополнительный ресурс sidecar. |
| Встроенные Kubernetes Secrets | Объект Secret. | Встроено, просто. | Base64, сложная ротация, нет внешнего источника. |
Рекомендация: для большинства production‑систем используйте ESO + HashiCorp Vault или AWS Secrets Manager — это даёт централизованное хранение, ротацию и аудит.
3. Термин: External Secrets Operator (ESO)
External Secrets Operator (ESO) — это Custom Resource Definition (CRD) для Kubernetes, который синхронизирует секреты из внешних источников в объекты Secret. ESO запускается как контроллер в кластере.
Как он работает:
- Вы создаёте ресурс
ExternalSecret, в котором указываете провайдера (например, Vault) и ключ для загрузки. - ESO читает значение из провайдера, создаёт или обновляет Kubernetes Secret с этим значением.
- При изменении секрета в провайдере ESO автоматически обновляет Secret в кластере (если настроен refreshInterval).
Пример манифеста для ESO с Vault:
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: llm-api-key
spec:
refreshInterval: "1h"
secretStoreRef:
name: vault-backend
kind: SecretStore
target:
name: openai-key # имя создаваемого Kubernetes Secret
creationPolicy: Owner
data:
- secretKey: api-key # ключ внутри создаваемого Secret
remoteRef:
key: secret/data/llm # путь в Vault
property: openai_api_key
После применения этого манифеста ESO создаст Secret/openai-key с ключом api-key.
4. Термин: SecretStore и ClusterSecretStore
SecretStore — ресурс ESO, определяющий, как подключиться к внешнему хранилищу (Vault, AWS Secrets Manager, etc.). ClusterSecretStore работает на уровне кластера (не namespace).
Пример для AWS Secrets Manager:
apiVersion: external-secrets.io/v1beta1
kind: SecretStore
metadata:
name: aws-secrets-store
spec:
provider:
aws:
service: SecretsManager
region: us-east-1
auth:
jwt:
serviceAccountRef:
name: my-service-account
Рекомендуется использовать ClusterSecretStore с IRSA (IAM Roles for Service Accounts) в AWS — это связывает сервис‑аккаунт Pod с IAM‑ролью без встроенных ключей AWS.
5. Ротация секретов (Rotation)
Ротация — периодическая смена API‑keys для снижения риска компрометации. ESO поддерживает автоматическую ротацию:
- Вы задаёте
refreshInterval(например,1h). - ESO каждые
refreshIntervalпроверяет, изменился ли секрет во внешнем хранилище. - Если изменился — ESO обновляет соответствующий Kubernetes Secret.
- Pod, который использует этот Secret, должен перезагрузиться, чтобы подхватить новое значение.
Проблема: простой Kubernetes не перезапускает Pod при изменении Secret. Решения:
- Stakater Reloader — наблюдатель, который при изменении Secret перезапускает Deployment.
- Rolling update вручную.
- Secrets Store CSI Driver — секрет монтируется как том, Pod видит изменения без перезапуска (если приложение читает файл повторно).
Пример с Reloader:
metadata:
annotations:
stakater.com/reload-on-change: "true"
6. Разграничение доступа: RBAC, ServiceAccount
RBAC (Role‑Based Access Control) в Kubernetes позволяет ограничить, какие Pod могут читать конкретные Secret.
Best practice:
- Создайте отдельный ServiceAccount для Pod, которому нужен доступ к LLM‑ключам.
- Создайте Role с правами
get,list,watchна нужный Secret. - Создайте RoleBinding, привязывающую ServiceAccount к Role.
- В Pod укажите
serviceAccountName.
apiVersion: v1
kind: ServiceAccount
metadata:
name: llm-app-sa
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: secret-reader
rules:
- apiGroups: [""]
resources: ["secrets"]
resourceNames: ["openai-key"]
verbs: ["get", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: llm-app-read-key
subjects:
- kind: ServiceAccount
name: llm-app-sa
roleRef:
kind: Role
name: secret-reader
apiGroup: rbac.authorization.k8s.io
Никакой другой Pod (кроме этого ServiceAccount) не сможет прочитать ключ.
7. Аудит доступа к секретам
Аудит позволяет отследить, кто и когда запрашивал секрет. Для этого:
- Включите аудитные логи Kubernetes API‑сервера (уровень
RequestResponse). - Внешнее хранилище (Vault, AWS Secrets Manager) предоставляет собственные логи доступа.
- Используйте инструменты вроде Falco для обнаружения подозрительного доступа.
Пример настройки аудита в Kubernetes:
apiVersion: apiserver.config.k8s.io/v1
kind: AuditConfiguration
metadata:
name: audit-config
rules:
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
Логи нужно отправлять в централизованную систему (Elasticsearch, Splunk) для анализа.
8. Практическая реализация в Agentic RAG‑системе
Предположим, у нас есть микросервис llm‑inference, который вызывает API OpenAI. Нам нужно передать ему ключ.
Шаги:
- Создайте секрет во внешнем хранилище: например, в Vault
secret/data/llmс ключомopenai_api_key. - Установите ESO в кластер (
helm install external-secrets ...). - Определите SecretStore (ссылку на Vault) или ClusterSecretStore.
- Создайте ExternalSecret, который будет синхронизировать
openai_api_keyв Kubernetes Secretopenai-key. - Настройте ServiceAccount, Role, RoleBinding для вашего Pod.
- В Pod используйте монтирование Secret как переменные окружения:
apiVersion: apps/v1 kind: Deployment spec: template: spec: serviceAccountName: llm-app-sa containers: - name: llm-inference env: - name: OPENAI_API_KEY valueFrom: secretKeyRef: name: openai-key key: api-key - Добавьте Reloader для автоматического перезапуска при смене ключа.
Почему не хранить в env в манифесте? — Манифест часто хранится в Git (GitOps), и ключ попадёт в историю коммитов.
9. Альтернативы и их ограничения
- helm secrets / sops — шифрует values.yaml, но расшифровка требует доступа к ключам вне кластера. Подходит для GitOps, но не решает ротацию.
- Vault Agent Sidecar — хорош для динамических секретов, но усложняет архитектуру.
- Sealed Secrets by Bitnami — шифрует Secret в Git, расшифровывается контроллером в кластере. Удобно, но не централизованное хранение.
Для production с Agentic RAG (где может быть несколько сервисов с LLM‑ключами) лучший выбор — ESO + Vault.
10. Типичные ошибки и как их избежать
| Ошибка | Последствия | Решение |
|---|---|---|
| Хранение ключа в ConfigMap или env в Docker‑образе | Ключ виден всем, кто имеет доступ к образу или логам | Использовать Secret и монтирование |
| Не задан refreshInterval в ESO | Секрет не обновляется автоматически | Указать refreshInterval |
Раздача прав get secret на уровне кластера | Любой разработчик может читать ключи | Использовать RBAC с resourceNames |
| Отсутствие аудита | Невозможно узнать, кто украл ключ | Включить аудит и настроить мониторинг |
| Ключ передаётся через env Pod без перезапуска при смене | Pod использует старый ключ до перезапуска | Использовать Reloader или CSI driver |
Пет-проект для закрепления
Задача: Развернуть локальный Minikube + Vault в dev‑режиме, настроить ESO для синхронизации фейкового OpenAI‑ключа и развернуть небольшое приложение (например, FastAPI), которое вызывает OpenAI API через смонтированный секрет.
Инструменты:
- Minikube или Kind (локальный кластер).
- Helm для установки ESO.
- HashiCorp Vault (запустить через helm или docker).
- FastAPI + Python.
Шаги:
- Запустите Minikube:
minikube start. - Установите Vault через Helm.
- Включите Vault в dev‑режиме (
vault server -devили через helm сserver.dev.enabled=true). - Положите в Vault ключ:
vault kv put secret/llm openai_api_key=sk-test123. - Установите ESO:
helm repo add external-secrets https://charts.external-secrets.io && helm install external-secrets external-secrets/external-secrets. - Создайте SecretStore, указывающий на Vault (с нужным токеном).
- Создайте ExternalSecret, как в примере выше.
- Разверните простое FastAPI приложение, которое читает
OPENAI_API_KEYиз окружения и делает тестовый запрос (можно к mock‑серверу, чтобы не тратить реальные деньги). - Настройте ServiceAccount, Role, RoleBinding.
- Проверьте, что ключ доступен только вашему Pod.
Ожидаемый результат: Приложение успешно запускается, видит ключ, а любой другой Pod не может его прочитать. При изменении ключа в Vault через refreshInterval (или вручную) секрет обновляется, а Pod с Reloader перезапускается.
Связь с другими вопросами
| Вопрос | Тема |
|---|---|
| 420 | Общая архитектура Agentic RAG, где требуются API‑ключи |
| 421 | Память агентов, где тоже могут быть секреты для внешних инструментов |
| 419 | Тестирование, включая проверку доступа к секретам |
| 400 | Определение Agentic RAG, где LLM используется как агент |
| 423 | Rate limits — тоже часть управления API‑ключами (квоты) |
| 410 | Многопоточные системы, где секреты нужно распределять |
Навигация
- Предыдущий: 421
- Следующий: 423
- Индекс: 00. Индекс разборов