Как вы интегрировали HashiCorp Vault в Kubernetes?

Ответ

Я интегрировал Vault в Kubernetes для безопасного управления секретами, используя два основных подхода в production-среде.

1. Vault Agent Injector (для статических секретов): Это sidecar-контейнер, который автоматически внедряет секреты в под как файлы или переменные окружения.

  • Установка через Helm:
    helm install vault hashicorp/vault 
    --set "server.ha.enabled=true" 
    --set "injector.enabled=true"
  • Конфигурация через аннотации в манифесте пода:
    apiVersion: v1
    kind: Pod
    metadata:
    name: my-app
    annotations:
    vault.hashicorp.com/agent-inject: 'true'
    vault.hashicorp.com/role: 'myapp-role' # Роль Kubernetes для аутентификации
    vault.hashicorp.com/agent-inject-secret-db-creds: 'database/creds/my-role'
    vault.hashicorp.com/agent-inject-template-db-creds: |
      {{- with secret "database/creds/my-role" -}}
      {{ .Data.username }}
      {{ .Data.password }}
      {{- end }}
    spec:
    serviceAccountName: my-app-sa # ServiceAccount, привязанный к роли Vault
    containers:
    - name: app
    image: my-app:latest

2. CSI Provider (для динамических секретов): Идеально подходит для баз данных, где нужны кратковременные учетные данные. Секреты монтируются как том и автоматически обновляются.

  • Включение CSI Provider:
    helm install vault hashicorp/vault 
    --set "csi.enabled=true"
  • Создание SecretProviderClass:
    apiVersion: secrets-store.csi.x-k8s.io/v1
    kind: SecretProviderClass
    metadata:
    name: db-dynamic-creds
    spec:
    provider: vault
    parameters:
    vaultAddress: "http://vault-active.vault.svc.cluster.local:8200"
    roleName: "db-admin"
    objects: |
      - objectPath: "database/creds/my-dynamic-role"
        secretKey: "password"

Ключевые настройки для продакшена, которые я выполнял:

  • Аутентификация через Kubernetes ServiceAccount: Настраивал в Vault kubernetes auth method, связывая K8s namespaces и service accounts с политиками Vault.
  • High Availability (HA): Запускал Vault в HA-режиме с Consul или Integrated Storage (Raft).
  • TLS и mTLS: Настраивал внутренний и внешний TLS для всего трафика, включая взаимную аутентификацию между Vault и injector/CSI.
  • Политики с наименьшими привилегиями: Тщательно прорабатывал политики Vault, выдавая приложениям доступ только к конкретным путям секретов.

Ответ 18+ 🔞

Э, слушай, история про то, как я Vault в кубер прикручивал. Ёпта, это отдельная сага, чувак. В общем, сидишь такой, думаешь: «Э бошка, думай!» Как секреты в продакшене хранить, чтобы не было потом «хиросимы и нигерсраки», если какой-нибудь «пидарас шерстяной» в кластер проберётся. Ну, Vault — штука мощная, но и возни с ним, бля, овердохуища.

Вот смотри, я юзал два основных подхода, чтобы не быть «распиздяем».

1. Vault Agent Injector (для статичных секретиков типа ключей API). Это такая «мартышлюшка»-сайдкар, которая тебе в под лезет и тихонько подкладывает секреты прямо в файлы или переменные окружения. Удобно, ёбать копать. Ставится через Helm — раз плюнуть.

helm install vault hashicorp/vault 
  --set "server.ha.enabled=true" 
  --set "injector.enabled=true"

А потом в манифесте своего пода навешиваешь аннотации, и он всё делает сам. Главное — ServiceAccount правильно привязать к роли в Vault, а то будет «доверия ебать ноль».

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  annotations:
    vault.hashicorp.com/agent-inject: 'true'
    vault.hashicorp.com/role: 'myapp-role'
    vault.hashicorp.com/agent-inject-secret-db-creds: 'database/creds/my-role'
    vault.hashicorp.com/agent-inject-template-db-creds: |
      {{- with secret "database/creds/my-role" -}}
      {{ .Data.username }}
      {{ .Data.password }}
      {{- end }}
spec:
  serviceAccountName: my-app-sa
  containers:
  - name: app
    image: my-app:latest

2. CSI Provider (для динамических секретов, типа паролей от БД, которые живут пять минут). Вот это, бля, вообще песня! Для баз данных — то, что доктор прописал. Секреты монтируются как том и сами по себе обновляются, как только срок жизни подходит к концу. Чувствуешь разницу? Не нужно приложение перезапускать. Включил — и забыл.

helm install vault hashicorp/vault 
  --set "csi.enabled=true"

Потом создаёшь SecretProviderClass, где указываешь, что и куда монтировать. Смотри, как просто:

apiVersion: secrets-store.csi.x-k8s.io/v1
kind: SecretProviderClass
metadata:
  name: db-dynamic-creds
spec:
  provider: vault
  parameters:
    vaultAddress: "http://vault-active.vault.svc.cluster.local:8200"
    roleName: "db-admin"
    objects: |
      - objectPath: "database/creds/my-dynamic-role"
        secretKey: "password"

А теперь, чувак, самое важное — что я в продакшене настраивал, чтобы не «накрыться медным тазом».

  • Аутентификация через ServiceAccount: В Vault включаешь kubernetes auth method и начинаешь вязать K8s неймспейсы и service accounts с политиками Vault. Чтобы приложение из default не могло достучаться до секретов из production. Иначе — пиздец.
  • High Availability (HA): Запускать Vault в одном экземпляре — это, прости, «мудя» полная. Обязательно в HA-режиме, либо с Consul, либо со своим Raft storage. Чтобы если одна нода легла — остальные работали.
  • TLS и mTLS: Это святое, бля. Весь трафик — и внешний, и внутренний — должен шифроваться. А между Vault и его инжектором/CSI-провайдером я ещё и mTLS настроил, взаимную аутентификацию. Чтобы никакой левый «хуй с горы» не мог притвориться инжектором и стырить все пароли.
  • Политики с наименьшими привилегиями: Вот тут мозги надо включать. В Vault политики пишешь так, чтобы приложение могло читать ТОЛЬКО свой конкретный путь. Не database/*, а строго database/creds/my-app-role. Иначе получится «во все дыры давалка» — любая скомпрометированная поделка получит доступ ко всему. «Подозрение ебать чувствую», когда вижу широкие политики.

В общем, работа не для слабаков. Но когда всё взведено и работает, а ты знаешь, что твои секреты в безопасности — это, бля, такое чувство, «сам от себя охуел». Главное — не расслабляться и следить за обновлениями, а то «будет вам хиросима».