Настройка Vault Agent для chown TLS-сертификатов PostgreSQL
Как настроить Vault Agent sidecar в Kubernetes для динамической генерации и ротации TLS-сертификатов PostgreSQL в non-root контейнере. Решение проблем с chown 70:70 в split_cert.sh, vault pki и injector аннотации.
Как настроить Vault Agent (sidecar), чтобы команда template command успешно выполняла chown 70:70 для генерируемых TLS-сертификатов PostgreSQL в общем volume (/vault/certs/postgres), монтируемом в контейнер Postgres? Почему скрипт split_cert.sh не может изменить владельца файлов на UID/GID 70:70 (пользователь postgres), и какие рекомендуемые подходы для динамической генерации и ротации сертификатов с non-root контейнером PostgreSQL?
Vault Agent в режиме sidecar для hashicorp vault генерирует динамические TLS-сертификаты PostgreSQL в общем volume /vault/certs/postgres, но скрипт split_cert.sh не может выполнить chown 70:70 из-за запуска от пользователя vault (uid=100, gid=1000) — возникает ошибка “Operation not permitted”. Это типичная проблема в vault kubernetes с non-root контейнером Postgres (UID/GID 70:70), где ручной chown от root работает, но автоматизация требует securityContext или initContainer. Рекомендуется использовать vault agent injector с аннотациями для прямой инъекции секретов и ротации postgres сертификат без постобработки скриптами.
Содержание
- Введение в hashicorp vault и vault agent для PostgreSQL
- Настройка vault kubernetes injector и sidecar для postgres сертификат
- Конфигурация vault agent template для генерации TLS-сертификатов
- Проблемы с chown в split_cert.sh и vault pki в non-root контейнере
- Решение прав доступа: от vault tls к UID 70:70 в PostgreSQL
- Рекомендуемые подходы для postgresql tls с vault injector
- Примеры аннотаций и ротация сертификатов в hashicorp vault agent
- Альтернативы и аналоги hashicorp vault для Kubernetes
- Источники
- Заключение
Введение в hashicorp vault и vault agent для PostgreSQL
Представьте: ваш PostgreSQL в Kubernetes работает в non-root контейнере под UID 70:70 для безопасности, но TLS-сертификаты нужно генерировать динамически. Здесь на помощь приходит hashicorp vault с vault agent в режиме sidecar. Это не просто хранение секретов — это полноценная система для выдачи и ротации postgres сертификат через vault pki.
Почему это актуально? В продакшене статические certs устаревают, а ручная ротация — это боль. Vault agent инжектирует секреты в shared volume, монтируемый в под PostgreSQL. Но вот засада: sidecar пишет файлы от своего пользователя (обычно uid=100), а Postgres их не видит под 70:70. Разберём по шагам, как это починить.
Hashicorp vault kubernetes упрощает жизнь с помощью Injector — мутирующий webhook, который добавляет sidecar автоматически по аннотациям. По данным официальной документации HashiCorp, это стандарт для postgresql tls.
Настройка vault kubernetes injector и sidecar для postgres сертификат
Сначала установите Vault Helm chart в кластер. Добавьте namespace с лейблом vault.hashicorp.com/role: postgres-role:
apiVersion: v1
kind: Namespace
metadata:
name: postgres-ns
labels:
vault.hashicorp.com/role: postgres-role
Injector — это Deployment с webhook’ом. В values.yaml Helm укажите:
injector:
enabled: true
image:
repository: hashicorp/vault
Для вашего Deployment Postgres добавьте аннотации:
apiVersion: apps/v1
kind: Deployment
metadata:
annotations:
vault.hashicorp.com/agent-inject: "true"
vault.hashicorp.com/role: "postgres-role"
vault.hashicorp.com/agent-inject-secret-postgres-tls: "pki/issue/postgres-server"
spec:
template:
spec:
containers:
- name: postgres
image: postgres:15
securityContext:
runAsUser: 70
runAsGroup: 70
volumeMounts:
- mountPath: /vault/certs/postgres
name: vault-certs
volumes:
- name: vault-certs
emptyDir: {}
Vault kubernetes добавит sidecar vault-agent с shared volume /vault/certs/postgres. Sidecar рендерит секреты из vault pki, а Postgres их читает. Но если нужен кастомный скрипт вроде split_cert.sh, проблемы с правами неизбежны.
А вы пробовали без скриптов? Injector может сам split’ить bundle в crt/key.
Конфигурация vault agent template для генерации TLS-сертификатов
Сердце — конфиг vault-agent-config.json в ConfigMap или secret. Для vault agent template:
{
"vault": {
"address": "http://vault.default.svc.cluster.local:8200"
},
"template": [{
"source": "{{ with secret \"pki/issue/postgres-server\" \"common_name=postgres-server\" }} {{ .Data.certificate | b64decode }} {{ .Data.private_key | b64decode }} {{ end }}",
"destination": "/vault/certs/postgres/bundle.pem",
"command": "/scripts/split_cert.sh"
}],
"auto_auth": {
"method": {
"type": "kubernetes"
}
}
}
Команда command запускает скрипт после записи bundle.pem. split_cert.sh выглядит так:
#!/bin/sh
openssl pkcs12 -in /vault/certs/postgres/bundle.pem -out /vault/certs/postgres/server.crt -clcerts -nokeys
openssl pkcs12 -in /vault/certs/postgres/bundle.pem -out /vault/certs/postgres/server.key -nocerts -nodes
chown 70:70 /vault/certs/postgres/server.*
Запускается от vault user — и chown фейлится. Документация по template предупреждает: права зависят от securityContext sidecar’а.
Интересно, зачем split’ить вручную? Vault может выдать отдельно cert/key через разные secrets.
Проблемы с chown в split_cert.sh и vault pki в non-root контейнере
Вот в чём собака зарыта. В обсуждении на Stack Overflow описана ваша ситуация: sidecar пишет bundle.pem от uid=100, скрипт пытается chown 70:70, но “Operation not permitted”. Почему?
- Vault agent по умолчанию — non-root (uid=100, gid=1000).
- Non-root Postgres (70:70) не читает файлы от 100:1000 без прав.
- Shared emptyDir не позволяет chown без CAP_FOWNER или root.
Ручной kubectl exec -u 0 с chown работает, потому что root обходит лимиты. В vault pki bundle — это PKCS12, split нужен для crt/key, но права ломают цепочку.
Это не баг hashicorp vault agent, а фича безопасности Kubernetes. Без фикса ротация сломается при рестарте пода.
Решение прав доступа: от vault tls к UID 70:70 в PostgreSQL
Фиксим по шагам. Вариант 1: securityContext в sidecar (Injector позволяет патчить).
В аннотациях добавьте:
vault.hashicorp.com/agent-extra-volume-paths: '[{"path":"/scripts","mode":"0444"}]'
Но для chown — укажите в Deployment (Injector пропустит):
spec:
template:
spec:
containers:
- name: vault-agent # sidecar
securityContext:
runAsUser: 0 # root для chown
capabilities:
add: ["FOWNER"]
Вариант 2: InitContainer перед Postgres:
initContainers:
- name: cert-init
image: bitnami/postgres:15 # или vault:1.15
command: ["/bin/sh", "-c"]
args:
- |
while true; do
if [ -f /vault/certs/postgres/server.crt ]; then
chown 70:70 /vault/certs/postgres/server.*
break
fi
sleep 1
done
securityContext:
runAsUser: 0
volumeMounts:
- mountPath: /vault/certs/postgres
name: vault-certs
Вариант 3: install вместо cp/chown в скрипте:
install -m 644 -o 70 -g 70 bundle.pem /vault/certs/postgres/server.crt # но требует root
Или sudoers в image sidecar’а (не рекомендуется). Лучше initContainer — он ждёт sidecar и фиксит права атомарно.
Для vault tls ротации добавьте vault.hashicorp.com/renew-interval: "24h".
Рекомендуемые подходы для postgresql tls с vault injector
HashiCorp рекомендует избегать скриптов: используйте несколько secrets.
Аннотация для отдельных файлов:
vault.hashicorp.com/agent-inject-secret-server-cert: "pki/cert/postgres-server"
vault.hashicorp.com/agent-inject-secret-server-key: "pki/private/postgres-server/key"
vault.hashicorp.com/template-server-cert: |
{{ with secret "pki/issue/postgres-server" "common_name=postgres-server" -}}
{{- .Data.certificate -}}
{{- end -}}
Injector сам chown’ит по umask или fsGroup. В Pod spec:
securityContext:
fsGroup: 70
Это магия: Kubernetes меняет группу на 70 при записи в volume. Работает для emptyDir/PVC. Для postgresql tls настройте в postgresql.conf:
ssl_cert_file = '/vault/certs/postgres/server.crt'
ssl_key_file = '/vault/certs/postgres/server.key'
Ротация? vault.hashicorp.com/agent-pre-populate-only: "false" — sidecar следит и обновляет.
Это чище, чем split_cert.sh. Примеры в доках подтверждают.
Примеры аннотаций и ротация сертификатов в hashicorp vault agent
Полный Deployment пример:
metadata:
annotations:
vault.hashicorp.com/agent-inject: 'true'
vault.hashicorp.com/role: 'postgres-role'
vault.hashicorp.com/agent-inject-template-server-cert: |
{{ with secret "pki/issue/postgres-server" "ttl=24h" }}
{{ .Data.certificate }}
{{ end }}
vault.hashicorp.com/template-path-server-cert: '/vault/certs/postgres/server.crt'
vault.hashicorp.com/agent-inject-secret-ca: 'pki/cert/ca'
spec:
securityContext:
fsGroup: 70
containers:
- name: postgres
volumeMounts:
- mountPath: /var/lib/postgresql/data/certs # symlink или bind
name: vault-certs
Ротация: sidecar проверяет TTL, перезапрашивает при истечении. Для hashicorp vault agent укажите failureMode: ignore в аннотациях, чтоб под стартовал без certs (graceful).
Тестируйте: kubectl logs vault-agent-xxxx покажет логи рендера.
Альтернативы и аналоги hashicorp vault для Kubernetes
Не фанат Vault? Cert-Manager + external issuer (ACME/VAULT) проще для postgres сертификат.
apiVersion: cert-manager.io/v1
kind: Certificate
spec:
secretName: postgres-tls
issuerRef:
name: vault-issuer
kind: ClusterIssuer
Или ExternalSecrets Operator: синхронит Vault в K8s secrets, затем volume mount. Но для динамики Vault выигрывает.
Kubernetes CSI driver secrets store — экспериментально. AWS/GCP Secrets Manager с sidecar proxies. Выбор за вами, но vault kubernetes — золотой стандарт для enterprise.
Источники
- Vault Agent template command cannot chown generated PostgreSQL certificates — Обсуждение проблемы chown в split_cert.sh для Vault Agent sidecar: https://stackoverflow.com/questions/79897791/vault-agent-template-command-cannot-chown-generated-postgresql-certificates-to-u
- Vault Agent with Kubernetes — Документация по настройке Vault Injector в Kubernetes: https://developer.hashicorp.com/vault/docs/platform/k8s/injector
- Vault Agent Template — Руководство по шаблонам и командам в Vault Agent: https://developer.hashicorp.com/vault/docs/agent/template
- Vault Injector Examples — Примеры аннотаций для секретов и TLS в Kubernetes: https://developer.hashicorp.com/vault/docs/platform/k8s/injector/examples
Заключение
Настройка vault agent для postgres сертификат в non-root PostgreSQL сводится к fsGroup=70 или initContainer — это решает chown без хаков. Забудьте split_cert.sh: используйте нативные шаблоны vault pki и аннотации injector для seamless ротации postgresql tls. В итоге — безопасные, динамические certs без даунтайма. Начните с теста в dev-ns, и ваш кластер скажет спасибо.
Vault Agent sidecar генерирует TLS-сертификаты для PostgreSQL в общем volume /vault/certs/postgres с помощью шаблона template и команды split_cert.sh. Скрипт извлекает server.crt и server.key из bundle.pem, но не может выполнить chown 70:70 из-за запуска от пользователя vault (uid=100, gid=1000) — ошибка “Operation not permitted”. Ручной chown от root работает, файлы читаются Postgres (70:70). Предложение: добавить sudoers для vault user или использовать install -o 70 -g 70. Это типичная проблема HashiCorp Vault Agent в Vault Kubernetes с non-root контейнерами.
Vault Agent Injector в Vault Kubernetes добавляет sidecar-контейнеры для рендеринга секретов в shared volume с помощью аннотаций вроде vault.hashicorp.com/agent-inject-secret. Поддерживает TLS volumes для client/CA certs и ключей (vault.hashicorp.com/tls-secret). Это позволяет динамически генерировать Postgres сертификат и PostgreSQL TLS без ручного chown, инжектируя секреты напрямую в под. Рекомендуется для HashiCorp Vault в K8s с ротацией certs.
Vault Agent template использует Consul Template для записи секретов из Vault PKI в файлы, включая Vault TLS certs. В конфиге template указывается contents с secret kt-int/issue/postgres-server и destination в shared volume. Команда (command) запускает скрипты вроде split_cert.sh для постобработки, но требует прав для chown в non-root setup. Идеально для HashiCorp Vault Agent с PostgreSQL.
Примеры аннотаций для Vault Injector в HashiCorp Vault Kubernetes: vault.hashicorp.com/agent-inject-template-db-creds для PostgreSQL creds и vault.hashicorp.com/ca-cert для TLS. Под добавляет init/sidecar контейнеры, монтирует shared volume для Postgres сертификат. После патча под reschedule’ится с Vault Agent, решая ротацию без ручного вмешательства в права доступа.
