Skip to content
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

Harden passing authentication type through hydra #20

Merged
merged 10 commits into from
Jul 7, 2023
22 changes: 11 additions & 11 deletions pkg/blob/azure.go
Original file line number Diff line number Diff line change
Expand Up @@ -89,21 +89,21 @@ func getCloudProvider(kubeconfig, nodeID, secretName, secretNamespace, userAgent
config, err = az.GetConfigFromSecret()
if err == nil && config != nil {
fromSecret = true

if tenantID := os.Getenv("AZURE_TENANT_ID"); tenantID != "" {
config.TenantID = tenantID
}
if clientID := os.Getenv("AZURE_CLIENT_ID"); clientID != "" {
config.AADClientID = clientID
}
if federatedTokenFile := os.Getenv("AZURE_FEDERATED_TOKEN_FILE"); federatedTokenFile != "" {
config.AADFederatedTokenFile = federatedTokenFile
config.UseFederatedWorkloadIdentityExtension = true
}
}
if err != nil {
klog.V(2).Infof("InitializeCloudFromSecret: failed to get cloud config from secret %s/%s: %v", az.SecretNamespace, az.SecretName, err)
}

if tenantID := os.Getenv("AZURE_TENANT_ID"); tenantID != "" {
config.TenantID = tenantID
}
if clientID := os.Getenv("AZURE_CLIENT_ID"); clientID != "" {
config.AADClientID = clientID
}
if federatedTokenFile := os.Getenv("AZURE_FEDERATED_TOKEN_FILE"); federatedTokenFile != "" {
config.AADFederatedTokenFile = federatedTokenFile
config.UseFederatedWorkloadIdentityExtension = true
}
}

