Skip to content

Commit c209320

Browse files
committed
pkg/storage/azure: add support for auth with workload identity
1 parent 28370b7 commit c209320

File tree

2 files changed

+83
-22
lines changed

2 files changed

+83
-22
lines changed

pkg/storage/azure/azure.go

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -60,12 +60,13 @@ var storageAccountInvalidCharRe = regexp.MustCompile(`[^0-9A-Za-z]`)
6060
// Azure holds configuration used to reach Azure's endpoints.
6161
type Azure struct {
6262
// IPI
63-
SubscriptionID string
64-
ClientID string
65-
ClientSecret string
66-
TenantID string
67-
ResourceGroup string
68-
Region string
63+
SubscriptionID string
64+
ClientID string
65+
ClientSecret string
66+
TenantID string
67+
ResourceGroup string
68+
Region string
69+
FederatedTokenFile string
6970

7071
// UPI
7172
AccountKey string
@@ -95,14 +96,27 @@ func GetConfig(secLister kcorelisters.SecretNamespaceLister, infraLister configl
9596
return nil, fmt.Errorf("unable to get cluster minted credentials: %s", err)
9697
}
9798

98-
return &Azure{
99-
SubscriptionID: string(sec.Data["azure_subscription_id"]),
100-
ClientID: string(sec.Data["azure_client_id"]),
101-
ClientSecret: string(sec.Data["azure_client_secret"]),
102-
TenantID: string(sec.Data["azure_tenant_id"]),
103-
ResourceGroup: string(sec.Data["azure_resourcegroup"]),
104-
Region: string(sec.Data["azure_region"]),
105-
}, nil
99+
cfg := &Azure{
100+
SubscriptionID: string(sec.Data["azure_subscription_id"]),
101+
ClientID: string(sec.Data["azure_client_id"]),
102+
ClientSecret: string(sec.Data["azure_client_secret"]),
103+
TenantID: string(sec.Data["azure_tenant_id"]),
104+
ResourceGroup: string(sec.Data["azure_resourcegroup"]),
105+
Region: string(sec.Data["azure_region"]),
106+
FederatedTokenFile: string(sec.Data["azure_federated_token_file"]),
107+
}
108+
109+
// when using azure workload identities, the secret does not contain
110+
// a resource group, as it is not known at the time of its creation.
111+
if cfg.ResourceGroup == "" {
112+
infra, err := util.GetInfrastructure(infraLister)
113+
if err != nil {
114+
return nil, fmt.Errorf("unable to get infrastructure object: %s", err)
115+
}
116+
cfg.ResourceGroup = infra.Status.PlatformStatus.Azure.ResourceGroupName
117+
}
118+
119+
return cfg, nil
106120
}
107121

108122
// loads user provided account key.
@@ -316,15 +330,36 @@ func (d *driver) storageAccountsClient(cfg *Azure, environment autorestazure.Env
316330
},
317331
},
318332
}
319-
options := azidentity.ClientSecretCredentialOptions{
320-
ClientOptions: azcore.ClientOptions{
321-
Cloud: cloudConfig,
322-
},
323-
}
324-
cred, err := azidentity.NewClientSecretCredential(cfg.TenantID, cfg.ClientID, cfg.ClientSecret, &options)
325-
if err != nil {
326-
return storage.AccountsClient{}, err
333+
334+
var (
335+
cred azcore.TokenCredential
336+
err error
337+
)
338+
if strings.TrimSpace(cfg.ClientSecret) == "" {
339+
options := azidentity.WorkloadIdentityCredentialOptions{
340+
ClientOptions: azcore.ClientOptions{
341+
Cloud: cloudConfig,
342+
},
343+
ClientID: cfg.ClientID,
344+
TenantID: cfg.TenantID,
345+
TokenFilePath: cfg.FederatedTokenFile,
346+
}
347+
cred, err = azidentity.NewWorkloadIdentityCredential(&options)
348+
if err != nil {
349+
return storage.AccountsClient{}, err
350+
}
351+
} else {
352+
options := azidentity.ClientSecretCredentialOptions{
353+
ClientOptions: azcore.ClientOptions{
354+
Cloud: cloudConfig,
355+
},
356+
}
357+
cred, err = azidentity.NewClientSecretCredential(cfg.TenantID, cfg.ClientID, cfg.ClientSecret, &options)
358+
if err != nil {
359+
return storage.AccountsClient{}, err
360+
}
327361
}
362+
328363
scope := environment.TokenAudience
329364
if !strings.HasSuffix(scope, "/.default") {
330365
scope += "/.default"

pkg/storage/azure/azure_test.go

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,32 @@ func TestGetConfig(t *testing.T) {
153153
Region: "region",
154154
},
155155
},
156+
{
157+
name: "cloud credentials workload identity",
158+
secrets: []runtime.Object{
159+
&corev1.Secret{
160+
ObjectMeta: metav1.ObjectMeta{
161+
Name: defaults.CloudCredentialsName,
162+
Namespace: "test",
163+
},
164+
Data: map[string][]byte{
165+
"azure_client_id": []byte("client_id"),
166+
"azure_federated_token_file": []byte("/path/to/token"),
167+
"azure_region": []byte("region"),
168+
"azure_subscription_id": []byte("subscription_id"),
169+
"azure_tenant_id": []byte("tenant_id"),
170+
},
171+
},
172+
},
173+
result: &Azure{
174+
SubscriptionID: "subscription_id",
175+
ClientID: "client_id",
176+
TenantID: "tenant_id",
177+
ResourceGroup: "resource-group-123",
178+
Region: "region",
179+
FederatedTokenFile: "/path/to/token",
180+
},
181+
},
156182
} {
157183
t.Run(tt.name, func(t *testing.T) {
158184
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})

0 commit comments

Comments
 (0)