fix(apiserver): allow queryserver egress to Linseed via guardian on managed clusters - #5240
Conversation
…anaged clusters A managed cluster runs no local Linseed, so the queryserver reaches it through guardian. The apiserver-access policy only permitted the local Linseed pods, which select nothing on a managed cluster, so the request fell through to the trailing Pass and was denied by whatever the customer's tiers enforce. Branch the rule the same way LINSEED_URL is already branched in this file: guardian when a ManagementClusterConnection is present, local Linseed otherwise. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Pull request overview
Updates the Calico Enterprise API server extension to ensure the queryserver can reach Linseed on managed clusters by allowing egress to Linseed through Guardian, aligning network policy behavior with the LINSEED_URL endpoint logic.
Changes:
- Insert a Guardian-targeted egress allow rule ahead of the trailing
Passrule whenManagementClusterConnectionis present. - Extract a shared
insertEgressBeforePasshelper to avoid duplicating the slice-capacity-safe insertion logic. - Add unit tests asserting the Guardian egress rule is present (managed clusters) and absent (non-managed clusters).
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated no comments.
| File | Description |
|---|---|
| pkg/enterprise/apiserver/extension.go | Adds managed-cluster Guardian egress rule insertion and factors out insertEgressBeforePass. |
| pkg/enterprise/apiserver/extension_test.go | Adds specs verifying Guardian egress rule rendering behavior based on managed-cluster inputs. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
|
|
||
| // insertEgressBeforePass inserts rule ahead of the policy's trailing Pass rule, so that it is | ||
| // evaluated before the tier hands the traffic to subsequent tiers. | ||
| func insertEgressBeforePass(policy *v3.NetworkPolicy, rule v3.Rule) { |
There was a problem hiding this comment.
This is a pretty specific function that I'm not sure adds benefit over what was previously in lined. It's doing nothing special, just appending rules and there's not even any guarantee that the rule given here is a "Pass" rule, it's just a rule.
Description
A managed cluster runs no local Linseed, so the query server reaches it through guardian —
the URL
LinseedEndpointreturns asLINSEED_URL. Thecalico-system.apiserver-accesspolicy permitted only the local Linseed pods, whose selector matches nothing on a managed
cluster, so the connection fell through to the policy's trailing
Pass. Thecalico-systemtier's default-deny excludes
calico-apiserverby design, so the traffic is then evaluatedagainst the customer's tiers, where any default-deny drops it.
The Manager policy board renders empty and the API call fails:
This branches the egress rule on the same condition
LINSEED_URLalready uses in this file:render.GuardianEntityRulewhen aManagementClusterConnectionis present, local Linseedotherwise.
The inert local-Linseed rule stays in the base policy in
pkg/render/apiserver.go. It selectsno pods on a managed cluster, and
APIServerConfigurationcarries no cluster type to branchon. Moving it into the extension would correct the layering at the cost of churning the base
fixture, which is better done on master alone than in a change that cherry-picks to four
release branches.
insertEgressBeforePassis extracted rather than duplicated. The OIDC path already used thecapacity-capped
egress[:n-1:n-1]slice to avoid aliasing the backing array; both callers nowshare it. Behaviour is unchanged.
Introduced in #4571, which added the dependency, hardcoded the guardian URL for managed
clusters, and shipped an egress rule covering only the self-hosted destination. #4786 later
refactored the URL onto the
LinseedEndpointhelper and #4871 moved it intopkg/enterprise/apiserver/; neither added the missing rule. First shipped in operatorv1.42.0, sorelease-v1.42throughrelease-v1.44need cherry-picks.Addresses CI-2048.
Testing
Verified end-to-end on a live Enterprise MCM managed cluster. A deny policy was applied in the
defaulttier selectingcalico-apiserver, standing in for the customer'sdeny-calico-system, and left in place for both runs. Only the operator image changed:GET /policiesv1.45.0-0.dev-23-g40788b9b6befcalico-systemtier presentThe 500 carried the reported error verbatim:
Also checked at the dataplane, with a probe pod carrying the
k8s-app: calico-apiserverlabel:TCP to guardian succeeded only with the fix, while a control destination the policy does not
permit stayed blocked in both runs — confirming the deny was genuinely in force rather than the
cluster being permissive.
Two things the cluster surfaced that the unit tests could not. The rendered rule is port 8080
while the query server dials
https://guardian.calico-system.svcon 443; that is correct,because the guardian Service is
443 → targetPort 8080and Calico enforces egress against thepost-DNAT pod port. And guardian's own ingress policy already has an unrestricted
Allow ... ports=[8080]rule, so there is no ingress-side gap and this egress-only change issufficient.
Unit tests: new spec asserting the guardian rule is rendered ahead of the trailing
Passwhena
ManagementClusterConnectionis present, and a companion spec asserting its absenceotherwise. Reverting the production change while keeping the tests fails the managed-cluster
spec.
pkg/enterprise/apiserver51/51,pkg/controller/apiserver28/28,pkg/rendergreen.make format-checkclean,make static-checksreports 0 issues.Backports: #5260 (
release-v1.42), #5261 (release-v1.43), #5262 (release-v1.43-2),#5263 (
release-v1.44).release-v1.41carries neither the egress rule norLINSEED_URL, sothe affected range starts at
release-v1.42(CE v3.23.1).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.🤖 Generated with Claude Code