Шпаргалка по работе с HashiCorp Vault в Kubernetes

Установка и настройка

Установка Vault через Helm

Добавление репозитория HashiCorp:

helm repo add hashicorp https://helm.releases.hashicorp.com

Обновление репозитория:

helm repo update

Установка Vault с базовыми настройками:

helm install vault hashicorp/vault

Установка с кастомными значениями:

helm install vault hashicorp/vault -f values.yaml

Обновление существующей установки:

helm upgrade vault hashicorp/vault -f values.yaml

Установка Vault через Kustomize

Применение kustomize для установки Vault:

kubectl apply -k vault-kustomize/overlays/prod

Установка в конкретный namespace:

kubectl apply -k vault-kustomize/overlays/prod -n vault-ns

Проверка установки

Проверка запущенных подов:

kubectl get pods -l app.kubernetes.io/name=vault

Проверка сервисов:

kubectl get services -l app.kubernetes.io/name=vault

Проверка статуса инициализации Vault:

kubectl exec -it vault-0 -- vault status

Базовые операции

Настройка локального доступа

Port-forward к поду Vault:

kubectl port-forward vault-0 8200:8200

Настройка переменных окружения:

export VAULT_ADDR=http://127.0.0.1:8200
export VAULT_TOKEN=<ваш-токен>

Проверка соединения:

vault status

Инициализация Vault

Инициализация хранилища с 5 ключами (3 необходимо для распечатывания):

vault operator init -key-shares=5 -key-threshold=3

Инициализация через kubectl:

kubectl exec -it vault-0 -- vault operator init -key-shares=5 -key-threshold=3

Базовые команды CLI

Проверка статуса:

vault status

Просмотр списка типов доступных секретов:

vault secrets list

Просмотр списка методов аутентификации:

vault auth list

Просмотр списка политик:

vault policy list

Аутентификация

Kubernetes Auth

Включение аутентификации Kubernetes:

vault auth enable kubernetes

Настройка Kubernetes Auth:

vault write auth/kubernetes/config \
    kubernetes_host="https://kubernetes.default.svc:443" \
    kubernetes_ca_cert=@/var/run/secrets/kubernetes.io/serviceaccount/ca.crt \
    token_reviewer_jwt=@/var/run/secrets/kubernetes.io/serviceaccount/token

Создание роли для сервисного аккаунта:

vault write auth/kubernetes/role/my-app \
    bound_service_account_names=my-app \
    bound_service_account_namespaces=default \
    policies=my-app-policy \
    ttl=1h

Использование Kubernetes Auth в поде

Получение JWT токена:

JWT=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)

Аутентификация и получение клиентского токена:

curl -s --request POST \
    --data "{\"jwt\": \"$JWT\", \"role\": \"my-app\"}" \
    http://vault-service:8200/v1/auth/kubernetes/login | jq -r '.auth.client_token'

Другие методы аутентификации

Включение LDAP-аутентификации:

vault auth enable ldap

Включение GitHub-аутентификации:

vault auth enable github

Включение AppRole-аутентификации:

vault auth enable approle

Секреты

Key-Value (KV) секреты

Включение kv-v2 движка секретов:

vault secrets enable -version=2 kv

Создание секрета:

vault kv put kv/my-app/config username=admin password=secret

Чтение секрета:

vault kv get kv/my-app/config

Чтение конкретного поля секрета:

vault kv get -field=password kv/my-app/config

Обновление секрета:

vault kv put kv/my-app/config username=admin password=new-secret

Удаление текущей версии секрета:

vault kv delete kv/my-app/config

Удаление всех версий и метаданных секрета:

vault kv metadata delete kv/my-app/config

Динамические секреты (Базы данных)

Включение движка secrets для базы данных:

vault secrets enable database

Настройка подключения к PostgreSQL:

vault write database/config/my-postgresql \
    plugin_name=postgresql-database-plugin \
    allowed_roles="my-role" \
    connection_url="postgresql://{{username}}:{{password}}@postgres:5432/postgres" \
    username="postgres" \
    password="password"

Создание роли для генерации учетных данных:

vault write database/roles/my-role \
    db_name=my-postgresql \
    creation_statements="CREATE ROLE \"{{name}}\" WITH LOGIN PASSWORD '{{password}}' VALID UNTIL '{{expiration}}'; GRANT SELECT ON ALL TABLES IN SCHEMA public TO \"{{name}}\";" \
    default_ttl="1h" \
    max_ttl="24h"

Получение временных учетных данных:

vault read database/creds/my-role

Секреты API-ключей

Включение Kubernetes Secrets Engine для хранения API-ключей:

vault secrets enable -path=api-keys kv-v2

Добавление API-ключа:

vault kv put api-keys/github token=ghp_12345abcde

Получение API-ключа:

vault kv get api-keys/github

Политики

Создание и управление политиками

Создание политики из HCL-файла:

vault policy write my-policy policy.hcl

Создание политики из stdin:

cat <<EOF | vault policy write my-policy -
path "kv/data/my-app/*" {
  capabilities = ["read", "list"]
}
path "database/creds/my-role" {
  capabilities = ["read"]
}
EOF

Просмотр политики:

vault policy read my-policy

Удаление политики:

vault policy delete my-policy

Примеры политик

Политика только для чтения KV-секретов:

path "kv/data/my-app/*" {
  capabilities = ["read", "list"]
}

Политика для управления KV-секретами:

