Skip to content

Latest commit

 

History

History
209 lines (164 loc) · 13.1 KB

Shared Access Signatures.md

File metadata and controls

209 lines (164 loc) · 13.1 KB

A Shared Access Signature (SAS) is a URI that grants restricted access rights to Azure Storage resources. It's a signed URI that points to one or more storage resources and includes a token that contains a special set of query parameters.

Use a SAS for secure, temporary access to your storage account, especially when users need to read/write their own data or for copying data within Azure Storage.

Note: You should prefer Entra ID

Types of SAS

  1. User Delegation SAS: This method uses Microsoft Entra ID credentials to create a SAS. It's a secure way to grant limited access to your Azure Storage resources without sharing your account key. It's recommended when you want to provide fine-grained access control to clients who are authenticated with Entra ID. The account must have generateUserDelegationKey permisison, or Contributor role.

  2. Service SAS: This method uses your storage account key to create a SAS. It's a straightforward way to grant limited access to your Azure Storage resources. However, it's less secure than the User Delegation SAS because it involves sharing your account key. It's typically used when you want to provide access to clients who are not authenticated with Entra ID.

  3. Account SAS: This method uses your storage account key to create a SAS. It's created at the storage account level, allowing access to multiple services within the account. It's typically used when you need to provide access to several services in your storage account. However, it involves sharing your account key, similar to the Service SAS.

    • Ad hoc SAS: Defines start, expiry, and permissions in the SAS URI. Any SAS can be an ad hoc SAS.
    • Service SAS: Uses a stored policy on resources to inherit start, expiry, and permissions.

How SAS Works

A SAS requires two components: a URI to the resource you want to access and a SAS token that you've created to authorize access to that resource.

  • URI: https://<account>.blob.core.windows.net/<container>/<blob>?
  • SAS token: sp=r&st=2020-01-20T11:42:32Z&se=2020-01-20T19:42:32Z&spr=https&sv=2019-02-02&sr=b&sig=SrW1HZ5Nb6MbRzTbXCaPm%2BJiSEn15tC91Y4umMPwVZs%3D

Reference:

Component Friendly Name Description
sp Shared Permissions Controls the access rights. Possible values include: add, create, delete, list, read, write. Ex: sp=acdlrw grants all the available rights.
st Shared Access Signature Start Time The date and time when access starts. Ex: st=2023-07-28T11:42:32Z means the access starts at 11:42:32 UTC on July 28, 2023.
se Shared Access Signature Expiry Time The date and time when access ends. Ex: se=2023-07-28T19:42:32Z means the access ends at 19:42:32 UTC on July 28, 2023.
sv Storage API Version The version of the storage API to use. Ex: sv=2020-02-10 means the storage API version 2020-02-10 is used.
sr Storage Resource The kind of storage being accessed. Possible values include: blob, file, queue, table, container, directory. Ex: sr=b means a blob is being accessed.
sig Signature The cryptographic signature. Ex: sig=SrW1HZ5Nb6MbRzTbXCaPm%2BJiSEn15tC91Y4umMPwVZs%3D is a cryptographic signature.
sip Source IP Range (Optional) Allowed IP addresses or IP range. Ex: sip=168.1.5.60-168.1.5.70 means only the IP addresses from 168.1.5.60 to 168.1.5.70 are allowed.
spr Supported Protocols (Optional) Allowed protocols. Possible values include: 'https', 'http,https'. Ex: spr=https means only HTTPS is allowed.
si Stored Access Policy Identifier (Optional) The name of the stored access policy. Ex: si=MyAccessPolicy means the stored access policy named "MyAccessPolicy" is used.
rscc Response Cache Control (Optional) The response header override for cache control. Ex: rscc=public means the "Cache-Control" header is set to "public".
rscd Response Content Disposition (Optional) The response header override for content disposition. Ex: rscd=attachment; filename=example.txt means the "Content-Disposition" header is set to "attachment; filename=example.txt".
rsce Response Content Encoding (Optional) The response header override for content encoding. Ex: rsce=gzip means the "Content-Encoding" header is set to "gzip".
rscl Response Content Language (Optional) The response header override for content language. Ex: rscl=en-US means the "Content-Language" header is set to "en-US".
rsct Response Content Type (Optional) The response header override for content type. Ex: rsct=text/plain means the "Content-Type" header is set to "text/plain".

Note: All 2-letter parameters are required, except si (Access Policy)

Best Practices

  • Always use HTTPS.
  • Use user delegation SAS wherever possible.
  • Set your expiration time to the smallest useful value.
  • Only grant the access that's required.
  • Create a middle-tier service to manage users and their access to storage when there's an unacceptable risk of using a SAS.

Allow you to group SAS and set additional constraints like start time, expiry time, and permissions. Work on container level.

Use SetAccessPolicy on BlobContainer to apply an array containing a single BlobSignedIdentifier that has a configured BlobAccessPolicy for the AccessPolicy property.

BlobSignedIdentifier identifier = new BlobSignedIdentifier
{
    Id = "stored access policy identifier",
    AccessPolicy = new BlobAccessPolicy
    {
        ExpiresOn = DateTimeOffset.UtcNow.AddHours(1),
        Permissions = "rw"
    }
};

blobContainer.SetAccessPolicy(permissions: new BlobSignedIdentifier[] { identifier });
az storage container policy create \
    --name <stored access policy identifier> \
    --container-name <container name> \
    --start <start time UTC datetime> \
    --expiry <expiry time UTC datetime> \
    --permissions <(a)dd, (c)reate, (d)elete, (l)ist, (r)ead, or (w)rite> \
    --account-key <storage account key> \
    --account-name <storage account name> \

