-
Notifications
You must be signed in to change notification settings - Fork 107
[WIP] feat: default to kubelet identity when AzureStorageIdentityClientID is empty for MSI auth #2430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
[WIP] feat: default to kubelet identity when AzureStorageIdentityClientID is empty for MSI auth #2430
Changes from all commits
fa042bf
cc21f55
ab09ab0
85b77c4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -754,20 +754,28 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr | |
| authEnv = append(authEnv, "AZURE_STORAGE_SPN_TENANT_ID="+storageSPNTenantID) | ||
| } | ||
|
|
||
| if azureStorageAuthType == storageAuthTypeMSI { | ||
| // check whether authEnv contains AZURE_STORAGE_IDENTITY_ prefix | ||
| if strings.EqualFold(azureStorageAuthType, storageAuthTypeMSI) { | ||
| // check whether authEnv contains a non-empty AZURE_STORAGE_IDENTITY_ value | ||
| containsIdentityEnv := false | ||
| for _, env := range authEnv { | ||
| if strings.HasPrefix(env, "AZURE_STORAGE_IDENTITY_") { | ||
| klog.V(2).Infof("AZURE_STORAGE_IDENTITY_ is already set in authEnv, skip setting it again") | ||
| containsIdentityEnv = true | ||
| break | ||
| // skip empty values like "AZURE_STORAGE_IDENTITY_CLIENT_ID=" | ||
| parts := strings.SplitN(env, "=", 2) | ||
| if len(parts) == 2 && parts[1] != "" { | ||
| klog.V(2).Infof("AZURE_STORAGE_IDENTITY_ is already set in authEnv, skip setting it again") | ||
| containsIdentityEnv = true | ||
| break | ||
| } | ||
| } | ||
| } | ||
| if !containsIdentityEnv && d.cloud != nil && d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID != "" { | ||
| klog.V(2).Infof("azureStorageAuthType is set to %s, add AZURE_STORAGE_IDENTITY_CLIENT_ID(%s) into authEnv", | ||
| azureStorageAuthType, d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID) | ||
| authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_CLIENT_ID="+d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID) | ||
| if !containsIdentityEnv { | ||
| if d.cloud != nil && d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID != "" { | ||
| klog.V(2).Infof("MSI auth: AzureStorageIdentityClientID not specified, default to kubelet identity (%s)", | ||
| d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID) | ||
|
Comment on lines
+771
to
+774
|
||
| authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_CLIENT_ID="+d.cloud.Config.AzureAuthConfig.UserAssignedIdentityID) | ||
| } else { | ||
| klog.Warningf("MSI auth: no identity client ID provided and kubelet identity not available, MSI/IMDS will be used as fallback") | ||
| } | ||
| } | ||
| } | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -2663,6 +2663,120 @@ func TestGetAuthEnvMSIAuthTypeSkipsIdentityEnvIfAlreadySet(t *testing.T) { | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.True(t, found, "Explicit AZURE_STORAGE_IDENTITY_CLIENT_ID should be preserved") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func TestGetAuthEnvMSIDefaultsToKubeletIdentity(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d := NewFakeDriver() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d.cloud = &storage.AccountRepo{} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d.cloud.Config.AzureAuthConfig = azclient.AzureAuthConfig{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| UserAssignedIdentityID: "kubelet-identity-client-id", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attrib := map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| containerNameField: "containername", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| storageAccountField: "accountname", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| storageAuthTypeField: storageAuthTypeMSI, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
andyzhangx marked this conversation as resolved.
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| secret := map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accountNameField: "accountname", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accountKeyField: "testkey", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| volumeID := "rg#accountname#containername" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _, _, _, _, authEnv, err := d.GetAuthEnv(context.TODO(), volumeID, "", attrib, secret) //nolint:dogsled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NoError(t, err) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| found := false | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| for _, env := range authEnv { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if env == "AZURE_STORAGE_IDENTITY_CLIENT_ID=kubelet-identity-client-id" { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| found = true | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| break | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.True(t, found, "Should default to kubelet identity when AzureStorageIdentityClientID is not specified") | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func TestGetAuthEnvMSIWarningWhenNoIdentityAvailable(t *testing.T) { | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d := NewFakeDriver() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| d.cloud = &storage.AccountRepo{} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| // UserAssignedIdentityID is empty — no kubelet identity available, falls back to IMDS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| attrib := map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| containerNameField: "containername", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| storageAccountField: "accountname", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| storageAuthTypeField: storageAuthTypeMSI, | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| secret := map[string]string{ | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accountNameField: "accountname", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| accountKeyField: "testkey", | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| volumeID := "rg#accountname#containername" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _, _, _, _, _, err := d.GetAuthEnv(context.TODO(), volumeID, "", attrib, secret) //nolint:dogsled | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| assert.NoError(t, err) // should not error, falls back to IMDS | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| } | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| func TestGetAuthEnvMSIDefaultsToKubeletIdentityWhenClientIDWhitespace(t *testing.T) { | |
| d := NewFakeDriver() | |
| d.cloud = &storage.AccountRepo{} | |
| d.cloud.Config.AzureAuthConfig = azclient.AzureAuthConfig{ | |
| UserAssignedIdentityID: "kubelet-identity-client-id", | |
| } | |
| attrib := map[string]string{ | |
| containerNameField: "containername", | |
| storageAccountField: "accountname", | |
| storageAuthTypeField: storageAuthTypeMSI, | |
| storageIdentityClientIDField: " ", | |
| } | |
| secret := map[string]string{ | |
| accountNameField: "accountname", | |
| accountKeyField: "testkey", | |
| } | |
| volumeID := "rg#accountname#containername" | |
| _, _, _, _, authEnv, err := d.GetAuthEnv(context.TODO(), volumeID, "", attrib, secret) //nolint:dogsled | |
| assert.NoError(t, err) | |
| found := false | |
| for _, env := range authEnv { | |
| if env == "AZURE_STORAGE_IDENTITY_CLIENT_ID=kubelet-identity-client-id" { | |
| found = true | |
| break | |
| } | |
| } | |
| assert.True(t, found, "Should default to kubelet identity when AzureStorageIdentityClientID is empty or whitespace") | |
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
azureStorageAuthTypeis compared using== storageAuthTypeMSI, but docs/examples commonly setAzureStorageAuthType: MSI(uppercase). This means the MSI-specific identity defaulting/error path won’t run for those values. Usestrings.EqualFold(azureStorageAuthType, storageAuthTypeMSI)here (consistent with the earlier secret-handling check) and add/adjust a unit test to cover uppercaseMSI.