fix: prevent yurthub from overwriting valid kube-system token with empty bearer token in tenant mode - #2764
Conversation
- Only rewrite Authorization header when GetTenantToken() returns a valid, non-empty token. - Avoids stripping credentials on k8s >=1.24 where legacy SA secrets aren't auto-created, preventing edge traffic disruption. - Removed plaintext token logging for security.
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## master #2764 +/- ##
==========================================
+ Coverage 46.20% 46.22% +0.02%
==========================================
Files 405 405
Lines 27540 27569 +29
==========================================
+ Hits 12724 12743 +19
- Misses 13649 13655 +6
- Partials 1167 1171 +4
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
|
Hi @zyjhtangtang @luc99hen sir , yurthub was replacing a valid kube-system token with an empty one Added a test covering all three cases: token available, token missing, If CI shows a failure on prepare_autonomy_tests, that's unrelated too — Thanks for reviewing! |



What type of PR is this?
/kind bug
What this PR does / why we need it:
WithSaTokenSubstitute(pkg/yurthub/proxy/util/util.go) replaces therequest's
Authorizationheader with the tenant's token whenever therequest is authenticated as a kube-system service account and the tenant
secret informer has synced. It unconditionally called
GetTenantToken()and, if that returned an empty string, the header became
Authorization: Bearer(empty) — destroying the original, still-validtoken.
GetTenantToken()returns""wheneverTenantSecret == nil, andTenantSecretis only set once the informer observes a defaultservice-account token secret in the tenant namespace. On Kubernetes
Consequence: as soon as the tenant informer synced but before the tenant
token secret appeared, every kube-system request through the hub had its
valid token overwritten with an empty one, and the tenant kube-apiserver
returned 401 for all of them — with no fallback and no error surfaced,
fully cutting off the edge node in tenant mode until the secret showed
up.
Secondary issue: the existing log line printed the full old and new
token values in plaintext.
This PR:
Authorizationheader whenGetTenantToken()returns a non-empty token; otherwise keeps the original header
untouched and logs a warning instead.
TestWithSaTokenSubstituteWithStubTenantwith a stubtenant.Interface, covering three cases: non-empty token → headerreplaced, empty token → original header preserved,
WaitForCacheSync()false → original header preserved.Verified locally (WSL2, matching CI's Go 1.25.0 / golangci-lint v2.11.4):
all clean — 0 test failures, 0 data races, 0 vet issues, 0 lint issues.
Which issue(s) this PR fixes:
Fixes #2761
Special notes for your reviewer:
When the tenant token is unavailable, requests now go out with the
original kube-system token instead of an empty one. The tenant apiserver
may still reject it (401/403) if RBAC doesn't map that identity, which is
the same outcome as today during the missing-secret window — but we no
longer actively destroy a token that could be valid (e.g., if the tenant
apiserver is configured to accept the kube-system identity).
No other callers of
GetTenantToken/GetTenantNsare affected by thischange.
Does this PR introduce a user-facing change?
other Note