path "kv/data/my-app/*" {
  capabilities = ["create", "read", "update", "delete", "list"]
}
path "kv/metadata/my-app/*" {
  capabilities = ["list"]
}

Политика для динамических баз данных:

path "database/creds/my-role" {
  capabilities = ["read"]
}

Политика для создания временных токенов:

path "auth/token/create" {
  capabilities = ["update"]
}

Kubernetes интеграция

Инъекция секретов через Vault Agent

Пример аннотаций для пода:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
  annotations:
    vault.hashicorp.com/agent-inject: "true"
    vault.hashicorp.com/agent-inject-secret-config.json: "kv/data/my-app/config"
    vault.hashicorp.com/agent-inject-template-config.json: |
      {{ with secret "kv/data/my-app/config" }}
      {
        "username": "{{ .Data.data.username }}",
        "password": "{{ .Data.data.password }}"
      }
      {{ end }}
    vault.hashicorp.com/role: "my-app"
spec:
  serviceAccountName: my-app
  containers:
  - name: app
    image: my-app:latest

Bank-Vaults Operator

Пример CRD для Vault:

apiVersion: vault.banzaicloud.com/v1alpha1
kind: Vault
metadata:
  name: vault
spec:
  size: 1
  image: vault:1.9.0
  bankVaultsImage: banzaicloud/bank-vaults:latest
  annotations:
    prometheus.io/scrape: "true"
    prometheus.io/port: "9102"

CSI драйвер для секретов

Пример использования CSI Driver:

apiVersion: v1
kind: Pod
metadata:
  name: my-app
spec:
  containers:
  - name: app
    image: my-app:latest
    volumeMounts:
    - name: secrets
      mountPath: "/app/secrets"
      readOnly: true
  volumes:
  - name: secrets
    csi:
      driver: secrets-store.csi.k8s.io
      readOnly: true
      volumeAttributes:
        secretProviderClass: "vault-db-creds"

Управление сертификатами

Настройка PKI

Включение PKI движка секретов:

vault secrets enable pki

Установка TTL для корневого сертификата:

vault secrets tune -max-lease-ttl=87600h pki

Генерация корневого сертификата:

vault write pki/root/generate/internal \
    common_name="example.com" \
    ttl=87600h

Создание роли для выдачи сертификатов:

vault write pki/roles/my-app \
    allowed_domains="my-app.example.com" \
    allow_subdomains=true \
    max_ttl=72h

Выпуск сертификатов

Запрос сертификата:

vault write pki/issue/my-app \
    common_name="service.my-app.example.com" \
    ttl="24h"

Чтение CA-сертификата:

vault read -field=certificate pki/cert/ca > ca.crt

Отладка

Отладочный под для Vault

Отладочный под с Vault CLI и основными инструментами:

apiVersion: v1
kind: Pod
metadata:
  name: vault-debug
spec:
  containers:
  - name: debug
    image: alpine:3.15
    command: ["/bin/sh", "-c"]
    args:
    - |
      apk add --no-cache curl jq vault
      echo "Waiting for commands..."
      sleep 3600
    env:
    - name: VAULT_ADDR
      value: "http://vault-service:8200"
    resources:
      limits:
        memory: "128Mi"
        cpu: "100m"
  serviceAccountName: default

Проверка работоспособности Vault

Проверка состояния и готовности:

kubectl exec -it vault-0 -- vault status

Проверка аутентификации:

kubectl exec -it vault-debug -- sh -c "
  export VAULT_TOKEN=<ваш-токен>
  vault token lookup
"

Проверка доступа к секретам:

kubectl exec -it vault-debug -- sh -c "
  export VAULT_TOKEN=<ваш-токен>
  vault kv get kv/my-app/config
"

Использование API напрямую через curl:

kubectl exec -it vault-debug -- sh -c "
  curl -s --header \"X-Vault-Token: <ваш-токен>\" \
  http://vault-service:8200/v1/sys/health | jq
"

Резервное копирование

Снапшот Raft-хранилища

Создание снапшота:

vault operator raft snapshot save snapshot.bak

Восстановление из снапшота:

vault operator raft snapshot restore snapshot.bak

Резервное копирование через kubectl

Сохранение снапшота из пода Vault:

kubectl exec -it vault-0 -- vault operator raft snapshot save snapshot.bak
kubectl cp vault-0:snapshot.bak ./vault-backup-$(date +%F).bak

Сохранение root-токена и ключей:

kubectl -n vault-ns get secret vault-root-token -o jsonpath='{.data.root_token}' | base64 --decode > vault-root-token.txt
kubectl -n vault-ns logs job/vault-bootstrap | grep "Unseal Key" > vault-unseal-keys.txt

Запечатывание/Распечатывание

Распечатывание Vault

Распечатывание через UI:

http://localhost:8200/ui

Распечатывание через CLI:

vault operator unseal <ключ-1>
vault operator unseal <ключ-2>
vault operator unseal <ключ-3>

Распечатывание через kubectl:

kubectl exec -it vault-0 -- vault operator unseal <ключ>

Запечатывание Vault (экстренная ситуация)

Запечатывание хранилища:

vault operator seal

Запечатывание через kubectl:

kubectl exec -it vault-0 -- vault operator seal

Auto-Unseal через AWS KMS

Пример конфигурации для Auto-Unseal:

apiVersion: vault.banzaicloud.com/v1alpha1
kind: Vault
metadata:
  name: vault
spec:
  size: 3
  config:
    seal:
      awskms:
        region: us-east-1
        kms_key_id: "alias/vault-unseal-key"