# Безопасность Стек безопасности: HashiCorp Vault, External Secrets Operator, CrowdSec, Vaultwarden. ## HashiCorp Vault Централизованное управление секретами, PKI, динамические credentials. Подробный README: [addons/vault/README.md](../addons/vault/README.md). ### Быстрый старт ```yaml # group_vars/all/addons.yml addon_vault: true vault_mode: "standalone" # standalone | ha vault_auto_unseal_type: "none" # none | k8s | aws | gcp | azure | transit vault_injector_enabled: true # Vault Agent Injector vault_ingress_host: "vault-hc.example.com" vault_ingress_tls: true ``` ```bash make addon-vault ``` ### Режимы auto-unseal | Тип | Описание | Где хранятся ключи | |---|---|---| | `none` | Ручной unseal при каждом рестарте | Нигде — только у оператора | | `k8s` | Ключи в Kubernetes Secret + unsealer Pod | Secret `vault-unseal-keys` | | `aws` | AWS KMS | AWS KMS ключ | | `gcp` | Google Cloud KMS | GCP KMS ключ | | `azure` | Azure Key Vault | Azure Key Vault | | `transit` | Другой Vault (transit engine) | Другой Vault | Для homelab рекомендуется `k8s`: ```yaml vault_auto_unseal_type: "k8s" vault_auto_unseal_k8s_shares: 5 vault_auto_unseal_k8s_threshold: 3 ``` ### HA режим (3 ноды, Raft) ```yaml vault_mode: "ha" vault_ha_replicas: 3 vault_auto_unseal_type: "k8s" # обязателен для HA ``` ### Инициализация (первый запуск) После установки Ansible автоматически: 1. Инициализирует Vault (`vault operator init`) 2. Сохраняет ключи unseal в Secret (при `vault_auto_unseal_type: k8s`) 3. Unseals Vault 4. Выводит root token ### Vault Agent Injector — инжекция секретов в поды ```yaml # Аннотации на Pod/Deployment: annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "my-app" vault.hashicorp.com/agent-inject-secret-config.env: "secret/myapp/config" vault.hashicorp.com/agent-inject-template-config.env: | {{- with secret "secret/myapp/config" -}} DB_PASSWORD={{ .Data.data.db_password }} API_KEY={{ .Data.data.api_key }} {{- end }} ``` Секрет будет доступен в поде как `/vault/secrets/config.env`. ### Примеры: как подключать env в манифесты из HashiCorp Vault #### Вариант 1 — Vault Agent Injector + `source /vault/secrets/*.env` ```yaml apiVersion: apps/v1 kind: Deployment metadata: name: app-with-injector namespace: my-app spec: replicas: 1 selector: matchLabels: app: app-with-injector template: metadata: labels: app: app-with-injector annotations: vault.hashicorp.com/agent-inject: "true" vault.hashicorp.com/role: "my-app" vault.hashicorp.com/agent-inject-secret-app.env: "secret/data/myapp/config" vault.hashicorp.com/agent-inject-template-app.env: | {{- with secret "secret/data/myapp/config" -}} DB_PASSWORD={{ .Data.data.db_password }} API_KEY={{ .Data.data.api_key }} {{- end }} spec: serviceAccountName: my-app containers: - name: app image: ghcr.io/example/app:latest command: ["/bin/sh", "-c"] args: - | set -a . /vault/secrets/app.env set +a exec /app/start ``` #### Вариант 2 — Vault → ExternalSecret → `envFrom.secretRef` ```yaml apiVersion: external-secrets.io/v1beta1 kind: ExternalSecret metadata: name: app-env namespace: my-app spec: secretStoreRef: name: vault-backend kind: ClusterSecretStore target: name: app-env data: - secretKey: DB_PASSWORD remoteRef: key: secret/myapp property: db_password - secretKey: API_KEY remoteRef: key: secret/myapp property: api_key --- apiVersion: apps/v1 kind: Deployment metadata: name: app-with-envfrom namespace: my-app spec: template: spec: containers: - name: app image: ghcr.io/example/app:latest envFrom: - secretRef: name: app-env ``` #### Вариант 3 — отдельные env-переменные через `secretKeyRef` ```yaml env: - name: DB_PASSWORD valueFrom: secretKeyRef: name: app-env key: DB_PASSWORD - name: API_KEY valueFrom: secretKeyRef: name: app-env key: API_KEY ``` ### Kubernetes Auth Method ```bash # Включить Kubernetes auth в Vault: vault auth enable kubernetes vault write auth/kubernetes/config \ token_reviewer_jwt="$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)" \ kubernetes_host="https://$KUBERNETES_PORT_443_TCP_ADDR:443" \ kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt # Создать роль: vault write auth/kubernetes/role/my-app \ bound_service_account_names=my-app \ bound_service_account_namespaces=my-app \ policies=my-app-policy \ ttl=24h ``` ### Helm чарты с Vault секретами ```yaml # Chart values через External Secrets (рекомендуется) # или через Vault Agent annotations на Pod # Прямой pull из Vault (в init container): initContainers: - name: vault-auth image: vault:latest command: - sh - -c - | vault login -method=kubernetes role=my-app vault kv get -field=password secret/myapp/db > /vault/secrets/db-password env: - name: VAULT_ADDR value: "http://vault.vault.svc.cluster.local:8200" volumeMounts: - name: vault-secrets mountPath: /vault/secrets ``` --- ## External Secrets Operator Синхронизирует секреты из Vault в Kubernetes Secrets автоматически. Подробный README: [addons/external-secrets/README.md](../addons/external-secrets/README.md). ### Быстрый старт ```yaml addon_external_secrets: true addon_vault: true # рекомендуется — ESO настраивается на Vault автоматически external_secrets_vault_url: "http://vault.vault.svc.cluster.local:8200" external_secrets_vault_role_id: "xxx" # после создания AppRole в Vault ``` Секрет в `vault.yml`: ```yaml vault_eso_approle_secret_id: "xxx" ``` ### Создать AppRole в Vault ```bash vault auth enable approle vault policy write eso-policy - <