Skip to content

Commit 0cce847

Browse files
fix(ske): use shared OIDC token adapters
1 parent 309e0e8 commit 0cce847

2 files changed

Lines changed: 145 additions & 25 deletions

File tree

internal/cmd/ske/kubeconfig/login/login.go

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -450,7 +450,13 @@ func workloadIdentityConfigured() bool {
450450
}
451451

452452
func getWorkloadIdentityAccessToken() (string, error) {
453-
roundTripper, err := sdkAuth.SetupAuth(&sdkConfig.Configuration{WorkloadIdentityFederation: true})
453+
// A nil token function intentionally preserves the SDK's projected-token-file fallback.
454+
tokenFunc, _ := auth.OIDCTokenFunc()
455+
roundTripper, err := sdkAuth.SetupAuth(&sdkConfig.Configuration{
456+
WorkloadIdentityFederation: true,
457+
ServiceAccountEmail: auth.OIDCServiceAccountEmail(),
458+
ServiceAccountFederatedTokenFunc: tokenFunc,
459+
})
454460
if err != nil {
455461
return "", fmt.Errorf("configure workload identity federation: %w", err)
456462
}

internal/cmd/ske/kubeconfig/login/login_test.go

Lines changed: 138 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,13 @@ import (
1818
"github.com/google/uuid"
1919
"github.com/spf13/cobra"
2020
"github.com/spf13/viper"
21-
"github.com/stackitcloud/stackit-sdk-go/core/clients"
2221
ske "github.com/stackitcloud/stackit-sdk-go/services/ske/v2api"
2322
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
2423
"k8s.io/apimachinery/pkg/runtime"
2524
clientauthenticationv1 "k8s.io/client-go/pkg/apis/clientauthentication/v1"
2625
"k8s.io/client-go/rest"
2726

27+
"github.com/stackitcloud/stackit-cli/internal/pkg/auth"
2828
"github.com/stackitcloud/stackit-cli/internal/pkg/config"
2929
"github.com/stackitcloud/stackit-cli/internal/pkg/testparams"
3030
"github.com/stackitcloud/stackit-cli/internal/pkg/utils"
@@ -246,20 +246,72 @@ func TestGetAccessTokenFromEnvironmentWithoutStoredSession(t *testing.T) {
246246
}
247247

248248
func TestWorkloadIdentityConfigured(t *testing.T) {
249-
tokenPath := t.TempDir() + "/token"
250-
if err := os.WriteFile(tokenPath, []byte("federated-token"), 0o600); err != nil {
251-
t.Fatalf("write federated token: %v", err)
252-
}
253-
t.Setenv(envServiceAccountEmail, "workload@sa.stackit.cloud")
254-
t.Setenv(clients.FederatedTokenFileEnv, tokenPath)
255-
256-
if !workloadIdentityConfigured() {
257-
t.Fatal("Expected workload identity to be configured")
249+
tests := []struct {
250+
name string
251+
configure func(t *testing.T)
252+
expected bool
253+
}{
254+
{
255+
name: "explicit OIDC",
256+
configure: func(t *testing.T) {
257+
t.Setenv(auth.EnvUseOIDC, "1")
258+
},
259+
expected: true,
260+
},
261+
{
262+
name: "static federated token",
263+
configure: func(t *testing.T) {
264+
t.Setenv(auth.EnvServiceAccountFederatedToken, "federated-token")
265+
},
266+
expected: true,
267+
},
268+
{
269+
name: "federated token file",
270+
configure: func(t *testing.T) {
271+
t.Setenv(auth.EnvFederatedTokenFile, "/projected/token")
272+
},
273+
expected: true,
274+
},
275+
{
276+
name: "GitHub Actions",
277+
configure: func(t *testing.T) {
278+
t.Setenv(auth.EnvGitHubRequestURL, "https://github.example.test/oidc")
279+
t.Setenv(auth.EnvGitHubRequestToken, "request-token")
280+
},
281+
expected: true,
282+
},
283+
{
284+
name: "Azure DevOps",
285+
configure: func(t *testing.T) {
286+
t.Setenv(auth.EnvAzureOIDCRequestURI, "https://azure.example.test/oidc")
287+
t.Setenv(auth.EnvAzureAccessToken, "access-token")
288+
},
289+
expected: true,
290+
},
291+
{
292+
name: "missing token source",
293+
configure: func(_ *testing.T) {},
294+
expected: false,
295+
},
296+
{
297+
name: "missing service account email",
298+
configure: func(t *testing.T) {
299+
t.Setenv(envServiceAccountEmail, "")
300+
t.Setenv(auth.EnvServiceAccountFederatedToken, "federated-token")
301+
},
302+
expected: false,
303+
},
258304
}
259305

260-
t.Setenv(envServiceAccountEmail, "")
261-
if workloadIdentityConfigured() {
262-
t.Fatal("Expected workload identity not to be configured without a service account email")
306+
for _, tt := range tests {
307+
t.Run(tt.name, func(t *testing.T) {
308+
clearOIDCTokenSourceEnv(t)
309+
t.Setenv(envServiceAccountEmail, "workload@sa.stackit.cloud")
310+
tt.configure(t)
311+
if actual := workloadIdentityConfigured(); actual != tt.expected {
312+
t.Fatalf("workloadIdentityConfigured() = %t, want %t", actual, tt.expected)
313+
}
314+
})
263315
}
264316
}
265317

@@ -297,20 +349,82 @@ func TestGetWorkloadIdentityAccessToken(t *testing.T) {
297349
}))
298350
defer server.Close()
299351

300-
tokenPath := t.TempDir() + "/token"
301-
if err := os.WriteFile(tokenPath, []byte(federatedToken), 0o600); err != nil {
302-
t.Fatalf("write federated token: %v", err)
352+
tests := []struct {
353+
name string
354+
configure func(t *testing.T)
355+
}{
356+
{
357+
name: "static federated token",
358+
configure: func(t *testing.T) {
359+
t.Setenv(auth.EnvServiceAccountFederatedToken, federatedToken)
360+
},
361+
},
362+
{
363+
name: "federated token file",
364+
configure: func(t *testing.T) {
365+
tokenPath := t.TempDir() + "/token"
366+
if err := os.WriteFile(tokenPath, []byte(federatedToken), 0o600); err != nil {
367+
t.Fatalf("write federated token: %v", err)
368+
}
369+
t.Setenv(auth.EnvFederatedTokenFile, tokenPath)
370+
},
371+
},
372+
{
373+
name: "GitHub Actions",
374+
configure: func(t *testing.T) {
375+
oidcServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
376+
w.Header().Set("Content-Type", "application/json")
377+
_ = json.NewEncoder(w).Encode(map[string]string{"value": federatedToken})
378+
}))
379+
t.Cleanup(oidcServer.Close)
380+
t.Setenv(auth.EnvGitHubRequestURL, oidcServer.URL)
381+
t.Setenv(auth.EnvGitHubRequestToken, "request-token")
382+
},
383+
},
384+
{
385+
name: "Azure DevOps",
386+
configure: func(t *testing.T) {
387+
oidcServer := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, _ *http.Request) {
388+
w.Header().Set("Content-Type", "application/json")
389+
_ = json.NewEncoder(w).Encode(map[string]string{"oidcToken": federatedToken})
390+
}))
391+
t.Cleanup(oidcServer.Close)
392+
t.Setenv(auth.EnvAzureOIDCRequestURI, oidcServer.URL)
393+
t.Setenv(auth.EnvAzureAccessToken, "access-token")
394+
},
395+
},
303396
}
304-
t.Setenv(envServiceAccountEmail, serviceAccountEmail)
305-
t.Setenv(clients.FederatedTokenFileEnv, tokenPath)
306-
t.Setenv("STACKIT_IDP_TOKEN_ENDPOINT", server.URL)
307397

