Summary
The chart's generated secrets cannot survive a GitOps render, and ArgoCD's
ignoreDifferences does not protect them. This blocks managing PatchMon with
ArgoCD at all — verified empirically on k8s-sto2, twice.
The mechanism
templates/secret.yaml seeds JWT_SECRET, SESSION_SECRET and AI_ENCRYPTION_KEY
with randAlphaNum, keeping them stable across upgrades via a lookup on the existing
Secret. lookup only resolves under helm upgrade/install. ArgoCD renders with
helm template, where it always returns empty — so every render mints three new values:
$ helm template patchmon patchmon/patchmon --version 0.3.6 -f values.yml | grep JWT_SECRET
JWT_SECRET: "fAWUcEVwQRqDHzWPsBZikBELm..." # render 1
JWT_SECRET: "GkWMNDFpxZ0nwVvA3HUPRq7HQ..." # render 2, same inputs
@BryanR77 documented this in #7 and added patchmon.session.secret /
patchmon.encryption.aiKey so the values can be pinned — but pinning them means
putting three secrets in git in plaintext, which is not a fix for GitOps users.
ignoreDifferences does not save you
The obvious mitigation is ignoreDifferences on the Secret's /data plus
RespectIgnoreDifferences=true. It does not work. Tested by syncing only that one
resource and hashing before/after:
| Sync options |
Result |
ServerSideApply=true + RespectIgnoreDifferences=true |
regenerated |
RespectIgnoreDifferences=true (client-side apply) |
regenerated |
Both times all three keys were replaced. Restored from a pre-made copy of the Secret;
no pod restarted, so nothing was lost — but on an unattended selfHeal: true sync this
would be silent and permanent.
Why it matters more than it looks
JWT_SECRET / SESSION_SECRET — every session invalidated on each sync.
AI_ENCRYPTION_KEY — anything already encrypted with the old key becomes
unrecoverable. There is no recovery path once the old value is gone.
A GitOps user with automated sync would rotate all three on every reconcile without
any signal that it happened.
Proposed fix
Support consuming these from an existing Secret, exactly mirroring the pattern the
chart already has for OIDC (patchmon.oidc.clientSecretFromSecret), which works well:
patchmon:
existingSecret:
name: "" # when set, the chart does NOT render its own Secret
keys:
jwt: JWT_SECRET
session: SESSION_SECRET
aiKey: AI_ENCRYPTION_KEY
When name is set:
templates/secret.yaml skips those keys entirely (or skips rendering altogether if
OIDC is also external);
deployment-server.yaml points each secretKeyRef at the named Secret.
That lets the secrets live in a real secret store (we use OpenBao + External Secrets)
and keeps them out of both git and the chart's render, which makes the manifest
deterministic and the ArgoCD diff clean.
Notes
Summary
The chart's generated secrets cannot survive a GitOps render, and ArgoCD's
ignoreDifferencesdoes not protect them. This blocks managing PatchMon withArgoCD at all — verified empirically on k8s-sto2, twice.
The mechanism
templates/secret.yamlseedsJWT_SECRET,SESSION_SECRETandAI_ENCRYPTION_KEYwith
randAlphaNum, keeping them stable across upgrades via alookupon the existingSecret.
lookuponly resolves underhelm upgrade/install. ArgoCD renders withhelm template, where it always returns empty — so every render mints three new values:@BryanR77 documented this in #7 and added
patchmon.session.secret/patchmon.encryption.aiKeyso the values can be pinned — but pinning them meansputting three secrets in git in plaintext, which is not a fix for GitOps users.
ignoreDifferencesdoes not save youThe obvious mitigation is
ignoreDifferenceson the Secret's/dataplusRespectIgnoreDifferences=true. It does not work. Tested by syncing only that oneresource and hashing before/after:
ServerSideApply=true+RespectIgnoreDifferences=trueRespectIgnoreDifferences=true(client-side apply)Both times all three keys were replaced. Restored from a pre-made copy of the Secret;
no pod restarted, so nothing was lost — but on an unattended
selfHeal: truesync thiswould be silent and permanent.
Why it matters more than it looks
JWT_SECRET/SESSION_SECRET— every session invalidated on each sync.AI_ENCRYPTION_KEY— anything already encrypted with the old key becomesunrecoverable. There is no recovery path once the old value is gone.
A GitOps user with automated sync would rotate all three on every reconcile without
any signal that it happened.
Proposed fix
Support consuming these from an existing Secret, exactly mirroring the pattern the
chart already has for OIDC (
patchmon.oidc.clientSecretFromSecret), which works well:When
nameis set:templates/secret.yamlskips those keys entirely (or skips rendering altogether ifOIDC is also external);
deployment-server.yamlpoints eachsecretKeyRefat the named Secret.That lets the secrets live in a real secret store (we use OpenBao + External Secrets)
and keeps them out of both git and the chart's render, which makes the manifest
deterministic and the ArgoCD diff clean.
Notes
lookupbehaviour is correct forhelm upgradeusers and should stay as thedefault — this is purely an additional opt-in path.
is silent and expensive.