From c7b812dde8c01383c04069b75402bc15162f44ef Mon Sep 17 00:00:00 2001 From: Sienna Meridian Satterwhite Date: Mon, 2 Mar 2026 18:32:33 +0000 Subject: [PATCH] feat(ory): replace hardcoded DSN + secrets with OpenBao DB engine + VSO MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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. --- base/ory/hydra-values.yaml | 9 +- base/ory/kratos-values.yaml | 18 ++-- base/ory/kustomization.yaml | 1 + base/ory/login-ui-deployment.yaml | 10 ++- base/ory/vault-secrets.yaml | 138 ++++++++++++++++++++++++++++++ 5 files changed, 167 insertions(+), 9 deletions(-) create mode 100644 base/ory/vault-secrets.yaml diff --git a/base/ory/hydra-values.yaml b/base/ory/hydra-values.yaml index eaf8ccd..3a3df77 100644 --- a/base/ory/hydra-values.yaml +++ b/base/ory/hydra-values.yaml @@ -1,13 +1,12 @@ # Base Ory Hydra Helm values. # DOMAIN_SUFFIX is replaced at apply time via sed. # 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: automigration: enabled: true config: - dsn: "postgresql://hydra:localdev@postgres-rw.data.svc.cluster.local:5432/hydra_db?sslmode=disable" urls: self: issuer: https://auth.DOMAIN_SUFFIX/ @@ -37,6 +36,12 @@ hydra-maester: - lasuite deployment: + extraEnv: + - name: DSN + valueFrom: + secretKeyRef: + name: hydra-db-creds + key: dsn resources: limits: memory: 64Mi diff --git a/base/ory/kratos-values.yaml b/base/ory/kratos-values.yaml index 282c108..0f911be 100644 --- a/base/ory/kratos-values.yaml +++ b/base/ory/kratos-values.yaml @@ -1,13 +1,12 @@ # Base Ory Kratos Helm values. # 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: automigration: enabled: true config: version: v0.13.0 - dsn: "postgresql://kratos:localdev@postgres-rw.data.svc.cluster.local:5432/kratos_db?sslmode=disable" selfservice: default_browser_return_url: https://auth.DOMAIN_SUFFIX/ @@ -54,12 +53,21 @@ kratos: admin: 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: - enabled: true - nameOverride: kratos-secrets + enabled: false + nameOverride: kratos-app-secrets deployment: + extraEnv: + - name: DSN + valueFrom: + secretKeyRef: + name: kratos-db-creds + key: dsn resources: limits: memory: 64Mi diff --git a/base/ory/kustomization.yaml b/base/ory/kustomization.yaml index 9526c5a..ee1f525 100644 --- a/base/ory/kustomization.yaml +++ b/base/ory/kustomization.yaml @@ -8,6 +8,7 @@ resources: - login-ui-deployment.yaml # Hydra chart CRDs are not rendered by helm template; apply manually. - hydra-oauth2client-crd.yaml + - vault-secrets.yaml # The hydra-maester sub-chart does not set .Release.Namespace in its Deployment template. patches: diff --git a/base/ory/login-ui-deployment.yaml b/base/ory/login-ui-deployment.yaml index 205ad9e..5ca097e 100644 --- a/base/ory/login-ui-deployment.yaml +++ b/base/ory/login-ui-deployment.yaml @@ -30,11 +30,17 @@ spec: - name: PORT value: "3000" - name: COOKIE_SECRET - value: "localdev-cookie-secret" + valueFrom: + secretKeyRef: + name: login-ui-secrets + key: cookie-secret - name: CSRF_COOKIE_NAME value: "csrf" - name: CSRF_COOKIE_SECRET - value: "localdev-csrf-secret" + valueFrom: + secretKeyRef: + name: login-ui-secrets + key: csrf-cookie-secret resources: limits: memory: 256Mi diff --git a/base/ory/vault-secrets.yaml b/base/ory/vault-secrets.yaml new file mode 100644 index 0000000..defe01d --- /dev/null +++ b/base/ory/vault-secrets.yaml @@ -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"