From 9c3b2bfbbe13fbbd89976428253251fc93cb895c Mon Sep 17 00:00:00 2001 From: rock Date: Mon, 26 Oct 2026 23:45:59 -0700 Subject: [PATCH] feat(iam): wire ZITADEL SMTP through envVarsSecret ZITADEL must send verification codes, and it only speaks SMTP. Route that at the smtp-gotify relay so codes reach Gotify and the phone. The settings go in as a ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_* envFrom secret, not as configmapConfig. Editing configmapConfig makes ArgoCD stop managing the rendered zitadel-config-yaml ConfigMap, which the Deployment still mounts; that twice left the IdP one restart away from failing. Env vars override the same keys and leave that ConfigMap alone. Validated with helm template 10.4.0: envFrom appears on both ZITADEL containers and zitadel-config-yaml still renders. --- k8s/argocd/secrets/secret-generator.yaml | 1 + .../secrets/zitadel-smtp-secrets.enc.yaml | 25 +++++++++++++++++++ k8s/infra/iam/zitadel-values.yaml | 14 +++++++++++ 3 files changed, 40 insertions(+) create mode 100644 k8s/argocd/secrets/zitadel-smtp-secrets.enc.yaml diff --git a/k8s/argocd/secrets/secret-generator.yaml b/k8s/argocd/secrets/secret-generator.yaml index 77211d2..03bcc74 100644 --- a/k8s/argocd/secrets/secret-generator.yaml +++ b/k8s/argocd/secrets/secret-generator.yaml @@ -36,6 +36,7 @@ files: - etcd-defrag-creds.enc.yaml - zitadel-masterkey.enc.yaml - smtp-gotify-secrets.enc.yaml + - zitadel-smtp-secrets.enc.yaml # Login UI RSA keypair, adopted from the chart-generated Secret so ArgoCD # owns it. Without this, the chart re-generates the keypair on every render, # which changes checksum/secret-login-service-key and leaves both Zitadel diff --git a/k8s/argocd/secrets/zitadel-smtp-secrets.enc.yaml b/k8s/argocd/secrets/zitadel-smtp-secrets.enc.yaml new file mode 100644 index 0000000..3fecdb6 --- /dev/null +++ b/k8s/argocd/secrets/zitadel-smtp-secrets.enc.yaml @@ -0,0 +1,25 @@ +apiVersion: v1 +kind: Secret +metadata: + name: zitadel-smtp-env + namespace: iam +stringData: + ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_SMTP_HOST: ENC[AES256_GCM,data:c1O6xqe9O7b6OzDCYSQJjqkCvc7cisM/dIgGu3aC6yZGIFuuvfE=,iv:aAVqKCgi8NspPAiIKsgK4yfy8CDqAO2Y/GVdUKpVoGc=,tag:2t1GkBBVyimKorM291cR6A==,type:str] + ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_TLS: ENC[AES256_GCM,data:Pni4WpI=,iv:g11iVRNTYs9VHjX7TATYkzgFR1UQ0QbpXlXxfkEwzQQ=,tag:VzJeOG58w7RqCMk7NZJNxw==,type:str] + ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROM: ENC[AES256_GCM,data:ldRZWrqh+geS9ooxaH4kXbkJinE=,iv:ZPOrJj5R5i5FOvRvObNE/Fw2oPKyH/lw7+pUSP1qE8o=,tag:fsICt7sB4De44VLy3v2nsQ==,type:str] + ZITADEL_DEFAULTINSTANCE_SMTPCONFIGURATION_FROMNAME: ENC[AES256_GCM,data:DpRonnBJpQ==,iv:+oucgXGstpvduMhZIZjmrvbbm8gixr2D2zET410fXRw=,tag:eTVFhvg+Xnr4m6o+iFWVAw==,type:str] +sops: + age: + - enc: | + -----BEGIN AGE ENCRYPTED FILE----- + YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA1eVFtenRNQXBKNndNZXpO + TXJoWWF1V2xnNUV2dVpxeXZWelBNVFZnTlFRCmUzT1RNL1lXbmMvR25LdWtrTXBB + WWNZK3hLRCtDVWl0enhLZmVpVjBlclEKLS0tIGYyWTlMaXQzbG12aGxTQi9CcnRM + UjRUOGJmQkZiU0I4L1MzaG1seFNJdncKqI3pFbUKj16946H2p9AHSK2DSArvo5Ep + y8y/aYc+NNPBaJzy/cdo9aI2mT4tNuw0IsM4f0VXlfEIc3teR5hdNA== + -----END AGE ENCRYPTED FILE----- + recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla + encrypted_regex: ^(data|stringData)$ + lastmodified: "2026-10-27T06:45:46Z" + mac: ENC[AES256_GCM,data:ec9gwKHWtajOyPO5+4ZEAhCuLSlmbQWgcJXL+I/E32/AIoc8NX4Ec8AoeURbfCiknYgeTizAKA2BAipJkZQPev/6j3tuwLI5A34k1g1ax7gdc1gGvEZEpJ03u5PUgJRXfHi4mgSSdF1MrasogOUe2tYSwVwF+HnByBTvxj6HOzk=,iv:8EuCICwZghS4u8PQ0bJwTwTOo12zlVPGOp9+qqJ/Kt0=,tag:CkJGpzS7lGe3SOBtRId9Kg==,type:str] + version: 3.13.2 diff --git a/k8s/infra/iam/zitadel-values.yaml b/k8s/infra/iam/zitadel-values.yaml index 4d7efb7..6c609be 100644 --- a/k8s/infra/iam/zitadel-values.yaml +++ b/k8s/infra/iam/zitadel-values.yaml @@ -145,6 +145,20 @@ setupJob: replicaCount: 2 revisionHistoryLimit: 3 +# Notification delivery. ZITADEL sends verification codes and password resets +# by SMTP only, and this cluster has no mail path, so every user sits at +# verified_email = empty and cannot finish a first login. +# +# The settings go in through envVarsSecret rather than configmapConfig on +# purpose: changing configmapConfig makes ArgoCD stop managing the rendered +# `zitadel-config-yaml` ConfigMap, which the Deployment still mounts, so the +# next pod restart fails. An envFrom secret overrides the same keys with no +# effect on that ConfigMap. +# +# Target is the in-cluster smtp-gotify relay, which forwards to Gotify so the +# codes arrive on the phone. +envVarsSecret: zitadel-smtp-env + # Best practice: a PDB guarantees at least one API pod stays available during # voluntary disruptions (node drain, rolling upgrade). Without it a drain can # take both replicas down at once. minAvailable 1 is correct for 2 replicas;