feat(ory): replace hardcoded DSN + secrets with OpenBao DB engine + VSO

All Ory service credentials now flow from OpenBao through VSO instead
of being hardcoded in Helm values or Deployment env vars.

Kratos:
- Remove config.dsn; flip secret.enabled=false with nameOverride pointing
  at kratos-app-secrets (a VSO-managed Secret with secretsDefault,
  secretsCookie, smtpConnectionURI).
- Inject DSN at runtime via deployment.extraEnv from kratos-db-creds
  (VaultDynamicSecret backed by OpenBao database static role, 24h rotation).

Hydra:
- Remove config.dsn; inject DSN via deployment.extraEnv from hydra-db-creds
  (VaultDynamicSecret, same rotation scheme).

Login UI:
- Replace hardcoded COOKIE_SECRET/CSRF_COOKIE_SECRET env var values with
  secretKeyRef reads from login-ui-secrets (VaultStaticSecret → secret/login-ui).

vault-secrets.yaml adds: VaultAuth, Hydra VSS, kratos-app-secrets VSS,
login-ui-secrets VSS, kratos-db-creds VDS, hydra-db-creds VDS.
This commit is contained in:
2026-03-02 18:32:33 +00:00
parent 580eb3983e
commit c7b812dde8
5 changed files with 167 additions and 9 deletions

View File

@@ -1,13 +1,12 @@
# Base Ory Hydra Helm values. # Base Ory Hydra Helm values.
# DOMAIN_SUFFIX is replaced at apply time via sed. # DOMAIN_SUFFIX is replaced at apply time via sed.
# secret.enabled: false — we create the "hydra" K8s Secret via seed script. # secret.enabled: false — we create the "hydra" K8s Secret via seed script.
# DSN is set in config (chart strips it from env, so must be in values). # DSN comes from env var via VaultDynamicSecret hydra-db-creds (database static role).
hydra: hydra:
automigration: automigration:
enabled: true enabled: true
config: config:
dsn: "postgresql://hydra:localdev@postgres-rw.data.svc.cluster.local:5432/hydra_db?sslmode=disable"
urls: urls:
self: self:
issuer: https://auth.DOMAIN_SUFFIX/ issuer: https://auth.DOMAIN_SUFFIX/
@@ -37,6 +36,12 @@ hydra-maester:
- lasuite - lasuite
deployment: deployment:
extraEnv:
- name: DSN
valueFrom:
secretKeyRef:
name: hydra-db-creds
key: dsn
resources: resources:
limits: limits:
memory: 64Mi memory: 64Mi

View File

@@ -1,13 +1,12 @@
# Base Ory Kratos Helm values. # Base Ory Kratos Helm values.
# DOMAIN_SUFFIX is replaced at apply time via sed. # DOMAIN_SUFFIX is replaced at apply time via sed.
# DSN is set in config (chart renders it into kratos-secrets Secret automatically). # DSN and secrets come from K8s Secrets managed by VSO VaultDynamicSecret/VaultStaticSecret.
kratos: kratos:
automigration: automigration:
enabled: true enabled: true
config: config:
version: v0.13.0 version: v0.13.0
dsn: "postgresql://kratos:localdev@postgres-rw.data.svc.cluster.local:5432/kratos_db?sslmode=disable"
selfservice: selfservice:
default_browser_return_url: https://auth.DOMAIN_SUFFIX/ default_browser_return_url: https://auth.DOMAIN_SUFFIX/
@@ -54,12 +53,21 @@ kratos:
admin: admin:
base_url: http://kratos-admin.ory.svc.cluster.local:4434/ base_url: http://kratos-admin.ory.svc.cluster.local:4434/
# Chart creates kratos-secrets from Helm values (dsn + generated random secrets). # Chart does not manage secrets — we create them externally via VSO.
# secret.nameOverride points chart at our VaultStaticSecret-managed K8s secret so
# the chart injects SECRETS_DEFAULT/SECRETS_COOKIE from kratos-app-secrets automatically.
# DSN is not injected by the chart when secret.enabled=false — we add it via extraEnv.
secret: secret:
enabled: true enabled: false
nameOverride: kratos-secrets nameOverride: kratos-app-secrets
deployment: deployment:
extraEnv:
- name: DSN
valueFrom:
secretKeyRef:
name: kratos-db-creds
key: dsn
resources: resources:
limits: limits:
memory: 64Mi memory: 64Mi

View File