To cancel (revoke) a policy, you can either delete it, rename it, or set its expiration time to a past date.

To remove all access policies from the resource, call the Set ACL operation with an empty request body.

Working with SAS

Gist:

  • Service SAS and Account SAS use StorageSharedKeyCredential; User delegation SAS use DefaultAzureCredential or similar Entra ID
  • Service SAS and User delegation SAS use BlobSasBuilder; Account SAS uses AccountSasBuilder
  • Set permissions: BlobSasPermissions for user and service; AccountSasPermissions for account
  • Obtaining URI:
    • User delegation SAS: Use key generated from BlobServiceClient.GetUserDelegationKeyAsync as first param of BlobSasBuilder.ToSasQueryParameters(key, accountName); pass it to BlobUriBuilder(BlobClient.Uri).Sas
    • Service SAS: BlobClient.GenerateSasUri(BlobSasBuilder)
    • Account SAS: BlobSasBuilder.ToSasQueryParameters(sharedKeyCredential) and construct Uri from it at root level (https://{accountName}.blob.core.windows.net?{sasToken})
// Using StorageSharedKeyCredential with account name and key directly for authentication.
// This key has full permissions to all operations on all resources in your storage account.
// Works for all SAS types, but less secure.
var credential = new StorageSharedKeyCredential("<account-name>", "<account-key>");

// Using DefaultAzureCredential with Entra ID. More secure, but doesn't work for Service SAS.
// TokenCredential credential = new DefaultAzureCredential();

var serviceClient = new BlobServiceClient(new Uri("<account-url>"), credential);
var blobClient = serviceClient.GetBlobContainerClient("<container-name>").GetBlobClient("<blob-name>");

// Create a SAS token for the blob resource that's also valid for 1 day
BlobSasBuilder sasBuilder = new BlobSasBuilder()
{
    BlobContainerName = blobClient.BlobContainerName,
    BlobName = blobClient.Name,
    Resource = "b", // HINT: in case of missing BlobName property, then Resource = "c"
    StartsOn = DateTimeOffset.UtcNow,
    ExpiresOn = DateTimeOffset.UtcNow.AddDays(1)
};
sasBuilder.SetPermissions(BlobSasPermissions.Read | BlobSasPermissions.Write);

////////////////////////////////////////////////////
// User Delegation SAS
////////////////////////////////////////////////////

// Request the user delegation key
// UserDelegationKey is used to sign the SAS token and has its own validity (can be used for multiple SAS)
UserDelegationKey userDelegationKey = await serviceClient.GetUserDelegationKeyAsync(
    DateTimeOffset.UtcNow,
    DateTimeOffset.UtcNow.AddDays(1));
var userSas = sasBuilder.ToSasQueryParameters(userDelegationKey, serviceClient.AccountName);
// Add the SAS token to the blob URI
BlobUriBuilder uriBuilder = new BlobUriBuilder(blobClient.Uri) { Sas = userSas };
var blobClientSASUserDelegation = new BlobClient(uriBuilder.ToUri());

////////////////////////////////////////////////////
// Service SAS
////////////////////////////////////////////////////

Uri blobSASURIService = blobClient.GenerateSasUri(sasBuilder);
var blobClientSASService = new BlobClient(blobSASURIService);

Account SAS:

var sharedKeyCredential = new StorageSharedKeyCredential("<account-name>", "<account-key>");

// Create a SAS token that's valid for one day
var sasBuilder = new AccountSasBuilder()
{
    Services = AccountSasServices.Blobs | AccountSasServices.Queues,
    ResourceTypes = AccountSasResourceTypes.Service,
    ExpiresOn = DateTimeOffset.UtcNow.AddDays(1),
    Protocol = SasProtocol.Https
};
sasBuilder.SetPermissions(AccountSasPermissions.Read | AccountSasPermissions.Write);

// Use the key to get the SAS token
// NOTE: You can pass sharedKeyCredential to ToSasQueryParameters (also valid for Service SAS)
var sasToken = sasBuilder.ToSasQueryParameters(sharedKeyCredential).ToString();

// Create a BlobServiceClient object with the account SAS appended
var blobServiceURI = $"https://{accountName}.blob.core.windows.net";
var blobServiceClientAccountSAS = new BlobServiceClient(
    new Uri($"{blobServiceURI}?{sasToken}"));
    ```

```sh
# Assign the necessary permissions to the user
az role assignment create \
 --role "Storage Blob Data Contributor" \
 --assignee <email> \
 --scope "/subscriptions/<subscription>/resourceGroups/<resource-group>/providers/Microsoft.Storage/storageAccounts/<storage-account>"

# Account Level SAS: --account-name and --account-key
# Service Level SAS: --resource-types + same as above
# User Level SAS: --auth-mode login
# (applicable for Stored Access Policies as well)

# Generate a user delegation SAS for a container
az storage container generate-sas \
 --account-name <storage-account> \
 --name <container> \
 --permissions acdlrw \
 --expiry <date-time> \
 --auth-mode login \
 --as-user

# Generate a user delegation SAS for a blob
az storage blob generate-sas \
 --account-name <storage-account> \
 --container-name <container> \
 --name <blob> \
 --permissions acdrw \
 --expiry <date-time> \
 --auth-mode login \
 --as-user \
 --full-uri

# Revoke all user delegation keys for the storage account
az storage account revoke-delegation-keys \
 --name <storage-account> \
 --resource-group $resourceGroup