From 12018c5f2c5c37d44daa2a874f551e5b7b9933c3 Mon Sep 17 00:00:00 2001 From: Darren Dowker Date: Wed, 29 Nov 2023 10:51:48 -0800 Subject: [PATCH 1/3] add signing support for shared key credentials with blob SAS --- broker/fragment/store_azure.go | 56 +++++++++++++++++++++++++--------- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/broker/fragment/store_azure.go b/broker/fragment/store_azure.go index cc55005f..88ae3fe6 100644 --- a/broker/fragment/store_azure.go +++ b/broker/fragment/store_azure.go @@ -48,6 +48,8 @@ type azureBackend struct { clientMu sync.Mutex udc *service.UserDelegationCredential udcExp *time.Time + + sharedKeyCredentials *service.SharedKeyCredential } func (a *azureBackend) Provider() string { @@ -57,31 +59,54 @@ func (a *azureBackend) Provider() string { // See here for an example of how to use the Azure client libraries to create signatures: // https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azblob/service/examples_test.go#L285 func (a *azureBackend) SignGet(ep *url.URL, fragment pb.Fragment, d time.Duration) (string, error) { + var ( + sasQueryParams QueryParameters + err error + ) + cfg, _, err := a.azureClient(ep) if err != nil { return "", err } blobName := cfg.rewritePath(cfg.prefix, fragment.ContentPath()) - udc, err := a.getUserDelegationCredential() - if err != nil { - return "", err - } + if ep.Scheme == "azure" { + // Note: for arize we assume azure scheme is for blob SAS (as opposed to container SAS in azure-ad case) + sasQueryParams, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(d), + ContainerName: cfg.containerName, + BlobName: blobName, + Permissions: sas.BlobPermissions{Add: true, Read: true, Write: true}.String(), + }.SignWithSharedKey(a.sharedKeyCredentials) + + if err != nil { + return "", err + } + } else if ep.Scheme == "azure-ad" { + udc, err := a.getUserDelegationCredential() + if err != nil { + return "", err + } - sasQueryParams, err := sas.BlobSignatureValues{ - Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) - ExpiryTime: time.Now().UTC().Add(d), // Timestamps are expected in UTC https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#service-sas-example - ContainerName: cfg.containerName, - BlobName: blobName, + sasQueryParams, err = sas.BlobSignatureValues{ + Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) + ExpiryTime: time.Now().UTC().Add(d), // Timestamps are expected in UTC https://docs.microsoft.com/en-us/rest/api/storageservices/create-service-sas#service-sas-example + ContainerName: cfg.containerName, + BlobName: blobName, - // To produce a container SAS (as opposed to a blob SAS), assign to Permissions using - // ContainerSASPermissions and make sure the BlobName field is "" (the default). - Permissions: to.Ptr(sas.ContainerPermissions{Read: true, Add: true, Write: true}).String(), - }.SignWithUserDelegation(udc) + // To produce a container SAS (as opposed to a blob SAS), assign to Permissions using + // ContainerSASPermissions and make sure the BlobName field is "" (the default). + Permissions: to.Ptr(sas.ContainerPermissions{Read: true, Add: true, Write: true}).String(), + }.SignWithUserDelegation(udc) - if err != nil { - return "", err + if err != nil { + return "", err + } + } else { + return "", fmt.Errorf("unknown scheme: %s", ep.Scheme) } + return fmt.Sprintf("%s/%s?%s", cfg.containerURL(), blobName, sasQueryParams.Encode()), nil } @@ -268,6 +293,7 @@ func (a *azureBackend) azureClient(ep *url.URL) (cfg AzureStoreConfig, client pi if err != nil { return cfg, nil, err } + a.sharedKeyCredentials = credentials } else if ep.Scheme == "azure-ad" { // Link to the Azure docs describing what fields are required for active directory auth // https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication-service-principal?tabs=azure-cli#-option-1-authenticate-with-a-secret From 53b3c78754358eceaa061fc446a718490b519933 Mon Sep 17 00:00:00 2001 From: Darren Dowker Date: Wed, 29 Nov 2023 11:37:04 -0800 Subject: [PATCH 2/3] fix build issues --- broker/fragment/store_azure.go | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/broker/fragment/store_azure.go b/broker/fragment/store_azure.go index 88ae3fe6..1a02932f 100644 --- a/broker/fragment/store_azure.go +++ b/broker/fragment/store_azure.go @@ -49,7 +49,7 @@ type azureBackend struct { udc *service.UserDelegationCredential udcExp *time.Time - sharedKeyCredentials *service.SharedKeyCredential + sharedKeyCredentials *sas.SharedKeyCredential } func (a *azureBackend) Provider() string { @@ -60,7 +60,7 @@ func (a *azureBackend) Provider() string { // https://github.com/Azure/azure-sdk-for-go/blob/main/sdk/storage/azblob/service/examples_test.go#L285 func (a *azureBackend) SignGet(ep *url.URL, fragment pb.Fragment, d time.Duration) (string, error) { var ( - sasQueryParams QueryParameters + sasQueryParams sas.QueryParameters err error ) @@ -72,12 +72,14 @@ func (a *azureBackend) SignGet(ep *url.URL, fragment pb.Fragment, d time.Duratio if ep.Scheme == "azure" { // Note: for arize we assume azure scheme is for blob SAS (as opposed to container SAS in azure-ad case) + perms := sas.BlobPermissions{Add: true, Read: true, Write: true} + sasQueryParams, err = sas.BlobSignatureValues{ Protocol: sas.ProtocolHTTPS, // Users MUST use HTTPS (not HTTP) ExpiryTime: time.Now().UTC().Add(d), ContainerName: cfg.containerName, BlobName: blobName, - Permissions: sas.BlobPermissions{Add: true, Read: true, Write: true}.String(), + Permissions: perms.String(), }.SignWithSharedKey(a.sharedKeyCredentials) if err != nil { From 18566aa718a05c989b1647d25697f532225c75ad Mon Sep 17 00:00:00 2001 From: Darren Dowker Date: Wed, 29 Nov 2023 12:08:50 -0800 Subject: [PATCH 3/3] another fix --- broker/fragment/store_azure.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/broker/fragment/store_azure.go b/broker/fragment/store_azure.go index 1a02932f..e97ebd9d 100644 --- a/broker/fragment/store_azure.go +++ b/broker/fragment/store_azure.go @@ -285,6 +285,7 @@ func (a *azureBackend) azureClient(ep *url.URL) (cfg AzureStoreConfig, client pi if err != nil { return cfg, nil, err } + a.sharedKeyCredentials = sharedKeyCred // Arize addition serviceClient, err := service.NewClientWithSharedKeyCredential(cfg.serviceUrl(), sharedKeyCred, &service.ClientOptions{}) if err != nil { return cfg, nil, err @@ -295,7 +296,6 @@ func (a *azureBackend) azureClient(ep *url.URL) (cfg AzureStoreConfig, client pi if err != nil { return cfg, nil, err } - a.sharedKeyCredentials = credentials } else if ep.Scheme == "azure-ad" { // Link to the Azure docs describing what fields are required for active directory auth // https://learn.microsoft.com/en-us/azure/developer/go/azure-sdk-authentication-service-principal?tabs=azure-cli#-option-1-authenticate-with-a-secret