Makefile - Уникальные имена контейнеров на каждый вызов make (ANSIBLE_RUN_ID); переопределение через ANSIBLE_CONTAINER_NAME / MOLECULE_CONTAINER_NAME; отдельное имя для Molecule, чтобы k3s-ansible и molecule не конфликтовали. - Старые цели molecule-prometheus и molecule-istio переведены на molecule-addon (prometheus-stack, istio); добавлены явные molecule-addon-prometheus-stack и molecule-addon-istio; в molecule-addon-all включены prometheus-stack и istio (полный набор аддонов), скорректированы подписи. - Phony-таргет dashboard (без внесения кода в dashboard/ в этот коммит). Сценарии Molecule (converge/verify) — десятки аддонов - Добавлены/выровнены переменные и шаблоны под текущие роли (harbor, hysteria2, ingress-*, jenkins, mediaserver, netbird, nextcloud, splitgw, vault, vaultwarden и др.). - Helm/файлы на хост: delegate_to: localhost, run_once где уместно (technitium-dns, yandex-dns-controller); verify на localhost для file-based проверок. - Уточнения проверок: metrics-server, minio, promtail, pushgateway, velero (bool из фактов/строк), splitgw (JSON, поиск портов/DNS-правил в структуре). - В meta ролей: prometheus_stack + namespace, istio + namespace; у istio согласованы converge/verify (в т.ч. метрики, ослаблены жёсткие assert под шаблоны Kiali). - csi-nfs: комментарий к volume_binding_mode (Immediate / WaitForFirstConsumer). Инфраструктура - .gitignore: каталог dashboard/ (локальная копия не в репозитории). - docker-compose: убрано фиксированное container_name для параллельных ; TZ по умолчанию Europe/Moscow. - roles/k3s/tasks/prereqs.yml: повторные попытки update_cache и apt install при кратковременных сбоях зеркал/сети.
HashiCorp Vault
Self-hosted менеджер секретов с шифрованием, аудитом и fine-grained политиками доступа.
Установка
# Standalone (по умолчанию, 1 Pod)
make addon-vault
# HA (3 Pods с Raft, нужны минимум 3 ноды)
make addon-vault ARGS="-e vault_mode=ha"
# С авто-unseal через k8s Secret (homelab/dev)
make addon-vault ARGS="-e vault_auto_unseal_type=k8s"
# С AWS KMS авто-unseal (production)
make addon-vault ARGS="-e vault_auto_unseal_type=aws -e vault_aws_kms_region=us-east-1 -e vault_aws_kms_key_id=..."
# С Ingress
make addon-vault ARGS="-e vault_ingress_enabled=true -e vault_ingress_host=vault.example.com"
Первичная инициализация (ручной режим)
После установки Vault нужно инициализировать (только один раз):
# Инициализация (генерирует unseal keys + root token)
kubectl exec -n vault vault-0 -- vault operator init \
-key-shares=5 \
-key-threshold=3
# ВАЖНО: сохрани 5 unseal keys и root token в надёжное место!
# Пример вывода:
# Unseal Key 1: abc...
# Unseal Key 2: def...
# ...
# Initial Root Token: hvs.xxxxx
# Unseal (нужно подать 3 из 5 ключей)
kubectl exec -n vault vault-0 -- vault operator unseal <key1>
kubectl exec -n vault vault-0 -- vault operator unseal <key2>
kubectl exec -n vault vault-0 -- vault operator unseal <key3>
# Проверка
kubectl exec -n vault vault-0 -- vault status
Авто-unseal режимы
k8s Secret (homelab, не для production)
make addon-vault ARGS="-e vault_auto_unseal_type=k8s"
Vault автоматически инициализируется и unseal keys сохраняются в k8s Secret vault-unseal-keys.
Unsealer Deployment следит за состоянием и unseals при перезапуске.
Получить root token:
kubectl get secret vault-unseal-keys -n vault \
-o jsonpath='{.data.root_token}' | base64 -d
AWS KMS (production)
# group_vars/all/addons.yml
vault_auto_unseal_type: "aws"
vault_aws_kms_region: "us-east-1"
vault_aws_kms_key_id: "arn:aws:kms:us-east-1:..."
# group_vars/all/vault.yml
vault_aws_kms_access_key: "AKIAIOSFODNN7EXAMPLE"
vault_aws_kms_secret_key: "wJalrXUtnFEMI/K7MDENG/..."
Transit Seal (через другой Vault)
vault_auto_unseal_type: "transit"
vault_transit_address: "https://vault-primary.example.com"
vault_transit_key_name: "autounseal"
# vault.yml:
vault_transit_seal_token: "hvs.CAESIxxxxxx"
Работа с секретами
CLI (локально через port-forward)
# Port-forward
kubectl port-forward -n vault svc/vault 8200:8200 &
# Авторизация
export VAULT_ADDR=http://localhost:8200
vault login <root_token>
# Включить KV v2 engine
vault secrets enable -path=secret kv-v2
# Записать секрет
vault kv put secret/myapp/config \
db_password="supersecret" \
api_key="abc123"
# Прочитать секрет
vault kv get secret/myapp/config
vault kv get -field=db_password secret/myapp/config
CLI (из пода в кластере)
kubectl exec -n vault vault-0 -- env VAULT_ADDR=http://localhost:8200 \
vault kv put secret/myapp/config db_password="supersecret"
Kubernetes Auth Method
Позволяет подам авторизоваться через их ServiceAccount токен:
# Включить kubernetes auth
vault auth enable kubernetes
# Настроить
vault write auth/kubernetes/config \
kubernetes_host="https://kubernetes.default.svc.cluster.local:443"
# Создать политику доступа
vault policy write myapp-policy - <<EOF
path "secret/data/myapp/*" {
capabilities = ["read"]
}
EOF
# Создать роль (привязка: namespace + serviceaccount → policy)
vault write auth/kubernetes/role/myapp-role \
bound_service_account_names="myapp-sa" \
bound_service_account_namespaces="myapp" \
policies="myapp-policy" \
ttl="1h"
Vault Agent Injector — секреты в YAML манифестах
Injector (установлен по умолчанию) автоматически монтирует секреты через sidecar по annotations.
Пример Pod с автоинжекцией секретов
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
namespace: myapp
spec:
template:
metadata:
annotations:
# Включаем инжектор
vault.hashicorp.com/agent-inject: "true"
# Адрес Vault (по умолчанию авто-определяется)
vault.hashicorp.com/role: "myapp-role"
# Инжектировать секрет как файл /vault/secrets/config
vault.hashicorp.com/agent-inject-secret-config: "secret/data/myapp/config"
# Шаблон (опционально — форматирует вывод)
vault.hashicorp.com/agent-inject-template-config: |
{{- with secret "secret/data/myapp/config" -}}
DB_PASSWORD={{ .Data.data.db_password }}
API_KEY={{ .Data.data.api_key }}
{{- end }}
spec:
serviceAccountName: myapp-sa # должен совпадать с vault role
containers:
- name: app
image: myapp:latest
command: ["sh", "-c", "source /vault/secrets/config && ./myapp"]
Создать ServiceAccount для пода
kubectl create serviceaccount myapp-sa -n myapp
Инжекция как переменные окружения
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp-role"
vault.hashicorp.com/agent-inject-secret-env: "secret/data/myapp/config"
vault.hashicorp.com/agent-inject-template-env: |
{{- with secret "secret/data/myapp/config" -}}
export DB_PASSWORD="{{ .Data.data.db_password }}"
export API_KEY="{{ .Data.data.api_key }}"
{{- end }}
# В контейнере:
command: ["/bin/sh", "-c", "source /vault/secrets/env && exec myapp"]
Vault в Helm чартах
Через Vault Agent (annotations в values.yaml)
# values.yaml вашего чарта
podAnnotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "myapp-role"
vault.hashicorp.com/agent-inject-secret-db: "secret/data/myapp/db"
vault.hashicorp.com/agent-inject-template-db: |
{{- with secret "secret/data/myapp/db" -}}
{{ .Data.data.password }}
{{- end }}
serviceAccount:
create: true
name: myapp-sa
Через External Secrets Operator (рекомендуется — см. ESO README)
# Helm чарт не меняется — ESO создаёт k8s Secret автоматически
# Используй стандартный envFrom/secretRef в values.yaml
envFrom:
- secretRef:
name: myapp-secrets # создан ExternalSecret → Vault
AppRole Auth (для сервисов без k8s ServiceAccount)
# Включить AppRole
vault auth enable approle
# Создать роль
vault write auth/approle/role/myservice \
secret_id_ttl="720h" \
token_ttl="1h" \
token_policies="myapp-policy"
# Получить Role ID (не секретный)
vault read auth/approle/role/myservice/role-id
# Получить Secret ID (секретный, одноразовый)
vault write -f auth/approle/role/myservice/secret-id
# Авторизация через AppRole
vault write auth/approle/login \
role_id="<role_id>" \
secret_id="<secret_id>"
Аудит и мониторинг
# Включить аудит лог в stdout
vault audit enable file file_path=stdout
# Статус кластера (HA)
kubectl exec -n vault vault-0 -- vault operator members
# Grafana: метрики доступны если addon_prometheus_stack: true
# Дашборд: импортируй ID 12904 из Grafana.com
Полезные команды
# Статус
kubectl exec -n vault vault-0 -- vault status
# Список engines
kubectl exec -n vault vault-0 -- vault secrets list
# Список auth methods
kubectl exec -n vault vault-0 -- vault auth list
# Seal (экстренная блокировка)
kubectl exec -n vault vault-0 -- vault operator seal
# Raft cluster (HA)
kubectl exec -n vault vault-0 -- vault operator raft list-peers