@@ -8,6 +8,7 @@ resources:
- login-ui-deployment.yaml - login-ui-deployment.yaml
# Hydra chart CRDs are not rendered by helm template; apply manually. # Hydra chart CRDs are not rendered by helm template; apply manually.
- hydra-oauth2client-crd.yaml - hydra-oauth2client-crd.yaml
- vault-secrets.yaml
# The hydra-maester sub-chart does not set .Release.Namespace in its Deployment template. # The hydra-maester sub-chart does not set .Release.Namespace in its Deployment template.
patches: patches:

View File

@@ -30,11 +30,17 @@ spec:
- name: PORT - name: PORT
value: "3000" value: "3000"
- name: COOKIE_SECRET - name: COOKIE_SECRET
value: "localdev-cookie-secret" valueFrom:
secretKeyRef:
name: login-ui-secrets
key: cookie-secret
- name: CSRF_COOKIE_NAME - name: CSRF_COOKIE_NAME
value: "csrf" value: "csrf"
- name: CSRF_COOKIE_SECRET - name: CSRF_COOKIE_SECRET
value: "localdev-csrf-secret" valueFrom:
secretKeyRef:
name: login-ui-secrets
key: csrf-cookie-secret
resources: resources:
limits: limits:
memory: 256Mi memory: 256Mi

138
base/ory/vault-secrets.yaml Normal file
View File

@@ -0,0 +1,138 @@
---
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultAuth
metadata:
name: vso-auth
namespace: ory
spec:
method: kubernetes
mount: kubernetes
kubernetes:
role: vso
serviceAccount: default
---
# Hydra app secrets (non-rotating). DSN comes from VaultDynamicSecret hydra-db-creds.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: hydra
namespace: ory
spec:
vaultAuthRef: vso-auth
mount: secret
type: kv-v2
path: hydra
refreshAfter: 30s
destination:
name: hydra
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
secretsSystem:
text: "{{ index .Secrets \"system-secret\" }}"
secretsCookie:
text: "{{ index .Secrets \"cookie-secret\" }}"
"pairwise-salt":
text: "{{ index .Secrets \"pairwise-salt\" }}"
---
# Kratos non-rotating encryption keys. DSN comes from VaultDynamicSecret kratos-db-creds.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: kratos-app-secrets
namespace: ory
spec:
vaultAuthRef: vso-auth
mount: secret
type: kv-v2
path: kratos
refreshAfter: 30s
destination:
name: kratos-app-secrets
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
secretsDefault:
text: "{{ index .Secrets \"secrets-default\" }}"
secretsCookie:
text: "{{ index .Secrets \"secrets-cookie\" }}"
smtpConnectionURI:
text: "{{ index .Secrets \"smtp-connection-uri\" }}"
---
# Kratos DB credentials from OpenBao database secrets engine (static role, 24h rotation).
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: kratos-db-creds
namespace: ory
spec:
vaultAuthRef: vso-auth
mount: database
path: static-creds/kratos
refreshAfter: 1h
rolloutRestartTargets:
- kind: Deployment
name: kratos
- kind: StatefulSet
name: kratos-courier
destination:
name: kratos-db-creds
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
dsn:
text: "postgresql://{{ index .Secrets \"username\" }}:{{ index .Secrets \"password\" }}@postgres-rw.data.svc.cluster.local:5432/kratos_db?sslmode=disable"
---
# Login UI session cookie + CSRF protection secrets.
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultStaticSecret
metadata:
name: login-ui-secrets
namespace: ory
spec:
vaultAuthRef: vso-auth
mount: secret
type: kv-v2
path: login-ui
refreshAfter: 30s
destination:
name: login-ui-secrets
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
cookie-secret:
text: "{{ index .Secrets \"cookie-secret\" }}"
csrf-cookie-secret:
text: "{{ index .Secrets \"csrf-cookie-secret\" }}"
---
# Hydra DB credentials from OpenBao database secrets engine (static role, 24h rotation).
apiVersion: secrets.hashicorp.com/v1beta1
kind: VaultDynamicSecret
metadata:
name: hydra-db-creds
namespace: ory
spec:
vaultAuthRef: vso-auth
mount: database
path: static-creds/hydra
refreshAfter: 1h
rolloutRestartTargets:
- kind: Deployment
name: hydra
destination:
name: hydra-db-creds
create: true
overwrite: true
transformation:
excludeRaw: true
templates:
dsn:
text: "postgresql://{{ index .Secrets \"username\" }}:{{ index .Secrets \"password\" }}@postgres-rw.data.svc.cluster.local:5432/hydra_db?sslmode=disable"