Skip to content

Commit

Permalink
pkg/storage/azure: add support for auth with workload identity
Browse files Browse the repository at this point in the history
  • Loading branch information
flavianmissi committed Jun 9, 2023
1 parent 0cef711 commit 3c29870
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 22 deletions.
79 changes: 57 additions & 22 deletions pkg/storage/azure/azure.go
Expand Up @@ -60,12 +60,13 @@ var storageAccountInvalidCharRe = regexp.MustCompile(`[^0-9A-Za-z]`)
// Azure holds configuration used to reach Azure's endpoints.
type Azure struct {
// IPI
SubscriptionID string
ClientID string
ClientSecret string
TenantID string
ResourceGroup string
Region string
SubscriptionID string
ClientID string
ClientSecret string
TenantID string
ResourceGroup string
Region string
FederatedTokenFile string

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

return &Azure{
SubscriptionID: string(sec.Data["azure_subscription_id"]),
ClientID: string(sec.Data["azure_client_id"]),
ClientSecret: string(sec.Data["azure_client_secret"]),
TenantID: string(sec.Data["azure_tenant_id"]),
ResourceGroup: string(sec.Data["azure_resourcegroup"]),
Region: string(sec.Data["azure_region"]),
}, nil
cfg := &Azure{
SubscriptionID: string(sec.Data["azure_subscription_id"]),
ClientID: string(sec.Data["azure_client_id"]),
ClientSecret: string(sec.Data["azure_client_secret"]),
TenantID: string(sec.Data["azure_tenant_id"]),
ResourceGroup: string(sec.Data["azure_resourcegroup"]),
Region: string(sec.Data["azure_region"]),
FederatedTokenFile: string(sec.Data["azure_federated_token_file"]),
}

// when using azure workload identities, the secret does not contain
// a resource group, as it is not known at the time of its creation.
if cfg.ResourceGroup == "" {
infra, err := util.GetInfrastructure(infraLister)
if err != nil {
return nil, fmt.Errorf("unable to get infrastructure object: %s", err)
}
cfg.ResourceGroup = infra.Status.PlatformStatus.Azure.ResourceGroupName
}

return cfg, nil
}

// loads user provided account key.
Expand Down Expand Up @@ -316,15 +330,36 @@ func (d *driver) storageAccountsClient(cfg *Azure, environment autorestazure.Env
},
},
}
options := azidentity.ClientSecretCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: cloudConfig,
},
}
cred, err := azidentity.NewClientSecretCredential(cfg.TenantID, cfg.ClientID, cfg.ClientSecret, &options)
if err != nil {
return storage.AccountsClient{}, err

var (
cred azcore.TokenCredential
err error
)
if strings.TrimSpace(cfg.ClientSecret) == "" {
options := azidentity.WorkloadIdentityCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: cloudConfig,
},
ClientID: cfg.ClientID,
TenantID: cfg.TenantID,
TokenFilePath: cfg.FederatedTokenFile,
}
cred, err = azidentity.NewWorkloadIdentityCredential(&options)
if err != nil {
return storage.AccountsClient{}, err
}
} else {
options := azidentity.ClientSecretCredentialOptions{
ClientOptions: azcore.ClientOptions{
Cloud: cloudConfig,
},
}
cred, err = azidentity.NewClientSecretCredential(cfg.TenantID, cfg.ClientID, cfg.ClientSecret, &options)
if err != nil {
return storage.AccountsClient{}, err
}
}

scope := environment.TokenAudience
if !strings.HasSuffix(scope, "/.default") {
scope += "/.default"
Expand Down
26 changes: 26 additions & 0 deletions pkg/storage/azure/azure_test.go
Expand Up @@ -153,6 +153,32 @@ func TestGetConfig(t *testing.T) {
Region: "region",
},
},
{
name: "cloud credentials workload identity",
secrets: []runtime.Object{
&corev1.Secret{
ObjectMeta: metav1.ObjectMeta{
Name: defaults.CloudCredentialsName,
Namespace: "test",
},
Data: map[string][]byte{
"azure_client_id": []byte("client_id"),
"azure_federated_token_file": []byte("/path/to/token"),
"azure_region": []byte("region"),
"azure_subscription_id": []byte("subscription_id"),
"azure_tenant_id": []byte("tenant_id"),
},
},
},
result: &Azure{
SubscriptionID: "subscription_id",
ClientID: "client_id",
TenantID: "tenant_id",
ResourceGroup: "resource-group-123",
Region: "region",
FederatedTokenFile: "/path/to/token",
},
},
} {
t.Run(tt.name, func(t *testing.T) {
indexer := cache.NewIndexer(cache.MetaNamespaceKeyFunc, cache.Indexers{})
Expand Down

0 comments on commit 3c29870

Please sign in to comment.