Give the manager its own trusted bundle for the Tigera OIDC type - #5142
Open
tmjd wants to merge 1 commit into
Open
Give the manager its own trusted bundle for the Tigera OIDC type#5142tmjd wants to merge 1 commit into
tmjd wants to merge 1 commit into
Conversation
tmjd
force-pushed
the
tsla-11722-manager-named-bundle
branch
from
August 5, 2026 20:16
d310544 to
8e0394f
Compare
For Authentication.spec.oidc.type: Tigera, handleCloudReconcile threw away the manager's component-named trusted bundle and replaced it with one from CreateTrustedBundleWithSystemRootCertificates(), which renders the default-named tigera-ca-bundle. That ConfigMap is owned by the core controller, which renders it into the same namespace - render.ManagerNamespace is common.CalicoNamespace - with a different set of certificates: the node and typha key pairs, plus the legacy typha-ca ConfigMap on clusters old enough to still carry one. Two controllers writing one ConfigMap with different contents overwrite each other, so the bundle alternates between two values. calico-manager mounts it directly and es-calico-kube-controllers inherits its hash annotations via LoadTrustedBundle, so both deployments alternate between two pod templates and roll repeatedly. The rollouts arrive in bursts rather than as a steady loop, since neither controller rebuilds the bundle on every reconcile. Both deployments stay available throughout, because each flip is an ordinary rolling update, so the cost is unnecessary restarts, log noise and a revision history that grows without bound. Kubernetes reuses the two ReplicaSets and bumps deployment.kubernetes.io/revision on each switch back, so the revision number can climb a long way while only a handful of ReplicaSets are ever created. The only thing the Tigera OIDC type actually needs is the system root certificates, so pass that as a flag to the one call that already builds the manager's bundle instead of rebuilding it. The manager is then always backed by a bundle named for itself, and handleCloudReconcile no longer takes part in building it - it just checks that the certificates the bundle trusts are available. That also drops a redundant AddCertificates loop which, on the cloud path, added every trusted secret a second time and so duplicated any certificate not signed by our own CA. The mount paths inside the container are constants, so only the ConfigMap and volume names change. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
tmjd
force-pushed
the
tsla-11722-manager-named-bundle
branch
from
August 5, 2026 20:46
8e0394f to
fa4383d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Bug fix. On clusters configured with the Tigera OIDC type,
calico-managerandes-calico-kube-controllersrepeatedly roll their pods, alternating between two pod templates.Impact
This is not a steady loop. Neither controller rewrites the bundle on every reconcile — the 5 minute periodic resync does not re-trigger it — so rollouts arrive in bursts, each set off by something that makes one of the controllers rebuild the bundle from cold: an upgrade, a manager restart, or a certificate rotation. Within a burst, replacements follow one another within seconds; between bursts the deployments can sit quiet for hours.
Both deployments stay available the whole time, since each flip is an ordinary rolling update. The cost is repeated unnecessary restarts, log and event noise, write contention on the shared ConfigMap (
Operation cannot be fulfilled on configmaps "tigera-ca-bundle"), and a revision history that grows without bound — not downtime.Root cause
For
Authentication.spec.oidc.type: Tigera,handleCloudReconcilediscards the manager's component-named trusted bundle and replaces it with one fromCreateTrustedBundleWithSystemRootCertificates(), which renders the default-namedtigera-ca-bundle(manager_controller_cloud.go:80-87):That ConfigMap is owned by the core controller, which renders it with a different set of certificates — the
nodeandtyphakey pairs, plus the legacytigera-operator/typha-caConfigMap on clusters old enough to still carry one (core_controller.go:1978-1990). Both land in the same namespace, sincerender.ManagerNamespaceiscommon.CalicoNamespace.Two controllers writing one ConfigMap with different contents overwrite each other, so
calico-system/tigera-ca-bundlealternates between exactly two values. Both consumers flip with it:calico-managermounts the bundle and hashes its data keys, so its pod-template annotations flip.es-calico-kube-controllersobtains it viacm.LoadTrustedBundle(), which copies the ConfigMap'shash.operator.tigera.io/*annotations onto the dependent workload — including the namespace-prefixedcalico-system.hash.operator.tigera.io/typha-cakey, which appears and disappears.Each deployment therefore oscillates between two pod templates. Kubernetes reuses the two ReplicaSets rather than creating new ones and simply bumps
deployment.kubernetes.io/revisionon each switch back, so a deployment can reach a revision number in the hundreds or thousands while only ever having created a handful of ReplicaSets. Diffing the two ReplicaSets of either deployment shows thetypha-caannotation and the bundle content hash as the only pod-template differences.Which clusters this affects
The extra certificate comes from the legacy
typha-caConfigMap, which only exists on clusters installed by an operator older than v1.29:b0fce5783(2022-03-04) replaced the dedicated Typha/Felix CA with the central CA, and nothing has ever deleted the old ConfigMap. Where one is present the two writers' bundles differ and the deployments flip. On a cluster installed after that change neither bundle contains it, both writers produce identical content, the second write is a no-op, and nothing flaps.Deleting the stale ConfigMap therefore stops the churn, but that is a mitigation rather than a fix — the two-writer conflict remains latent and resurfaces wherever the two controllers' inputs diverge for any other reason.
The change
The only thing the Tigera OIDC type actually needs is the system root certificates, so pass that as a flag to the one call that already builds the manager's bundle, rather than rebuilding it:
authenticationCRis already fetched above this point, so the decision can be made here. The manager is then always backed by a bundle named for itself, andhandleCloudReconcileno longer takes part in building it — it only checks that the certificates the bundle trusts are available, and itsauthenticationCRparameter is gone.That also removes a redundant
AddCertificatesloop.AddCertificatesappends rather than deduplicating by name (it skips only nil entries and certificates signed by our own CA), so on the cloud path every trusted secret was added a second time and any certificate not signed by our CA — a BYO cert — ended up duplicated in the bundle. Certificates are now added exactly once, by the single constructor call.Upgrade impact
The manager now creates and mounts
calico-manager-ca-bundle-system-certsinstead of the sharedtigera-ca-bundle. Worth a reviewer's attention:tigera-ca-bundlefor its other consumers.VolumeMounts()uses the constantTrustedCertVolumeMountPath, and only the ConfigMap and volume names derive from the bundle name. Voltron and manager keep reading the same files.calico-managerrolls once on upgrade as the new volume is mounted.Testing
should leave the manager's trusted bundle alone on the cloud pathpasses a component-named bundle intohandleCloudReconcileand asserts the bundle handed back is still that one, and is nottigera-ca-bundle. Verified it fails if the override is reintroduced, producingtigera-ca-bundle.handleCloudReconcilerather thanReconcile, because reaching this code throughReconcilerequiresutils.GetKeyValidatorConfig→tigerakvc.New, which performs live OIDC discovery and JWKS fetches against the issuer. That is also why this path had no prior unit coverage at all. It does mean theincludeSystemRootsexpression itself is not unit-covered; a fake-issuer harness would let a future test cover it, and would be a worthwhile follow-up.go test ./pkg/controller/manager/...passes (29 specs).gofmtclean; the repo pre-commit hook passes.Components affected
The manager controller on the Tigera OIDC path. Multi-tenant and other OIDC types already used the named bundle and are unaffected.
Release Note
For PR author
make gen-filesmake gen-versionsFor PR reviewers
A note for code reviewers - all pull requests must have the following:
kind/bugif this is a bugfix.kind/enhancementif this is a a new feature.enterpriseif this PR applies to Calico Enterprise only.