How to create Azure Storage SAS token using DefaultAzureCredential class

1.8k Views Asked by At

I want to create SAS token to download a blob stored in container in azure storage. I can easily generate SAS token using shared credential but this requires storage access key. How can I generate sas token using managed Identity.

        credential, err := azblob.NewSharedKeyCredential(accountName, accountKey)
        sasQueryParams, err := azblob.BlobSASSignatureValues{
            Protocol:      azblob.SASProtocolHTTPS,
            ExpiryTime:    time.Now().UTC().Add(4 * time.Hour),
            ContainerName: containerName,
            BlobName:      blobName,
            Permissions:   azblob.BlobSASPermissions{Add: false, 
    Read: true, Write: false}.String(),
    }.NewSASQueryParameters(credential)

2

There are 2 best solutions below

1
On

How can I generate sas token using managed Identity?

You can generate it by using DefaultAzureCredential and the proper access to that blob in the storage container.

Connect to the storage account by using the Azure AD credentials of Default Azure Credential class.

Sample Code:

    var strgAccName = _configuration.GetValue<string>("YourStorageAccountName");
    var saUri = $"https://{strgAccName}.blob.core.windows.net";
    var blobServiceClient = new BlobServiceClient(new Uri(saUri), new DefaultAzureCredential());
    var blobContainerClient = blobServiceClient.GetBlobContainerClient(_configuration.GetValue<string>("YourContainerName"));
    var blobClient = blobContainerClient.GetBlobClient("YourImage.jpg"); 
    // We can issue the SAS token till a maximum of 7 days.
    var userDelegationKey =  blobServiceClient.GetUserDelegationKey(DateTimeOffset.UtcNow,
                                                                    DateTimeOffset.UtcNow.AddHours(4)); 
                                                            
    var sasBuilder = new BlobSasBuilder()
    {
        BlobContainerName = blobClient.BlobContainerName,
        BlobName = blobClient.Name,
        Resource = "b", // b: blob, c: container
        StartsOn = DateTimeOffset.UtcNow,
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(4),
    };

    sasBuilder.SetPermissions(BlobSasPermissions.Read); 
    var blobUriBuilder = new BlobUriBuilder(blobClient.Uri)
    {
        Sas = sasBuilder.ToSasQueryParameters(userDelegationKey,blobServiceClient.AccountName)
    };
    // Read this in any view like `blobUriBuilder.ToUri().ToString();`
}

And re-check the delegated access is there or not for that blob. So, we don't use any access key and connection string for this.

Thanks to @Anupam Maiti for this Article, please refer this for step-by-step procedure.

0
On

Probably late but this is a working code, you can authenticate using one of the method listed here:

And later, using the DefaultCredentials, the code automatically inherit the authentication and generate the SAS token.

In the code below, the final part is used to actually test that the SAS token is valid and working properly.

package main

import (
    "context"
    "fmt"
    "log"
    "provisioner/common/azure/authentication"
    "time"

    "github.com/Azure/azure-sdk-for-go/sdk/azcore/to"
    "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob"
    "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/sas"
    "github.com/Azure/azure-sdk-for-go/sdk/storage/azblob/service"
)

func main() {

    containerName := "CONTAINER_NAME"
    storageUrl := "https://XXXXXXXX.blob.core.windows.net/"

    // Get the default credential
    cred, err := authentication.BuildDefaultAzureCredentials()
    if err != nil {
        log.Fatal(err.Error())
    }

    // Get the azure blob client
    client, err := azblob.NewClient(storageUrl, cred, nil)
    if err != nil {
        log.Fatal(err.Error())
    }

    serviceClient := client.ServiceClient()

    // Prepare SAS Token Input field
    now := time.Now().UTC().Add(-10 * time.Second)
    expiry := now.Add(48 * time.Hour)
    info := service.KeyInfo{
        Start:  to.Ptr(now.UTC().Format(sas.TimeFormat)),
        Expiry: to.Ptr(expiry.UTC().Format(sas.TimeFormat)),
    }

    // Get Delegation Key
    udc, err := serviceClient.GetUserDelegationCredential(context.TODO(), info, nil)
    if err != nil {
        log.Fatal(err.Error())
    }

    sasQueryParams, err := sas.BlobSignatureValues{
        Protocol:      sas.ProtocolHTTPS,
        StartTime:     time.Now().UTC().Add(time.Second * -10),
        ExpiryTime:    time.Now().UTC().Add(15 * time.Minute),
        Permissions:   to.Ptr(sas.ContainerPermissions{Read: true, List: true}).String(),
        ContainerName: containerName,
    }.SignWithUserDelegation(udc)
    if err != nil {
        log.Fatal(err.Error())
    }

    sasURL := storageUrl + "?" + sasQueryParams.Encode()

    // This URL can be used to authenticate requests now
    azClient, err := azblob.NewClientWithNoCredential(sasURL, nil)
    if err != nil {
        log.Fatal(err.Error())
    }

    // list blobs in container
    pager := azClient.NewListBlobsFlatPager(containerName, nil)
    for pager.More() {
        resp, err := pager.NextPage(context.Background())
        if err != nil {
            log.Fatal(err.Error())
        }
        for _, b := range resp.Segment.BlobItems {
            fmt.Println(*b.Name)
        }
    }

}