Untracked ExternalSecrets in the default namespace retry a missing SSM key every hour, forever #809
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#809
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
What this is
Seven ExternalSecrets on kai-server are failing continuously with
UpdateFailed ... Secret does not exist, and most of them are not defined in any repository I can find.external-secretsgithub-pat/github/patdefaultdocker-registry/github/patdefaultnull-db/coilysiren/backend/db-passworddefaultnull-datastore-token/coilysiren/backend/datastore-tokendefaultnull-sentry/sentry-dsn/eco-mcp-appdefaultts-authkey/coilysiren/eco-mcp/ts-authkeycoilysiren-eco-appts-authkey/coilysiren/eco-mcp/ts-authkeycoilysiren-eco-appcoilysiren-eco-app-sentry/sentry-dsn/eco-mcp-appAt
refreshInterval: 1h, ~2670 retries is roughly 111 days of hourly failure.Which are tracked, and which are not
Only one has a definition I could locate:
external-secrets/github-pat→deploy/externalsecret.ymlin this repository, reading/github/patvia aSecretStorenamedaws-parameter-store.The rest —
default/docker-registry,default/null-db,default/null-datastore-token,default/null-sentry,default/ts-authkey— appear in no.yml,.yaml, or.tffile acrossinfrastructure,deploy,agentic-os-kai, or the other checked-out repositories. Note thatdefault/docker-registryis a different object from deploy'sdocker-registry-edge-basic-auth, which reads/docker-registry/basic-auth-usersand is healthy.The
null-prefix suggests these were deliberately-nulled placeholders at some point. That reading is undercut bynull-db-0being a live running Postgres pod indefaultwith a bound 5Gi PVC holding 47MB, so at least that one is not inert.Why they survive
prune: falseis deliberate on the Flux path during the soak, so an object whose manifest was deleted upstream stays in the cluster and keeps reconciling. That is the intended behavior of the soak, but its cost is exactly this: a growing set of objects nobody owns, failing forever, with no signal distinguishing "orphan we forgot" from "live thing that is broken".The part that actually needs a decision
external-secrets/github-patis tracked, and it is failing. Either/github/patdoes not exist in SSM, or theSecretStorecannot read it. That is a real credential that this repository declares it needs.I could not verify SSM directly — the
aws-ssmMCP exposes exactly one policy-approved parameter, and/github/patis not it. Someone with SSM read access should check whether/github/patexists before anything is deleted. If it does exist, this is a store/permission problem, not a missing-key problem, and the error message is misleading.Why it is worth clearing
Two of these are
ts-authkeyforeco-mcp. If eco-app ever needs a fresh Tailscale identity, that path is already broken and has been for months — it will fail at the moment it is needed rather than announcing itself now. The rest is event-stream noise that makes real ExternalSecret failures harder to notice.Acceptance
/github/patis confirmed present or absent in SSM, andexternal-secrets/github-pateither syncs or is removed.default-namespace ExternalSecret above is identified as orphan or live. Orphans are deleted; live ones get a tracked manifest.null-dbspecifically: it is running with real data on a PVC and is declared nowhere. It needs an owner or a decommission.Notes
No changes made. Deleting cluster objects that are not in version control is not something to do from an investigation — the manifests may exist somewhere I cannot see, and
null-dbholds data.Next owner
Ops, with a director call on the
null-*set.Correction: the "~111 days" figure is wrong, and there is a real break date
kubectl describe externalsecret github-pat -n external-secrets:Two things the body gets wrong
The retry arithmetic. I read ~2670 occurrences as hourly retries and derived "roughly 111 days". The event line reads
x2690 over 12d— the counter covers 12 days, not 111, and works out to ~224 failures/day, about one per 6.4 minutes.refreshInterval: 1hgoverns successful refresh; failures retry far faster. The occurrence counts in the body's table are therefore a measure of retry aggressiveness, not of duration, and should not be read as age for any row.It is not "always been broken".
Synced Resource Version: 3-...andRefresh Time: 2026-05-25T05:11:13Zsay this ExternalSecret synced successfully and then broke exactly one hour later, at its next refresh:2026-05-25T05:11:13Z— last successful refresh2026-05-25T06:11:13Z— transitioned toSecretSyncedErrorThat is roughly 80 days of failure, and more usefully, a precise timestamp for what changed. Something happened to
/github/pator to theaws-parameter-storeSecretStore's access to it between 05:11 and 06:11 UTC on 2026-05-25. That is a far better lead than the body's framing.Why it sharpens the SSM question
The body asks someone to check whether
/github/patexists. Still the right check, with a better prior: the parameter was readable on 2026-05-25 at 05:11Z. So the likely candidates are a deleted or renamed parameter, or a credential/permission change on the store — not a key that was never created.Message: could not get secret data from provideris the provider-level error, distinct from the event'sSecret does not exist. Worth confirming the IAM identity behind theSecretStorestill hasssm:GetParameteron that path, since a permissions failure can surface as a not-found.Unchanged
The rest of the issue stands: the
default-namespace ExternalSecrets remain untracked in any repository,null-dbis still a live Postgres with data and no manifest, and theprune: falseexplanation for why orphans persist is unaffected. I have only re-derived timings forexternal-secrets/github-pat; the other rows' occurrence counts are subject to the same 12-day-window caveat and none of them should be read as age.Correction:
null-dbis empty. The "it holds data" caution is void.Kai pointed out the obvious thing I argued past: the name says what it is. Checking the numbers, it holds up.
The body says the
null-prefix reading is "undercut bynull-db-0being a live running Postgres pod ... with a bound 5Gi PVC holding 47MB, so at least that one is not inert." That inference was wrong. 47MB is the empty-Postgres floor, not evidence of content.The comparison that settles it
sirens-echo/sirens-echo-job-store-datasirens-deep/sirens-deep-job-store-datadefault/data-null-db-0forgejo/forgejo-db-datacoilysiren-eco-gnome/eco-gnome-db-dataThe two job stores are byte-identical at 48,291,840 — and deploy's own README describes those manifests as provisioning "an empty database", with the harness applying its own migrations on boot. So that figure is a known empty-
postgres:17baseline.null-dbsits 524,288 bytes below that baseline and carries the lowest RSS of any Postgres in the cluster. It has less on disk than two databases documented as empty, and it is idle.What it is
StatefulSet/null-db, 84 days old,1/1ClusterIPServicenull-dbon 5432null-service(ClusterIP, port 80, 90 days old)A consistent
null-family:null-db,null-service,null-datastore-token,null-sentry. That reads as a deliberate null-object set — placeholders that exist so something has a resolvable target — which is also the most natural explanation for why their ExternalSecrets point at SSM keys that do not exist. I do not know their original purpose and am not asserting one.What changes
The Notes section's blocker is removed. I wrote that deletion was risky because
null-dbholds data. It does not. If these are confirmed as decommissionable placeholders, there is no data-loss risk in removing the StatefulSet, its PVC, and thenull-*ExternalSecrets — only the ordinary care of confirming nothing resolvesnull-db:5432ornull-service.The
null-*ExternalSecret failures may be by design. If these are null objects, three of the eight rows in the body's table are expected-failing and not defects. That would leave the real signal as:external-secrets/github-pat— tracked, previously synced, broke 2026-05-25 (see the correction above)default/docker-registry— untracked, reads/github/patcoilysiren-eco-app/ts-authkeyandcoilysiren-eco-app-sentry— a live service whose credentials do not resolveThat last pair is the one worth attention, and it was getting lost among the placeholders.
Limits of this check
I inferred emptiness from disk footprint and RSS, not from
pg_database_sizeor a table listing — the guarded kubectl surface has noexecverb, so I could not query the database directly. The evidence is strong but circumstantial. Anyone with a shell should confirm before deleting, which is a one-command check.Resolved. Zero ExternalSecrets are failing on kai-server.
All 100, every one synced. The
defaultnamespace, called out here specifically, now holds exactly one ExternalSecret (eco-admin-token) and it is healthy.I did not establish how they were resolved, only that they are. The consumers appear to have been deleted rather than repointed: the three named in the sibling issue #589 all return
NotFound, and/github/patdoes not exist in SSM either. So the drift was cleaned up from the consumer side at some point and nothing recorded it here.This and #766 or #809 (whichever you are not reading) shared 12 rare identifiers in a duplicate scan, which is how the pair surfaced. Closing both.