308-
actual, err := getWorkloadIdentityAccessToken()
309-
if err != nil {
310-
t.Fatalf("get workload identity access token: %v", err)
398+
for _, tt := range tests {
399+
t.Run(tt.name, func(t *testing.T) {
400+
clearOIDCTokenSourceEnv(t)
401+
t.Setenv(envServiceAccountEmail, serviceAccountEmail)
402+
t.Setenv("STACKIT_IDP_TOKEN_ENDPOINT", server.URL)
403+
tt.configure(t)
404+
405+
actual, err := getWorkloadIdentityAccessToken()
406+
if err != nil {
407+
t.Fatalf("get workload identity access token: %v", err)
408+
}
409+
if actual != accessToken {
410+
t.Fatalf("Expected access token %q, got %q", accessToken, actual)
411+
}
412+
})
311413
}
312-
if actual != accessToken {
313-
t.Fatalf("Expected access token %q, got %q", accessToken, actual)
414+
}
415+
416+
func clearOIDCTokenSourceEnv(t *testing.T) {
417+
t.Helper()
418+
for _, env := range []string{
419+
auth.EnvUseOIDC,
420+
auth.EnvServiceAccountFederatedToken,
421+
auth.EnvFederatedTokenFile,
422+
auth.EnvGitHubRequestURL,
423+
auth.EnvGitHubRequestToken,
424+
auth.EnvAzureOIDCRequestURI,
425+
auth.EnvAzureAccessToken,
426+
} {
427+
t.Setenv(env, "")
314428
}
315429
}
316430

0 commit comments

Comments
 (0)