mirror of
https://github.com/cozystack/cozystack.git
synced 2026-11-07 20:43:54 +09:00
feat(keycloak): add optional KMS-encrypting database proxy (#3003)
## What this PR does Adds an optional, flag-gated **column-level PII encryption** feature to the `keycloak` system package. When `encryption.enabled=true`, a `keycloak-kms-proxy` Deployment + Service is placed on the wire between the Keycloak StatefulSet and its CloudNativePG database, and Keycloak's `KC_DB_URL_HOST`/`KC_DB_URL_PORT` are repointed at the proxy. The proxy transparently encrypts Keycloak PII columns (username, email, first/last name, `pii-*` attributes, credential secrets) before they reach PostgreSQL and decrypts them on reads; the data-encryption key is wrapped by a KMS and never lives inside the database. The proxy lives in its own repository: https://github.com/cozystack/keycloak-kms-proxy (image `ghcr.io/cozystack/keycloak-kms-proxy:v0.1.0`). **KMS backend** is selectable via `encryption.kms.backend`: - `static` (default): a self-generated 32-byte KEK kept in a Secret — works on any cluster, suitable for evaluation. - `vault-transit`: the KEK lives in HashiCorp Vault (recommended for production; supports KEK rotation). The feature is **off by default**, so existing installs are unaffected — `KC_DB_URL_HOST` keeps sourcing from the CNPG `keycloak-db-app` secret. ### Changes - `values.yaml`: new `encryption` block. - `templates/proxy.yaml` (new): gated Deployment + Service (+ self-generated KEK Secret for the static backend), hardened pod (nonroot, read-only rootfs, dropped caps, seccomp). - `templates/sts.yaml`: conditional DB-endpoint override when encryption is enabled. - `tests/encryption_test.yaml` (new): helm-unittest covering on/off and both KMS backends. `helm unittest .` → 11/11 pass. ### Follow-ups (not in this draft) - Backend TLS re-origination to the CNPG endpoint + CA validation. - Liquibase bootstrap-window handling (`KKP_LENIENT`). - Offline backfill Job for migrating existing data. - HA via a shared DEK set (currently single replica). ### Screenshots N/A — no UI changes. ### Release note ```release-note feat(keycloak): add optional KMS-encrypting database proxy for column-level PII encryption (off by default; static KEK or Vault Transit) ``` <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Added optional transparent encryption for Keycloak database sensitive fields * Users can configure encryption scope and select key management backend options * **Tests** * Added comprehensive test coverage validating encryption feature across multiple configuration scenarios <!-- end of auto-generated comment: release notes by coderabbit.ai -->
This commit is contained in:
4 files changed
+452
-49
No files matched your search
@@ -0,0 +1,163 @@
|
||||
{{- if .Values.encryption.enabled }}
|
||||
{{- $clusterDomain := (index .Values._cluster "cluster-domain") | default "cozy.local" }}
|
||||
{{- $kms := .Values.encryption.kms }}
|
||||
{{- /*
|
||||
Fail fast on an unsupported backend. Both the KEK Secret below and the env
|
||||
wiring further down key off $backend, so an invalid value (e.g. a "vault"
|
||||
typo) can never render a Deployment that mounts KKP_KEK from a Secret that
|
||||
was never created — which would silently break the whole IdP.
|
||||
*/}}
|
||||
{{- $backend := ($kms.backend | default "static") }}
|
||||
{{- if and (ne $backend "static") (ne $backend "vault-transit") }}
|
||||
{{- fail (printf "encryption.kms.backend must be 'static' or 'vault-transit', got %q" $backend) }}
|
||||
{{- end }}
|
||||
{{- if eq $backend "static" }}
|
||||
{{- /*
|
||||
Static KMS: a self-generated 32-byte KEK kept in a Secret. Generated once
|
||||
and preserved across upgrades via lookup (same pattern as the admin
|
||||
credentials in sts.yaml). For production prefer kms.backend=vault-transit.
|
||||
*/}}
|
||||
{{- $existing := lookup "v1" "Secret" .Release.Namespace "keycloak-kms-proxy-kek" }}
|
||||
{{- $kek := randAlphaNum 32 | b64enc }}
|
||||
{{- if and $existing $existing.data }}
|
||||
{{- $kek = index $existing.data "kek" | default $kek }}
|
||||
{{- end }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: keycloak-kms-proxy-kek
|
||||
labels:
|
||||
app: keycloak-kms-proxy
|
||||
data:
|
||||
kek: {{ $kek | quote }}
|
||||
---
|
||||
{{- end }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: keycloak-kms-proxy
|
||||
labels:
|
||||
app: keycloak-kms-proxy
|
||||
spec:
|
||||
# Single replica: HA needs a shared wrapped DEK set (KKP_DEKSET_FILE) so
|
||||
# every replica encrypts deterministic columns with the same key. Tracked
|
||||
# as a follow-up.
|
||||
replicas: 1
|
||||
selector:
|
||||
matchLabels:
|
||||
app: keycloak-kms-proxy
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app: keycloak-kms-proxy
|
||||
spec:
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65532
|
||||
fsGroup: 65532
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: proxy
|
||||
image: {{ .Values.encryption.image }}
|
||||
imagePullPolicy: IfNotPresent
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
ports:
|
||||
- name: postgres
|
||||
containerPort: 5432
|
||||
- name: metrics
|
||||
containerPort: 9090
|
||||
env:
|
||||
- name: KKP_LISTEN_ADDR
|
||||
value: ":5432"
|
||||
- name: KKP_METRICS_ADDR
|
||||
value: ":9090"
|
||||
# NOTE: the proxy re-originates the connection to keycloak-db-rw and
|
||||
# negotiates TLS in-band, but does not yet pin the CNPG CA. Backend
|
||||
# CA validation (sslrootcert) is a tracked follow-up before this is
|
||||
# production-ready; see the keycloak-kms-proxy project.
|
||||
- name: KKP_BACKEND_ADDR
|
||||
value: "keycloak-db-rw.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}:5432"
|
||||
# The proxy terminates SCRAM on both legs. Keycloak still presents
|
||||
# the CNPG-managed credential (KC_DB_USERNAME/KC_DB_PASSWORD come
|
||||
# from keycloak-db-app), so the upstream and backend credentials
|
||||
# are the same CNPG role.
|
||||
- name: KKP_UPSTREAM_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: username
|
||||
- name: KKP_UPSTREAM_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: password
|
||||
- name: KKP_BACKEND_USER
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: username
|
||||
- name: KKP_BACKEND_PASSWORD
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: password
|
||||
- name: KKP_FIELDS
|
||||
value: {{ .Values.encryption.fields | quote }}
|
||||
- name: KKP_LENIENT
|
||||
value: {{ .Values.encryption.lenient | quote }}
|
||||
{{- if eq $backend "vault-transit" }}
|
||||
{{- $vault := $kms.vault | default dict }}
|
||||
- name: KKP_VAULT_ADDR
|
||||
value: {{ required "encryption.kms.vault.address is required when kms.backend=vault-transit" $vault.address | quote }}
|
||||
- name: KKP_VAULT_KEY_NAME
|
||||
value: {{ required "encryption.kms.vault.keyName is required when kms.backend=vault-transit" $vault.keyName | quote }}
|
||||
- name: KKP_VAULT_MOUNT
|
||||
value: {{ $vault.mount | default "transit" | quote }}
|
||||
- name: KKP_VAULT_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ required "encryption.kms.vault.tokenSecretName is required when kms.backend=vault-transit" $vault.tokenSecretName }}
|
||||
key: token
|
||||
{{- else }}
|
||||
- name: KKP_KEK
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-kms-proxy-kek
|
||||
key: kek
|
||||
{{- end }}
|
||||
{{- with .Values.encryption.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
readinessProbe:
|
||||
tcpSocket:
|
||||
port: postgres
|
||||
periodSeconds: 10
|
||||
livenessProbe:
|
||||
tcpSocket:
|
||||
port: postgres
|
||||
periodSeconds: 15
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: keycloak-kms-proxy
|
||||
labels:
|
||||
app: keycloak-kms-proxy
|
||||
spec:
|
||||
selector:
|
||||
app: keycloak-kms-proxy
|
||||
ports:
|
||||
- name: postgres
|
||||
port: 5432
|
||||
targetPort: postgres
|
||||
- name: metrics
|
||||
port: 9090
|
||||
targetPort: metrics
|
||||
{{- end }}
|
||||
@@ -156,24 +156,27 @@ spec:
|
||||
key: password
|
||||
- name: KC_DB
|
||||
value: "postgres"
|
||||
{{- if .Values.encryption.enabled }}
|
||||
# Encryption on: route through the keycloak-kms-proxy, which dials
|
||||
# the real CNPG cluster. Auth (username/password/dbname) still comes
|
||||
# from the CNPG-managed keycloak-db-app secret below and passes
|
||||
# through the proxy unchanged.
|
||||
- name: KC_DB_URL_HOST
|
||||
value: keycloak-kms-proxy.{{ .Release.Namespace }}.svc.{{ $clusterDomain }}
|
||||
- name: KC_DB_URL_PORT
|
||||
value: "5432"
|
||||
{{- else }}
|
||||
- name: KC_DB_URL_HOST
|
||||
{{- if .Values.db.host }}
|
||||
value: {{ .Values.db.host | quote }}
|
||||
{{- else }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: "host"
|
||||
{{- end }}
|
||||
- name: KC_DB_URL_PORT
|
||||
{{- if .Values.db.port }}
|
||||
value: {{ .Values.db.port | quote }}
|
||||
{{- else }}
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: "port"
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
- name: KC_DB_USERNAME
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
@@ -189,10 +192,6 @@ spec:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: "dbname"
|
||||
{{- with .Values.db.urlProperties }}
|
||||
- name: KC_DB_URL_PROPERTIES
|
||||
value: {{ . | quote }}
|
||||
{{- end }}
|
||||
- name: KC_FEATURES
|
||||
value: "docker"
|
||||
- name: KC_HOSTNAME
|
||||
@@ -206,15 +205,10 @@ spec:
|
||||
{{- with .Values.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if or $themes .Values.extraVolumeMounts }}
|
||||
{{- if $themes }}
|
||||
volumeMounts:
|
||||
{{- if $themes }}
|
||||
- name: themes
|
||||
mountPath: /opt/keycloak/themes
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- name: http
|
||||
@@ -243,15 +237,10 @@ spec:
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
{{- if or $themes .Values.extraVolumes }}
|
||||
{{- if $themes }}
|
||||
volumes:
|
||||
{{- if $themes }}
|
||||
- name: themes
|
||||
emptyDir:
|
||||
sizeLimit: 256Mi
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
terminationGracePeriodSeconds: 60
|
||||
@@ -0,0 +1,222 @@
|
||||
suite: keycloak optional KMS-encrypting DB proxy
|
||||
templates:
|
||||
- templates/proxy.yaml
|
||||
- templates/sts.yaml
|
||||
|
||||
release:
|
||||
name: keycloak
|
||||
namespace: cozy-keycloak
|
||||
|
||||
tests:
|
||||
- it: does not render the proxy when encryption is disabled (default)
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 0
|
||||
|
||||
- it: keeps Keycloak pointed at the CNPG secret when encryption is disabled
|
||||
template: templates/sts.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: StatefulSet
|
||||
set:
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KC_DB_URL_HOST
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-db-app
|
||||
key: "host"
|
||||
|
||||
- it: renders three documents (KEK Secret + Deployment + Service) when enabled
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 3
|
||||
|
||||
- it: deploys the proxy wired to the static KEK and the CNPG backend
|
||||
template: templates/proxy.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Deployment
|
||||
set:
|
||||
encryption.enabled: true
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.name
|
||||
value: keycloak-kms-proxy
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KKP_KEK
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: keycloak-kms-proxy-kek
|
||||
key: kek
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KKP_BACKEND_ADDR
|
||||
value: keycloak-db-rw.cozy-keycloak.svc.cozy.local:5432
|
||||
|
||||
- it: generates the static KEK Secret
|
||||
template: templates/proxy.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Secret
|
||||
set:
|
||||
encryption.enabled: true
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.name
|
||||
value: keycloak-kms-proxy-kek
|
||||
|
||||
- it: exposes the proxy on a postgres Service
|
||||
template: templates/proxy.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Service
|
||||
set:
|
||||
encryption.enabled: true
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- equal:
|
||||
path: metadata.name
|
||||
value: keycloak-kms-proxy
|
||||
- equal:
|
||||
path: spec.ports[0].port
|
||||
value: 5432
|
||||
|
||||
- it: repoints Keycloak at the proxy Service when encryption is enabled
|
||||
template: templates/sts.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: StatefulSet
|
||||
set:
|
||||
encryption.enabled: true
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KC_DB_URL_HOST
|
||||
value: keycloak-kms-proxy.cozy-keycloak.svc.cozy.local
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KC_DB_URL_PORT
|
||||
value: "5432"
|
||||
|
||||
- it: uses the Vault Transit backend when selected
|
||||
template: templates/proxy.yaml
|
||||
documentSelector:
|
||||
path: kind
|
||||
value: Deployment
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault-transit
|
||||
encryption.kms.vault.address: https://vault.vault.svc:8200
|
||||
encryption.kms.vault.keyName: keycloak
|
||||
encryption.kms.vault.tokenSecretName: keycloak-vault-token
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- contains:
|
||||
path: spec.template.spec.containers[0].env
|
||||
content:
|
||||
name: KKP_VAULT_ADDR
|
||||
value: https://vault.vault.svc:8200
|
||||
|
||||
- it: does not generate a static KEK Secret for the Vault backend
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault-transit
|
||||
encryption.kms.vault.address: https://vault.vault.svc:8200
|
||||
encryption.kms.vault.keyName: keycloak
|
||||
encryption.kms.vault.tokenSecretName: keycloak-vault-token
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- hasDocuments:
|
||||
count: 2
|
||||
|
||||
- it: rejects an unsupported kms backend at render time
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorPattern: "encryption.kms.backend must be 'static' or 'vault-transit'"
|
||||
|
||||
- it: requires vault.address for the vault-transit backend
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault-transit
|
||||
encryption.kms.vault.keyName: keycloak
|
||||
encryption.kms.vault.tokenSecretName: keycloak-vault-token
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorPattern: "encryption.kms.vault.address is required"
|
||||
|
||||
- it: requires vault.keyName for the vault-transit backend
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault-transit
|
||||
encryption.kms.vault.address: https://vault.vault.svc:8200
|
||||
encryption.kms.vault.tokenSecretName: keycloak-vault-token
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorPattern: "encryption.kms.vault.keyName is required"
|
||||
|
||||
- it: requires vault.tokenSecretName for the vault-transit backend
|
||||
template: templates/proxy.yaml
|
||||
set:
|
||||
encryption.enabled: true
|
||||
encryption.kms.backend: vault-transit
|
||||
encryption.kms.vault.address: https://vault.vault.svc:8200
|
||||
encryption.kms.vault.keyName: keycloak
|
||||
_cluster:
|
||||
root-host: example.org
|
||||
cluster-domain: cozy.local
|
||||
asserts:
|
||||
- failedTemplate:
|
||||
errorPattern: "encryption.kms.vault.tokenSecretName is required"
|
||||
@@ -62,28 +62,57 @@ extraEnv: []
|
||||
# name: my-secret
|
||||
# key: my-key
|
||||
|
||||
# Database connection. By default Keycloak connects directly to the chart's
|
||||
# CNPG cluster using the keycloak-db-app secret. Override these to route the
|
||||
# connection through an external endpoint (e.g. a connection proxy such as
|
||||
# PgBouncer) without the chart needing to know about it.
|
||||
db:
|
||||
# DB host. Empty = use the keycloak-db-app secret's "host" key.
|
||||
host: ""
|
||||
# DB port. Empty = use the keycloak-db-app secret's "port" key.
|
||||
port: ""
|
||||
# Extra JDBC URL properties, appended verbatim as KC_DB_URL_PROPERTIES, e.g.
|
||||
# "?sslmode=verify-full&prepareThreshold=0&sslrootcert=/etc/keycloak-db-ca/ca.crt"
|
||||
# Empty = KC_DB_URL_PROPERTIES is not set.
|
||||
urlProperties: ""
|
||||
|
||||
# Extra volumes and volume mounts on the Keycloak container (in addition to
|
||||
# themes). Useful for mounting a CA so KC_DB_URL_PROPERTIES can reference an
|
||||
# sslrootcert when routing the DB connection through a proxy.
|
||||
extraVolumes: []
|
||||
# - name: keycloak-db-ca
|
||||
# secret:
|
||||
# secretName: keycloak-db-ca
|
||||
extraVolumeMounts: []
|
||||
# - name: keycloak-db-ca
|
||||
# mountPath: /etc/keycloak-db-ca
|
||||
# readOnly: true
|
||||
# Transparent column-level PII encryption for the Keycloak database.
|
||||
# When enabled, a keycloak-kms-proxy Deployment is placed on the wire
|
||||
# between Keycloak and its CloudNativePG database: Keycloak's DB endpoint
|
||||
# is repointed at the proxy, which encrypts designated PII columns on
|
||||
# writes and decrypts them on reads. The data-encryption key is wrapped by
|
||||
# a KMS, so it never lives inside PostgreSQL.
|
||||
# Project: https://github.com/cozystack/keycloak-kms-proxy
|
||||
#
|
||||
# OPERATIONAL CAVEATS — read before enabling:
|
||||
# * Availability downgrade. The proxy runs as a single replica (HA needs a
|
||||
# shared wrapped DEK set, tracked as a follow-up). Keycloak itself runs HA
|
||||
# (2 replicas); with encryption on, both replicas funnel their DB traffic
|
||||
# through this one pod, so any proxy restart — node drain, rollout, image
|
||||
# pull, OOM — briefly drops the database connection for the entire IdP.
|
||||
# * Existing data is NOT migrated automatically. Flipping enabled:true on a
|
||||
# populated database leaves the pre-existing PII as plaintext; logins that
|
||||
# match on the deterministic columns (username/email) then fail until the
|
||||
# offline backfill has run. Disabling later is just as unsafe — Keycloak
|
||||
# would point back at CNPG and read ciphertext directly. Off-by-default only
|
||||
# protects FRESH installs. To enable on an existing install, run the backfill
|
||||
# procedure first:
|
||||
# https://github.com/cozystack/keycloak-kms-proxy/blob/main/docs/migration-existing-keycloak.md
|
||||
# * Static KEK = single point of permanent data loss. With kms.backend=static
|
||||
# the KEK is generated once and kept in the keycloak-kms-proxy-kek Secret
|
||||
# (in etcd, next to the DB credentials — "static" trades some at-rest
|
||||
# protection for zero external dependencies). If that Secret is ever lost,
|
||||
# every previously-encrypted value becomes permanently undecryptable, so it
|
||||
# MUST be part of the backup set. For production prefer kms.backend=vault-transit.
|
||||
encryption:
|
||||
enabled: false
|
||||
image: ghcr.io/cozystack/keycloak-kms-proxy:v0.1.0
|
||||
# Encrypted field set: "" = full default set (username, email, names,
|
||||
# PII attributes, credentials), "email-only", or "disabled" (passthrough).
|
||||
fields: ""
|
||||
# Bootstrap window only: downgrades fail-loud rules to passthrough so the
|
||||
# Keycloak Liquibase migrations can complete. MUST be false in steady state.
|
||||
lenient: false
|
||||
kms:
|
||||
# "static" — a self-generated 32-byte KEK kept in a Secret (works on any
|
||||
# cluster, suitable for evaluation). "vault-transit" — the KEK lives in
|
||||
# HashiCorp Vault (recommended for production; supports KEK rotation).
|
||||
backend: static
|
||||
vault:
|
||||
address: "" # e.g. https://vault.vault.svc:8200
|
||||
keyName: "" # Transit key name
|
||||
mount: transit # Transit mount path
|
||||
# Existing Secret holding the Vault token under key "token".
|
||||
tokenSecretName: ""
|
||||
resources:
|
||||
requests:
|
||||
memory: 128Mi
|
||||
cpu: 50m
|
||||
limits:
|
||||
memory: 256Mi
|
||||
Reference in new issue
Block a user