Skip to content

Fix nil pointer panic in GetImagePullSecrets with useSecretsForPrivateRepositories: false - #416

Open
jorisd wants to merge 1 commit into
deckhouse:mainfrom
jorisd:fix-nil-secretindexer-panic
Open

jorisd wants to merge 1 commit into
deckhouse:mainfrom
jorisd:fix-nil-secretindexer-panic

Conversation

@jorisd

@jorisd jorisd commented Aug 17, 2026

Copy link
Copy Markdown

Fixes #343.

Root cause

In NewChecker (pkg/registry/checker.go), the startup probe against Secrets("default").List() only assigns controllerIndexers.secretIndexer on the success branch:

if statusError, isStatus := enumerr.(*k8sapierrors.StatusError); isStatus {
    if statusError.ErrStatus.Code == 401 {
        logrus.Warn(...)
    } else {
        logrus.WithFields(...).Error("Error trying to list secrets")
    }
} else if err != nil {
    logrus.Fatal(err.Error())
} else {
    rc.controllerIndexers.secretIndexer = rc.secretsInformer.Informer().GetIndexer()
}

When useSecretsForPrivateRepositories: false is set, the ClusterRole grants no access to secrets, so the probe fails with a 403 StatusError — which falls into the isStatus branch, not the 401 sub-case, so secretIndexer is never assigned and stays nil.

The secrets informer is still started unconditionally by informerFactory.Start(stopCh) a few lines below, regardless of this probe's outcome. Nothing else guards against secretIndexer being nil, so as soon as any watched workload has an imagePullSecret configured, GetImagePullSecrets (pkg/registry/indexers.go) calls ci.secretIndexer.GetByKey(ref) on a nil cache.Indexer and panics with a SIGSEGV. The pod then crash-loops permanently, since the same workload set is reconciled on every restart.

Fix

Assign secretIndexer unconditionally, right after the probe, instead of only on the success path. The underlying store simply stays permanently empty when RBAC denies access — which is the degraded/anonymous behavior the useSecretsForPrivateRepositories: false setting is already meant to support (per the existing 401 warning message), it just never got wired up for the "informer running but never synced" case.

This reproduces reliably and is confirmed by two independent reports on #343 (v0.13.0 and v0.14.0, both with useSecretsForPrivateRepositories: false). Credit to @ex-trim for identifying that setting useSecretsForPrivateRepositories: true works around it, and for the initial idea of moving the indexer assignment — this PR keeps the original probe/logging behavior intact and only changes where secretIndexer gets set.

Testing

Manually verified against our own deployment: with useSecretsForPrivateRepositories: false and at least one workload carrying an imagePullSecret, the unpatched binary panics within a few reconcile cycles; same workload set with this change applied no longer panics (secret lookups just resolve to "not found", as expected for the RBAC-restricted mode).

…orbidden

The startup probe against Secrets("default").List() only assigned
controllerIndexers.secretIndexer on the success path. Whenever the
probe failed with a non-401 StatusError (e.g. 403 Forbidden, which is
exactly what happens when useSecretsForPrivateRepositories is set to
false and the ClusterRole grants no access to secrets), secretIndexer
was left nil.

The secrets informer is started by informerFactory.Start() regardless
of this probe, so nothing prevents GetImagePullSecrets from later
calling ci.secretIndexer.GetByKey() on any workload that has an
imagePullSecret configured, causing a SIGSEGV.

Assign secretIndexer unconditionally: the underlying store just stays
permanently empty when RBAC denies access, which is the degraded mode
the anonymous/RBAC-restricted setup was already intended to support.

Fixes deckhouse#343

Signed-off-by: joris <344303+jorisd@users.noreply.github.com>
@jorisd
jorisd force-pushed the fix-nil-secretindexer-panic branch from 95bb284 to e696892 Compare September 23, 2026 18:00

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

runtime error: invalid memory address or nil pointer dereference

1 participant