@@ -57,6 +57,10 @@ const (
57
57
azureCredentialsKey = "AzureCredentials"
58
58
)
59
59
60
+ // globalAzureCredentials caches User Assigned Managed Identity (UAMI) credentials across driver instances so that
61
+ // reconciles do not recreate the credential repeatedly.
62
+ var globalAzureCredentials sync.Map
63
+
60
64
// storageAccountInvalidCharRe is a regular expression for characters that
61
65
// cannot be used in Azure storage accounts names (i.e. that are not
62
66
// numbers nor lower-case letters) and that are not upper-case letters. If
@@ -334,7 +338,7 @@ func NewDriver(ctx context.Context, c *imageregistryv1.ImageRegistryConfigStorag
334
338
}
335
339
336
340
func (d * driver ) newAzClient (cfg * Azure , environment autorestazure.Environment , tagset map [string ]* string ) (* azureclient.Client , error ) {
337
- client , err := azureclient . New ( & azureclient.Options {
341
+ clientOptions := & azureclient.Options {
338
342
Environment : environment ,
339
343
TenantID : cfg .TenantID ,
340
344
ClientID : cfg .ClientID ,
@@ -343,10 +347,19 @@ func (d *driver) newAzClient(cfg *Azure, environment autorestazure.Environment,
343
347
SubscriptionID : cfg .SubscriptionID ,
344
348
TagSet : tagset ,
345
349
Policies : d .policies ,
346
- })
350
+ }
351
+
352
+ if cred , ok , err := d .ensureUAMICred (d .Context , environment ); err != nil {
353
+ return nil , err
354
+ } else if ok {
355
+ clientOptions .Creds = cred
356
+ }
357
+
358
+ client , err := azureclient .New (clientOptions )
347
359
if err != nil {
348
360
return nil , err
349
361
}
362
+
350
363
return client , nil
351
364
}
352
365
@@ -381,25 +394,10 @@ func (d *driver) storageAccountsClient(cfg *Azure, environment autorestazure.Env
381
394
// UserAssignedIdentityCredentials is specifically for managed Azure HCP
382
395
userAssignedIdentityCredentialsFilePath := os .Getenv ("MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH" )
383
396
if userAssignedIdentityCredentialsFilePath != "" {
384
- var ok bool
385
-
386
- // We need to only store the Azure credentials once and reuse them after that.
387
- storedCreds , found := d .azureCredentials .Load (azureCredentialsKey )
388
- if ! found {
389
- klog .V (2 ).Info ("Using UserAssignedIdentityCredentials for Azure authentication for managed Azure HCP" )
390
- clientOptions := azcore.ClientOptions {
391
- Cloud : cloudConfig ,
392
- }
393
- cred , err = dataplane .NewUserAssignedIdentityCredential (context .Background (), userAssignedIdentityCredentialsFilePath , dataplane .WithClientOpts (clientOptions ))
394
- if err != nil {
395
- return storage.AccountsClient {}, err
396
- }
397
- d .azureCredentials .Store (azureCredentialsKey , cred )
398
- } else {
399
- cred , ok = storedCreds .(azcore.TokenCredential )
400
- if ! ok {
401
- return storage.AccountsClient {}, fmt .Errorf ("expected %T to be a TokenCredential" , storedCreds )
402
- }
397
+ if c , ok , err := d .ensureUAMICred (d .Context , environment ); err != nil {
398
+ return storage.AccountsClient {}, err
399
+ } else if ok {
400
+ cred = c
403
401
}
404
402
} else if strings .TrimSpace (cfg .ClientSecret ) == "" {
405
403
options := azidentity.WorkloadIdentityCredentialOptions {
@@ -1237,14 +1235,30 @@ func (d *driver) RemoveStorage(cr *imageregistryv1.Config) (retry bool, err erro
1237
1235
}
1238
1236
1239
1237
if d .Config .NetworkAccess != nil && d .Config .NetworkAccess .Internal != nil && d .Config .NetworkAccess .Internal .PrivateEndpointName != "" {
1240
- azclient , err := azureclient . New ( & azureclient.Options {
1238
+ clientOptions := & azureclient.Options {
1241
1239
Environment : environment ,
1242
1240
TenantID : cfg .TenantID ,
1243
1241
ClientID : cfg .ClientID ,
1244
1242
ClientSecret : cfg .ClientSecret ,
1245
1243
FederatedTokenFile : cfg .FederatedTokenFile ,
1246
1244
SubscriptionID : cfg .SubscriptionID ,
1247
- })
1245
+ }
1246
+
1247
+ if cred , ok , err := d .ensureUAMICred (d .Context , environment ); err != nil {
1248
+ util .UpdateCondition (
1249
+ cr ,
1250
+ defaults .StorageExists ,
1251
+ operatorapiv1 .ConditionUnknown ,
1252
+ storageExistsReasonAzureError ,
1253
+ fmt .Sprintf ("Unable to get azure client: %s" , err ),
1254
+ )
1255
+ return false , err
1256
+ } else if ok {
1257
+ klog .V (2 ).Infof ("Using cached UAMI credential for RemoveStorage client" )
1258
+ clientOptions .Creds = cred
1259
+ }
1260
+
1261
+ azclient , err := azureclient .New (clientOptions )
1248
1262
if err != nil {
1249
1263
util .UpdateCondition (
1250
1264
cr ,
@@ -1320,3 +1334,38 @@ func (d *driver) RemoveStorage(cr *imageregistryv1.Config) (retry bool, err erro
1320
1334
func (d * driver ) ID () string {
1321
1335
return d .Config .Container
1322
1336
}
1337
+
1338
+ func (d * driver ) ensureUAMICred (ctx context.Context , env autorestazure.Environment ) (azcore.TokenCredential , bool , error ) {
1339
+ if stored , ok := globalAzureCredentials .Load (azureCredentialsKey ); ok {
1340
+ if cred , ok := stored .(azcore.TokenCredential ); ok {
1341
+ klog .V (2 ).Infof ("Loaded UAMICred from driver cache" )
1342
+ return cred , true , nil
1343
+ }
1344
+ return nil , false , fmt .Errorf ("expected cached credential to be azcore.TokenCredential" )
1345
+ }
1346
+ if os .Getenv ("MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH" ) == "" {
1347
+ return nil , false , nil
1348
+ }
1349
+ cloudConfig := cloud.Configuration {
1350
+ ActiveDirectoryAuthorityHost : env .ActiveDirectoryEndpoint ,
1351
+ Services : map [cloud.ServiceName ]cloud.ServiceConfiguration {
1352
+ cloud .ResourceManager : {
1353
+ Audience : env .TokenAudience ,
1354
+ Endpoint : env .ResourceManagerEndpoint ,
1355
+ },
1356
+ },
1357
+ }
1358
+ cred , err := dataplane .NewUserAssignedIdentityCredential (
1359
+ ctx ,
1360
+ os .Getenv ("MANAGED_AZURE_HCP_CREDENTIALS_FILE_PATH" ),
1361
+ dataplane .WithClientOpts (azcore.ClientOptions {Cloud : cloudConfig }),
1362
+ )
1363
+ if err != nil {
1364
+ return nil , false , err
1365
+ }
1366
+ if actual , loaded := globalAzureCredentials .LoadOrStore (azureCredentialsKey , cred ); loaded {
1367
+ return actual .(azcore.TokenCredential ), true , nil
1368
+ }
1369
+ klog .V (2 ).Infof ("Storing UAMICred for driver" )
1370
+ return cred , true , nil
1371
+ }
0 commit comments