Skip to content

Commit e3e6989

Browse files
committed
Key cache on cluster server URL + user name when available
kcc-injector now sets provideClusterInfo on injected exec configs, so kubectl passes the target API server URL to kcc-cache via KUBERNETES_EXEC_INFO. kcc-cache uses that server URL together with the kubeconfig user name (KUBE_CREDENTIAL_CACHE_USER) as the cache key. This makes the key stable against cosmetic argv changes (avoiding needless re-auth) while still discriminating both the target cluster and the identity, so one user's credentials are never served for another on the same cluster. When the server URL is unavailable (provideClusterInfo not set, or a manual setup) it falls back to the previous argv + env key. Re-running `kcc-injector -i ~/.kube/config` once enables it; no other manual setup is required. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DHL4n3s3iBGwQR34JxpDn9
1 parent 4aab249 commit e3e6989

2 files changed

Lines changed: 44 additions & 9 deletions

File tree

cmd/kcc-cache/main.go

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -57,18 +57,47 @@ func main() {
5757
}
5858

5959
// cache key
60-
var cacheKey = strings.Join(os.Args[1:], " ")
60+
//
61+
// When kubectl provides cluster info (provideClusterInfo: true, which
62+
// kcc-injector enables), the target API server URL is available via the
63+
// KUBERNETES_EXEC_INFO env var. Combined with the kubeconfig user name
64+
// (KUBE_CREDENTIAL_CACHE_USER, also set by kcc-injector) this yields a
65+
// stable cache key: it survives cosmetic argv changes and never serves one
66+
// identity's credentials for another identity on the same cluster.
67+
//
68+
// If the server URL is unavailable (provideClusterInfo not set, or a manual
69+
// setup), fall back to the legacy argv + env based key.
70+
var cacheKey string
6171
{
62-
env := ""
63-
for _, key := range cacheKeyEnvlist {
64-
v := os.Getenv(key)
65-
if v == "" {
66-
continue
72+
server := ""
73+
if e := os.Getenv("KUBERNETES_EXEC_INFO"); e != "" {
74+
var execInfo struct {
75+
Spec struct {
76+
Cluster struct {
77+
Server string `json:"server"`
78+
} `json:"cluster"`
79+
} `json:"spec"`
80+
}
81+
if err := json.Unmarshal([]byte(e), &execInfo); err == nil {
82+
server = execInfo.Spec.Cluster.Server
6783
}
68-
env = fmt.Sprintf("%s %s='%s'", env, key, v)
6984
}
70-
if env != "" {
71-
cacheKey = fmt.Sprintf("%s # env:%s", cacheKey, env)
85+
86+
if server != "" {
87+
cacheKey = fmt.Sprintf("user=%q server=%q", os.Getenv("KUBE_CREDENTIAL_CACHE_USER"), server)
88+
} else {
89+
cacheKey = strings.Join(os.Args[1:], " ")
90+
env := ""
91+
for _, key := range cacheKeyEnvlist {
92+
v := os.Getenv(key)
93+
if v == "" {
94+
continue
95+
}
96+
env = fmt.Sprintf("%s %s='%s'", env, key, v)
97+
}
98+
if env != "" {
99+
cacheKey = fmt.Sprintf("%s # env:%s", cacheKey, env)
100+
}
72101
}
73102
}
74103

cmd/kcc-injector/main.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,7 @@ func main() {
7373
if user.Exec.Command == replaceCmd {
7474
user.Exec.Command = user.Exec.Args[0]
7575
user.Exec.Args = user.Exec.Args[1:]
76+
user.Exec.ProvideClusterInfo = false
7677
}
7778

7879
search := func() (index int) {
@@ -103,6 +104,11 @@ func main() {
103104
user.Exec.Command = replaceCmd
104105
}
105106

107+
// Expose the target cluster's API server URL to kcc-cache via the
108+
// KUBERNETES_EXEC_INFO env var, so it can key the cache on the
109+
// cluster (server URL) in addition to the user name.
110+
user.Exec.ProvideClusterInfo = true
111+
106112
found := false
107113
userEnv := api.ExecEnvVar{
108114
Name: "KUBE_CREDENTIAL_CACHE_USER",

0 commit comments

Comments
 (0)