Skip to content

Commit

Permalink
Merge pull request #943 from k8s-infra-cherrypick-robot/cherry-pick-9…
Browse files Browse the repository at this point in the history
…42-to-release-1.21

[release-1.21] feat: support setting AzureStorageSPNClientID/TenantId in secret
  • Loading branch information
k8s-ci-robot committed Jun 1, 2023
2 parents afe2e24 + e8a5600 commit 11b29d1
Show file tree
Hide file tree
Showing 3 changed files with 51 additions and 17 deletions.
2 changes: 1 addition & 1 deletion docs/driver-parameters.md
Original file line number Diff line number Diff line change
Expand Up @@ -103,7 +103,7 @@ volumeAttributes.keyVaultSecretVersion | Azure Key Vault secret version | existi
kubectl create secret generic azure-secret --from-literal=azurestorageaccountname="xxx" --from-literal azurestorageaccountkey="xxx" --type=Opaque
kubectl create secret generic azure-secret --from-literal=azurestorageaccountname="xxx" --from-literal azurestorageaccountsastoken="xxx" --type=Opaque
kubectl create secret generic azure-secret --from-literal msisecret="xxx" --type=Opaque
kubectl create secret generic azure-secret --from-literal azurestoragespnclientsecret="xxx" --type=Opaque
kubectl create secret generic azure-secret --from-literal azurestoragespnclientsecret="xxx" azurestoragespnclientid="xxx" azurestoragespntenantid="xxx" --type=Opaque
```

### Tips
Expand Down
50 changes: 38 additions & 12 deletions pkg/blob/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,8 @@ const (
softDeleteContainersField = "softdeletecontainers"
enableBlobVersioningField = "enableblobversioning"
getAccountKeyFromSecretField = "getaccountkeyfromsecret"
storageSPNClientIDField = "azurestoragespnclientid"
storageSPNTenantIDField = "azurestoragespntenantid"
keyVaultURLField = "keyvaulturl"
keyVaultSecretNameField = "keyvaultsecretname"
keyVaultSecretVersionField = "keyvaultsecretversion"
Expand Down Expand Up @@ -369,6 +371,8 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
accountSasToken string
msiSecret string
storageSPNClientSecret string
storageSPNClientID string
storageSPNTenantID string
secretName string
pvcNamespace string
keyVaultURL string
Expand Down Expand Up @@ -416,10 +420,10 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
authEnv = append(authEnv, "AZURE_STORAGE_IDENTITY_RESOURCE_ID="+v)
case "msiendpoint":
authEnv = append(authEnv, "MSI_ENDPOINT="+v)
case "azurestoragespnclientid":
authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_ID="+v)
case "azurestoragespntenantid":
authEnv = append(authEnv, "AZURE_STORAGE_SPN_TENANT_ID="+v)
case storageSPNClientIDField:
storageSPNClientID = v
case storageSPNTenantIDField:
storageSPNTenantID = v
case "azurestorageaadendpoint":
authEnv = append(authEnv, "AZURE_STORAGE_AAD_ENDPOINT="+v)
}
Expand Down Expand Up @@ -463,11 +467,17 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
}
if secretName != "" {
// read from k8s secret first
var name string
name, accountKey, accountSasToken, msiSecret, storageSPNClientSecret, err = d.GetInfoFromSecret(ctx, secretName, secretNamespace)
var name, spnClientID, spnTenantID string
name, accountKey, accountSasToken, msiSecret, storageSPNClientSecret, spnClientID, spnTenantID, err = d.GetInfoFromSecret(ctx, secretName, secretNamespace)
if name != "" {
accountName = name
}
if spnClientID != "" {
storageSPNClientID = spnClientID
}
if spnTenantID != "" {
storageSPNTenantID = spnTenantID
}
if err != nil && strings.EqualFold(azureStorageAuthType, "msi") {
klog.V(2).Infof("ignore error(%v) since secret is optional for auth type(%s)", err, azureStorageAuthType)
err = nil
Expand Down Expand Up @@ -499,6 +509,10 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
msiSecret = v
case storageSPNClientSecretField:
storageSPNClientSecret = v
case storageSPNClientIDField:
storageSPNClientID = v
case storageSPNTenantIDField:
storageSPNTenantID = v
}
}
}
Expand Down Expand Up @@ -527,6 +541,16 @@ func (d *Driver) GetAuthEnv(ctx context.Context, volumeID, protocol string, attr
authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_SECRET="+storageSPNClientSecret)
}

if storageSPNClientID != "" {
klog.V(2).Infof("storageSPNClientID(%s) is not empty, use it to access storage account(%s), container(%s)", storageSPNClientID, accountName, containerName)
authEnv = append(authEnv, "AZURE_STORAGE_SPN_CLIENT_ID="+storageSPNClientID)
}

if storageSPNTenantID != "" {
klog.V(2).Infof("storageSPNTenantID(%s) is not empty, use it to access storage account(%s), container(%s)", storageSPNTenantID, accountName, containerName)
authEnv = append(authEnv, "AZURE_STORAGE_SPN_TENANT_ID="+storageSPNTenantID)
}

return rgName, accountName, accountKey, containerName, authEnv, err
}

Expand Down Expand Up @@ -757,7 +781,7 @@ func (d *Driver) GetStorageAccesskey(ctx context.Context, accountOptions *azure.
if secretName == "" {
secretName = fmt.Sprintf(secretNameTemplate, accountOptions.Name)
}
_, accountKey, _, _, _, err := d.GetInfoFromSecret(ctx, secretName, secretNamespace) //nolint
_, accountKey, _, _, _, _, _, err := d.GetInfoFromSecret(ctx, secretName, secretNamespace) //nolint
if err != nil {
klog.V(2).Infof("could not get account(%s) key from secret(%s) namespace(%s), error: %v, use cluster identity to get account key instead", accountOptions.Name, secretName, secretNamespace, err)
accountKey, err = d.cloud.GetStorageAccesskey(ctx, accountOptions.SubscriptionID, accountOptions.Name, accountOptions.ResourceGroup)
Expand All @@ -766,25 +790,27 @@ func (d *Driver) GetStorageAccesskey(ctx context.Context, accountOptions *azure.
}

// GetInfoFromSecret get info from k8s secret
// return <accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, error>
func (d *Driver) GetInfoFromSecret(ctx context.Context, secretName, secretNamespace string) (string, string, string, string, string, error) {
// return <accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, error>
func (d *Driver) GetInfoFromSecret(ctx context.Context, secretName, secretNamespace string) (string, string, string, string, string, string, string, error) {
if d.cloud.KubeClient == nil {
return "", "", "", "", "", fmt.Errorf("could not get account key from secret(%s): KubeClient is nil", secretName)
return "", "", "", "", "", "", "", fmt.Errorf("could not get account key from secret(%s): KubeClient is nil", secretName)
}

secret, err := d.cloud.KubeClient.CoreV1().Secrets(secretNamespace).Get(ctx, secretName, metav1.GetOptions{})
if err != nil {
return "", "", "", "", "", fmt.Errorf("could not get secret(%v): %w", secretName, err)
return "", "", "", "", "", "", "", fmt.Errorf("could not get secret(%v): %w", secretName, err)
}

accountName := strings.TrimSpace(string(secret.Data[defaultSecretAccountName][:]))
accountKey := strings.TrimSpace(string(secret.Data[defaultSecretAccountKey][:]))
accountSasToken := strings.TrimSpace(string(secret.Data[accountSasTokenField][:]))
msiSecret := strings.TrimSpace(string(secret.Data[msiSecretField][:]))
spnClientSecret := strings.TrimSpace(string(secret.Data[storageSPNClientSecretField][:]))
spnClientID := strings.TrimSpace(string(secret.Data[storageSPNClientIDField][:]))
spnTenantID := strings.TrimSpace(string(secret.Data[storageSPNTenantIDField][:]))

klog.V(4).Infof("got storage account(%s) from secret", accountName)
return accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, nil
return accountName, accountKey, accountSasToken, msiSecret, spnClientSecret, spnClientID, spnTenantID, nil
}

// getSubnetResourceID get default subnet resource ID from cloud provider config
Expand Down
16 changes: 12 additions & 4 deletions pkg/blob/blob_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1047,7 +1047,7 @@ func TestGetInfoFromSecret(t *testing.T) {
d.cloud.KubeClient = nil
secretName := "foo"
secretNamespace := "bar"
_, _, _, _, _, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
_, _, _, _, _, _, _, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
expectedErr := fmt.Errorf("could not get account key from secret(%s): KubeClient is nil", secretName)
if assert.Error(t, err) {
assert.Equal(t, expectedErr, err)
Expand All @@ -1062,7 +1062,7 @@ func TestGetInfoFromSecret(t *testing.T) {
d.cloud.KubeClient = fakeClient
secretName := ""
secretNamespace := ""
_, _, _, _, _, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
_, _, _, _, _, _, _, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
// expectedErr := fmt.Errorf("could not get secret(%v): %w", secretName, err)
assert.Error(t, err) // could not check what type of error, needs fix
/*if assert.Error(t, err) {
Expand Down Expand Up @@ -1095,12 +1095,14 @@ func TestGetInfoFromSecret(t *testing.T) {
if secretCreateErr != nil {
t.Error("failed to create secret")
}
an, ak, accountSasToken, msiSecret, storageSPNClientSecret, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
an, ak, accountSasToken, msiSecret, storageSPNClientSecret, storageSPNClientID, storageSPNTenantID, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
assert.Equal(t, accountName, an, "accountName should match")
assert.Equal(t, accountKey, ak, "accountKey should match")
assert.Equal(t, "", accountSasToken, "accountSasToken should be empty")
assert.Equal(t, "", msiSecret, "msiSecret should be empty")
assert.Equal(t, "", storageSPNClientSecret, "storageSPNClientSecret should be empty")
assert.Equal(t, "", storageSPNClientID, "storageSPNClientID should be empty")
assert.Equal(t, "", storageSPNTenantID, "storageSPNTenantID should be empty")
assert.Equal(t, nil, err, "error should be nil")
},
},
Expand All @@ -1116,6 +1118,8 @@ func TestGetInfoFromSecret(t *testing.T) {
accountSasTokenValue := "foo"
msiSecretValue := "msiSecret"
storageSPNClientSecretValue := "storageSPNClientSecret"
storageSPNClientIDValue := "storageSPNClientID"
storageSPNTenantIDValue := "storageSPNTenantID"
secret := &v1api.Secret{
ObjectMeta: metav1.ObjectMeta{
Namespace: secretNamespace,
Expand All @@ -1126,19 +1130,23 @@ func TestGetInfoFromSecret(t *testing.T) {
accountSasTokenField: []byte(accountSasTokenValue),
msiSecretField: []byte(msiSecretValue),
storageSPNClientSecretField: []byte(storageSPNClientSecretValue),
storageSPNClientIDField: []byte(storageSPNClientIDValue),
storageSPNTenantIDField: []byte(storageSPNTenantIDValue),
},
Type: "Opaque",
}
_, secretCreateErr := d.cloud.KubeClient.CoreV1().Secrets(secretNamespace).Create(context.TODO(), secret, metav1.CreateOptions{})
if secretCreateErr != nil {
t.Error("failed to create secret")
}
an, ak, accountSasToken, msiSecret, storageSPNClientSecret, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
an, ak, accountSasToken, msiSecret, storageSPNClientSecret, storageSPNClientID, storageSPNTenantID, err := d.GetInfoFromSecret(context.TODO(), secretName, secretNamespace)
assert.Equal(t, accountName, an, "accountName should match")
assert.Equal(t, "", ak, "accountKey should be empty")
assert.Equal(t, accountSasTokenValue, accountSasToken, "sasToken should match")
assert.Equal(t, msiSecretValue, msiSecret, "msiSecret should match")
assert.Equal(t, storageSPNClientSecretValue, storageSPNClientSecret, "storageSPNClientSecret should match")
assert.Equal(t, storageSPNClientIDValue, storageSPNClientID, "storageSPNClientID should match")
assert.Equal(t, storageSPNTenantIDValue, storageSPNTenantID, "storageSPNTenantID should match")
assert.Equal(t, nil, err, "error should be nil")
},
},
Expand Down

0 comments on commit 11b29d1

Please sign in to comment.