fix(iam): make the ZITADEL OIDC secrets and identity links IaC-owned

Every consumer SSO login failed for two independent reasons, and neither was
recorded in git.

1. The OIDC client secrets lived only in the cluster. They are written by
   scripts/iam/zitadel-provision.py, whose `apply` phase calls
   _generate_client_secret for every app on every run. A rotation therefore
   invalidated the stored secret in ArgoCD, Grafana, MinIO, Immich and
   Paperless, with no git value to compare against. Declaring the five Secrets
   as SOPS manifests makes ArgoCD the owner, so the next rotation is a
   reviewable diff instead of silent drift.

2. Forgejo, Paperless and Immich store the identity-provider link inside their
   own databases, not in Kubernetes. Those rows still carried the Authentik
   subject and provider, which produced three different symptoms from one
   cause: Forgejo never left /user/link_account, Paperless showed the social
   signup page, and Immich answered 400 "email already linked to different
   account". The PostSync Job re-points each row at the ZITADEL `sub`,
   matching on email or username rather than the numeric ids this was first
   observed on, so a re-run converges.

Verified with a real browser login against a live ZITADEL session: Forgejo,
Paperless, Immich, Grafana and ArgoCD all reach their authenticated landing
page. Vault has no UI by design. MinIO remains open: the operator sidecar
serves its console with no OIDC environment, so it advertises form login only.
This commit is contained in:
2026-10-31 13:37:04 -07:00
parent 41dcda819e
commit cf1263235b
8 changed files with 272 additions and 0 deletions
+27
View File
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: oidc-secret
namespace: argocd
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/part-of: iam
type: Opaque
stringData:
client-id: ENC[AES256_GCM,data:KJmGTcCz/c60+aLs7BqwL6Je,iv:hpwBdXp9einCN8EdvMXgTyf4Tl6SN9VTmDQotdEC/qE=,tag:MmF076Vsm0ejZtQMfG+e5w==,type:str]
client-secret: ENC[AES256_GCM,data:0W2lS6WTzUpJUQo4AQSZk0iXOqZjKVqXCRv4HVuNrGpcZYf81oJVR8dM/FnApd4zS1Y11465aXYcImqcKo4xkg==,iv:ECIkWzeRTroWpugjqASD3eJHipn4m2JWthC/1gaXhkA=,tag:GU5GyKhUvutJRuxkhQNE0Q==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBZZjVTSlN6c2dZbDZCeEFa
SU9YVy9HUEEzckRVb0QrRmh5NTN2Qm8ycFFVCkpwVnAxK3BGT29NdnN2VDlveDBG
RHo5YjVicllRc1NlRzNabS9vWlo3cVUKLS0tIHF4OE1GKzJUZlBhU3dNOFFaeWZC
M3QrRTRxbkNRZVMreWsyQytlMDdFUTAKwtVdzOk6nMDrauDcRUnun3JU/Cfi3qgB
jhftbXHaxcKhB5MJCwZkN7VmtpxOjpvYgpetj9cBNXx2yVVcS7G5Hg==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-31T03:41:24Z"
mac: ENC[AES256_GCM,data:GHwigzuZRGkLIH6vaDjUsefjdnmhToePQGB9+3CIZW8DunlkgmGqk/jIsQee7Yo0fa1OOdMHRQH7+biooUP1Z5GANmsBnQhDT0GAnd3JPbIN2lIJKeManGDALqsbhLzmfcSBNByIJaJh5c3xakL/LmU+CoUWluWCLQqjpeeiMEk=,iv:uBRbVAgzXxxn3Xx7foUZWyK/Cq6yMd3/lkt+S+uY2bk=,tag:Mr0F5rp5aEVNd7pZqnyWUw==,type:str]
version: 3.13.2
+26
View File
@@ -0,0 +1,26 @@
apiVersion: v1
kind: Secret
metadata:
name: grafana-oidc
namespace: logging
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/part-of: iam
type: Opaque
stringData:
GF_AUTH_GENERIC_OAUTH_CLIENT_SECRET: ENC[AES256_GCM,data:ZCO6gQGNRKtahbUctlLYCTx3TpRdz5lj8r6X4fUXkyvS5rbWXgip2mGqho4LUSHh8du3wo+bK8VyP1MhzIFRGA==,iv:O2aCivj8Z3cbKCqj/Q8uG6mEH9QJbCrDLPIjX6bLkjo=,tag:qpKgg9AAtIUvYzr5zwTO1g==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBEc2xWSk1ldGxpYzlHUlF5
aFZQWnVxWXJVemZVd1llQlZUTkNrTFpVWGhrCjZtbW1XU1Z0U1ZlTHlGMjVSTUFp
NnFNTjdlYUUyTlhnN3QybFZJSGRuRG8KLS0tIG9DL3ZQYmErc2ZndWd6TUNlOStp
UTI0UDZZM2IwQU9oRmxsU25rQi9zUUkKYznGn96vdcEZSCpfyReNj4qLoS0t19ZQ
frodab7z/n6TadRwsb1ufb+YIHa4pGPlImmrlNGOIpnKvzXlmOCP4Q==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-31T03:41:24Z"
mac: ENC[AES256_GCM,data:uOPMvN1D/6AdxpWrR0aQYAxSEcC8/aJNg574cF+ypi/rt+srk68q2kAiKwA5L5GDvXs65rSZh2PMkJ0KV75g3ShFYOQSLaq0HIwYYTvIXRLtF43G8vMHaaZAhDC1pZeYPdD1KG61pDVjyCDc+qFZ/90kHqYiIeAdEI4Tia5YOJ4=,iv:SpU/YrCxORAJWJCLyTNSaNuIB0dAhq8+Bma58RUYL3U=,tag:s7fsEDQfqElTsE8EQsZfxw==,type:str]
version: 3.13.2
+27
View File
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: immich-oidc
namespace: immich
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/part-of: iam
type: Opaque
stringData:
client-secret: ENC[AES256_GCM,data:SAxFOfR1lIeKFHII2BJskF2T46lXlFFu+qzLxyf/uBDiQACRDTkQGzeJccc2jNT5hagS5GDOidnZN4aXrHGjUA==,iv:V4sDhHbiOyB+cllFuBpfO0JsiEG5frWMj0lUZSCLRwk=,tag:tb/m9gFUSb7SGuiilYoZSg==,type:str]
config.json: ENC[AES256_GCM,data:6HCZ2bl5RavyHP15RMMRkKYaCGXIVwIEkIOkT5VZs2BFZ7b+Po2fLimM7efVsR1QAF4NZ3StAOnsdJoEaTrNeEfCf22pLdELYw4swodlJi0Ybty09q9N7JZzENoa+3Sor0wxPI0FE70m058Sg+NkliRXxwpdwMAFkh6nj4zwZy0dUiyaHVsQFs5CDoAMrKP5KCdQhAz6Qx622C2D03pWjZICAO/VrKhLU/2N8c8Jid9r2zJWFJxegazhEtJ+AE/1aM+h9rjb7IB9HObRUROd8tYypOgV5u3LBQMg9DP4PTHcPoDdyHbKtRYyCTP5adIt6/Xr37C+5o3dpEi8cR8yUfWIn2jYkcbhIUSVGCVE8b4e3b6jNhvUAlv5JZubjVmm+MJdAhGTPBi7NEPoU+1p0Bs8yx4mjvtXZRn4is2oei322vhUUpIq/OzAn5Km8v/8CnzyS6Zclsl5Oa+jRqWIqNJ3vVYSReytN11KbvCNtDmVsrNpPg1Set3mhk7CIrND3tZQqX6Q4P7/vllAvfsoorf7BZrI7z7/SrRxYWZZWziC7tsPnqul+yntymWxHt2NW203Fdk=,iv:6IymBA+UeVGjDffyKAxpiAA/1G9/eB6mJJmZ8Ntwq90=,tag:X38OSEIgoNbrSyHFADwADQ==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBKV0Fta2VXVThvTnl1S09O
TkgwTjJBc040K3NRdXFRTlFEMGJqaVVVZmd3Ck9MMDc0VzNkRDhrbTFteHc1VFVo
OTNrMytLVFZYMkZYSGJjU2pnMjNlSk0KLS0tIDJrajNqZjVNQ1NjZ2FienJFcEVK
d3JIMk1lQjNuVE9LTmhoYzJlRHpua3MK17o8wpCg98eiFYJdZhWqHOl+riMcqLpg
pL+jzEAb6F8aOOvlog99TDyq5Pw0g1MvJBmw+2jyMTAZE2cIoX4CLg==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-31T03:41:24Z"
mac: ENC[AES256_GCM,data:cv9uXDrbECSIPQLbEugfvYyGG6BoNxu/Cva7BmUYF6DkT34dCtCMNI2ey1nV5m8dJM1ote2lxpnWjt/6s1P41AMRsdyGkEaGrAW/62uP8NCX6PP+p519qTUvf4ZdGFQ24Uo0UVQ0AV/vCw1RAurmZXKcoLVvQaCzgDCn2EgfAiE=,iv:mpJ+YqFamDGaEiqy6Y3gT5IqMcKs2qR/FyfmxKM7BcM=,tag:U+UtCTLTX+b/FjZGfUrrgQ==,type:str]
version: 3.13.2
+27
View File
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: minio-oidc
namespace: storage
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/part-of: iam
type: Opaque
stringData:
MINIO_IDENTITY_OPENID_CLIENT_SECRET: ENC[AES256_GCM,data:M8iRH6BxzEz7r/eOwED+uiOdHwkXg5DD5s4xEaKJCNAn2HwlpuKM+pUVLyLNwSxeN7Kf6dYVMUWuuzL2N3BkEQ==,iv:tSa3MSSNkM38/avXIt4CHUDZ64zXGGqiInCJx3cP2gI=,tag:z5ODn9b3/464+O1bF5CoZg==,type:str]
client-secret: ENC[AES256_GCM,data:9/YiXaYw/AavqklSPZ0akuF6gNjPL9OrpEc1jMz8N5QgYD8aZJxol0mUXqhoLy6zldaifo7ZxtzRONdJkuGBwg==,iv:kEUzmeQMVbyI/2ag/9baRWp0XJ1VhIqBlpVxZB6OEog=,tag:kf34PPlQzHTWfd2ndGvP3A==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSA3S2JTSFF3Y2VMWkNncTIw
K2VKM1dDNnE1ZE5YSTNDN0ZFS2paNXNHSUU0ClFGWnBSVThrbWk3MGUyTVlPRGNB
cGJOMmxSMlZnNHNMT3cxNzFneEc2b0EKLS0tIG9lbURIdEdLNVZVR3JiWkFWVmMx
aUVDVUpOTENjK0ViYWFVRm5BNmcwbncKg5ThSLcmeJKY2mm7EkRlDg6FKnpBvFrE
eEwfEEX68KirboOsv6U1TPjyf2ZM0Wfj+1kVfiNQTLi7QEE3R377KQ==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-31T03:41:24Z"
mac: ENC[AES256_GCM,data:QA7Skxv7f9AOZCPWAZlEW+TR4eNSSX8LlxFc6zUqfiWu3oPPThMQxXiHJi4FEeUsjwe3Qy/FsPWF2182P0yZ/lfiXFi6bfPMzL9OeyYISrjfd/MUBm02+JG/MMrMXat+sxQgrTljl7z5H74X7BywHOLLGHjHDoWEEzqU3pJrFIQ=,iv:wecxDkPDPQmFwaRZjnxKD6zuTXQREjfkyZ34eNF/63M=,tag:IUDoRtpMCYa3amxWoyHL+g==,type:str]
version: 3.13.2
@@ -0,0 +1,27 @@
apiVersion: v1
kind: Secret
metadata:
name: paperless-oidc
namespace: paperless
labels:
app.kubernetes.io/managed-by: argocd
app.kubernetes.io/part-of: iam
type: Opaque
stringData:
SOCIALACCOUNT_PROVIDERS_JSON: ENC[AES256_GCM,data:mz6fvwB8/E881pnl0fX2sXj5vdnGUoN0jQsYX7OqzRhZxAmXwvsIt3ZdqXPdoz8xXJOM+2P082aFV24q5jKjU6m4pGVxZT79kooNQdPImcthBl/1oSvgbuQrKnX9kDdlcfTaONckya1SycXyixyqWIx+dQmosLcPXQZgVrbJ0XgPYAnHAqdNB8S0yLNCPQMmf+isC+JQY/iw5gVYbVehTTZnJkZoh07d2amMFLbx1janzKuGWsSeXEEwFPfntBEDcq8CMD+uGfZmiaunTvztLZCIYfm/ZriBeWroY42nrncAhBcjMWfT7hFjK6I+SMY1+/uDjVuhlmg96C6uwnFBgzTDiqz46W8kg+qYVg3DAO1KdORL84N54vhMOj+NMoG0GxL1SW4M9JPoMCjnkpVvhE0C6m9MeNcV5CEDN+wPQuoDA60F5NrGmp9cnPD4GVXBOGqdUjr9QQbfkZeGrzIyREYS5krBD/89mx7a,iv:dCXz2VwJGXqKnETGEKrtg8afTjQZ80fdQetQkQbWFmA=,tag:3fSADqRQrqE2Kmap0cMYCQ==,type:str]
client-secret: ENC[AES256_GCM,data:960UNsowQT3xrBdQ0pD4VrFQSFFi/2yiN3RPVnK4a0yySDjcxlsZVLn0fWnLEVHbmAWEe10j36xhGS2pzTx06A==,iv:ztpJi0zHCKx7Jjk40wtDNHhatr2vCOMdD8XIUnfIzTU=,tag:efTUtQmPvteeEtX9ZOT1nw==,type:str]
sops:
age:
- enc: |
-----BEGIN AGE ENCRYPTED FILE-----
YWdlLWVuY3J5cHRpb24ub3JnL3YxCi0+IFgyNTUxOSBXdW01dUY4ZXZYeWdWeU5B
Uk9kUkRDS2tLUXc5dVVMOFJJVUcxbmtEbjNVCk4vK3ZVYlppT0lwSGtTeXJiM1ZU
SEZyTWlrYjNVNFBxU01YcGs1Q2YrOEEKLS0tIHlyR2JnWDBpUkcyUTNDM2IxMjkr
NTROVkVyd3RpS014WktISi9Ba3dZOE0KoP8Q30KCrLF+mqVIIfp6k6B727yiUBIj
1H3krVQt6eOadTZZd+EPS0nvJA4wzUyaCco6oiB00gckhPnZu8m4jw==
-----END AGE ENCRYPTED FILE-----
recipient: age1e5fq3hwxy78psus2nfvmtmua36g0u3suk78ephw6246l974d2utsvn0hla
encrypted_regex: ^(data|stringData)$
lastmodified: "2026-10-31T03:41:24Z"
mac: ENC[AES256_GCM,data:xB4NS9KAjJ9e14kCrP87PcXyW5F4eBNwWnmkBOXYAVb9RMsFuEG6zAslENLur+LBO2TYyYE+YSV0HVvGICU2jJ8LxsJXdfCm0ADxrhkBcneBgLwqDPMURZDwQSCLJxdh3AyV2+vRDGdrjyjzUE507fWpYd84HPEgyrVJ4w+V6TA=,iv:foISE6qjTurY6Mll8FEdirvx9QXOalsUPdWx+sK59CM=,tag:3hmGRXsMFkKw4+VYcNypdA==,type:str]
version: 3.13.2
+10
View File
@@ -30,6 +30,16 @@ files:
- paperless-ai-secrets.enc.yaml
- memory-agent-oidc.enc.yaml
- oauth2-credentials.enc.yaml
# ZITADEL OIDC client secrets for the consumer apps. These used to live only
# in the cluster, written by scripts/iam/zitadel-provision.py, so a rotation
# there left every consumer holding a stale secret and no git record of the
# real value. Declaring them here makes ArgoCD the owner and the rotation
# outcome reviewable in a diff.
- argocd-oidc.enc.yaml
- grafana-oidc.enc.yaml
- minio-oidc.enc.yaml
- immich-oidc.enc.yaml
- paperless-oidc.enc.yaml
- forgejo-registry-token.enc.yaml
- pi-sandbox-secrets.enc.yaml
- etcd-defrag-creds.enc.yaml