if config == nil {
Expand Down
117 changes: 58 additions & 59 deletions pkg/blob/blob.go
Original file line number Diff line number Diff line change
Expand Up @@ -48,65 +48,64 @@ import (

const (
// DefaultDriverName holds the name of the csi-driver
DefaultDriverName = "blob.csi.azure.com"
blobCSIDriverName = "blob_csi_driver"
separator = "#"
volumeIDTemplate = "%s#%s#%s#%s#%s#%s"
secretNameTemplate = "azure-storage-account-%s-secret"
serverNameField = "server"
storageEndpointSuffixField = "storageendpointsuffix"
tagsField = "tags"
matchTagsField = "matchtags"
protocolField = "protocol"
accountNameField = "accountname"
accountKeyField = "accountkey"
storageAccountField = "storageaccount"
storageAccountTypeField = "storageaccounttype"
skuNameField = "skuname"
subscriptionIDField = "subscriptionid"
resourceGroupField = "resourcegroup"
locationField = "location"
secretNameField = "secretname"
secretNamespaceField = "secretnamespace"
containerNameField = "containername"
containerNamePrefixField = "containernameprefix"
storeAccountKeyField = "storeaccountkey"
isHnsEnabledField = "ishnsenabled"
softDeleteBlobsField = "softdeleteblobs"
softDeleteContainersField = "softdeletecontainers"
enableBlobVersioningField = "enableblobversioning"
getAccountKeyFromSecretField = "getaccountkeyfromsecret"
storageSPNClientIDField = "azurestoragespnclientid"
storageSPNTenantIDField = "azurestoragespntenantid"
keyVaultURLField = "keyvaulturl"
keyVaultSecretNameField = "keyvaultsecretname"
keyVaultSecretVersionField = "keyvaultsecretversion"
storageAccountNameField = "storageaccountname"
allowBlobPublicAccessField = "allowblobpublicaccess"
requireInfraEncryptionField = "requireinfraencryption"
ephemeralField = "csi.storage.k8s.io/ephemeral"
podNamespaceField = "csi.storage.k8s.io/pod.namespace"
mountOptionsField = "mountoptions"
falseValue = "false"
trueValue = "true"
defaultSecretAccountName = "azurestorageaccountname"
defaultSecretAccountKey = "azurestorageaccountkey"
accountSasTokenField = "azurestorageaccountsastoken"
msiSecretField = "msisecret"
storageSPNClientSecretField = "azurestoragespnclientsecret"
EcProtocol = "edgecache"
Fuse = "fuse"
Fuse2 = "fuse2"
NFS = "nfs"
vnetResourceGroupField = "vnetresourcegroup"
vnetNameField = "vnetname"
subnetNameField = "subnetname"
accessTierField = "accesstier"
networkEndpointTypeField = "networkendpointtype"
mountPermissionsField = "mountpermissions"
useDataPlaneAPIField = "usedataplaneapi"
provisionerSecretNameField = "volume.kubernetes.io/provisioner-deletion-secret-name"
provisionerSecretNamespaceField = "volume.kubernetes.io/provisioner-deletion-secret-namespace"
DefaultDriverName = "blob.csi.azure.com"
blobCSIDriverName = "blob_csi_driver"
separator = "#"
volumeIDTemplate = "%s#%s#%s#%s#%s#%s"
secretNameTemplate = "azure-storage-account-%s-secret"
serverNameField = "server"
storageEndpointSuffixField = "storageendpointsuffix"
tagsField = "tags"
matchTagsField = "matchtags"
protocolField = "protocol"
accountNameField = "accountname"
accountKeyField = "accountkey"
storageAccountField = "storageaccount"
storageAccountTypeField = "storageaccounttype"
skuNameField = "skuname"
subscriptionIDField = "subscriptionid"
resourceGroupField = "resourcegroup"
locationField = "location"
secretNameField = "secretname"
secretNamespaceField = "secretnamespace"
containerNameField = "containername"
containerNamePrefixField = "containernameprefix"
storeAccountKeyField = "storeaccountkey"
isHnsEnabledField = "ishnsenabled"
softDeleteBlobsField = "softdeleteblobs"
softDeleteContainersField = "softdeletecontainers"
enableBlobVersioningField = "enableblobversioning"
getAccountKeyFromSecretField = "getaccountkeyfromsecret"
storageSPNClientIDField = "azurestoragespnclientid"
storageSPNTenantIDField = "azurestoragespntenantid"
keyVaultURLField = "keyvaulturl"
keyVaultSecretNameField = "keyvaultsecretname"
keyVaultSecretVersionField = "keyvaultsecretversion"
storageAccountNameField = "storageaccountname"
allowBlobPublicAccessField = "allowblobpublicaccess"
requireInfraEncryptionField = "requireinfraencryption"
ephemeralField = "csi.storage.k8s.io/ephemeral"
podNamespaceField = "csi.storage.k8s.io/pod.namespace"
mountOptionsField = "mountoptions"
falseValue = "false"
trueValue = "true"
defaultSecretAccountName = "azurestorageaccountname"
defaultSecretAccountKey = "azurestorageaccountkey"
accountSasTokenField = "azurestorageaccountsastoken"
msiSecretField = "msisecret"
storageSPNClientSecretField = "azurestoragespnclientsecret"
EcProtocol = "edgecache"
Fuse = "fuse"
Fuse2 = "fuse2"
NFS = "nfs"
vnetResourceGroupField = "vnetresourcegroup"
vnetNameField = "vnetname"
subnetNameField = "subnetname"
accessTierField = "accesstier"
networkEndpointTypeField = "networkendpointtype"
mountPermissionsField = "mountpermissions"
useDataPlaneAPIField = "usedataplaneapi"
EcStrgAuthenticationField = "edgecache-storage-auth"

// See https://docs.microsoft.com/en-us/rest/api/storageservices/naming-and-referencing-containers--blobs--and-metadata#container-names
containerNameMinLength = 3
Expand Down
2 changes: 2 additions & 0 deletions pkg/blob/controllerserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,8 @@ func (d *Driver) CreateVolume(ctx context.Context, req *csi.CreateVolumeRequest)
accessTier = v
case networkEndpointTypeField:
networkEndpointType = v
case EcStrgAuthenticationField:
containerNameReplaceMap[EcStrgAuthenticationField] = v
case mountPermissionsField:
// only do validations here, used in NodeStageVolume, NodePublishVolume
if v != "" {
Expand Down
48 changes: 12 additions & 36 deletions pkg/blob/nodeserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (
"time"

"sigs.k8s.io/blob-csi-driver/pkg/edgecache"
cv "sigs.k8s.io/blob-csi-driver/pkg/edgecache/cachevolume"
blobcsiutil "sigs.k8s.io/blob-csi-driver/pkg/util"

"github.com/Azure/azure-sdk-for-go/storage"
Expand All @@ -42,7 +43,6 @@ import (
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

maps "golang.org/x/exp/maps"
"golang.org/x/net/context"
"google.golang.org/grpc"
mount_azure_blob "sigs.k8s.io/blob-csi-driver/pkg/blobfuse-proxy/pb"
Expand Down Expand Up @@ -336,6 +336,14 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
}

if protocol == EcProtocol {
// get authentication method
storageAuthType, storageAuthTypeOk := attrib[EcStrgAuthenticationField]
if !storageAuthTypeOk {
err = fmt.Errorf("could not determine storage authentication for edgecache, missing key is %s", EcStrgAuthenticationField)
klog.Error(err)
return nil, err
}

klog.V(2).Infof("edgecache will be used for volume %s", volumeID)
klog.V(3).Infof("edgecache attrib %v", attrib)
pvName, exists := attrib[pvNameKey]
Expand All @@ -350,41 +358,9 @@ func (d *Driver) NodeStageVolume(ctx context.Context, req *csi.NodeStageVolumeRe
return nil, err
}

// attempt to figure out the name of the kube secret for the storage account key
if len(secretName) == 0 { // if the keyName wasn't already figured out by 'GetAuthEnv'
secretName, exists = pv.ObjectMeta.Annotations[provisionerSecretNameField]
secretNamespace = pv.ObjectMeta.Annotations[provisionerSecretNamespaceField]
if !exists { // if keyName doesn't exist in the PV annotations
klog.Errorf("Failed to discover storage account key name.")
return nil, fmt.Errorf("failed to discover storage account key name")
}
}

var storageAuthType string
if d.cloud.Config.AzureAuthConfig.UseFederatedWorkloadIdentityExtension {
storageAuthType = "WorkloadIdentity"
} else if d.cloud.Config.AzureAuthConfig.UseManagedIdentityExtension {
storageAuthType = "ManagedIdentity"
} else {
return nil, fmt.Errorf("unable to detect authentication type, cannot continue")
}

// Pass this to RetryUpdatePVC to confidently add these annotations
var addAnnotations = func(inpvc *v1.PersistentVolumeClaim) *v1.PersistentVolumeClaim {
pvcClone := inpvc.DeepCopy()
annotations := map[string]string{
"external/edgecache-create-volume": "yes",
"external/edgecache-secret-name": secretName,
"external/edgecache-secret-namespace": secretNamespace,
"external/edgecache-account": accountName,
"external/edgecache-container": containerName,
"external/edgecache-authentication": storageAuthType,
}
maps.Copy(pvcClone.ObjectMeta.Annotations, annotations)
return pvcClone
}
err = blobcsiutil.RetryUpdatePVC(d.cloud.KubeClient, pv.Spec.ClaimRef.Namespace, pv.Spec.ClaimRef.Name, addAnnotations)
if err != nil {
cvHelper := cv.NewCVHelper(d.cloud.KubeClient)
providedAuth := cv.NewBlobAuth(accountName, containerName, secretName, secretNamespace, storageAuthType)
if err := cvHelper.SendProvisionVolume(pv, d.cloud.Config.AzureAuthConfig, providedAuth); err != nil {
return nil, err
}

Expand Down
Loading