Azure File Storage: Implementing restricted access with PowerShell and .NET
Introduction
Azure Storage supports a wide variety of options accommodating a variety of file formats and access methods. With the introduction of the Azure File storage (which reached the general availability on September 30, 2015), it is possible to provide access to shared storage via SMB 3.0 from any location (as long as traffic on TCP port 445 is not filtered). This opens a range of new possibilities for hosting shared content in Azure. However, unlike traditional file shares in your on-premises environment, Azure File storage does not currently support file system level protection and does not integrate with Active Directory (or Azure Active Directory). This means that, in order to protect the content of Azure Storage files shares, you have to leverage access control mechanisms inherent to the Azure Storage.
With Azure File storage, there are two main options that you can take advantage of to restrict access to shared content:
- Storage account keys - each storage account is associated with a pair of access keys. The knowledge of either of the two keys in combination with the name of the storage account is sufficient to fully manage its content. While convenient from the management standpoint, this option is clearly not suitable for delegating access to individual services, containers, or objects within the storage account.
- Shared Access Signatures (SAS) tokens - these are strings of characters digitally signed with one of two storage account keys, which you can generate on the as-needed basis. When generating a SAS, you have the option of specifying criteria that impose restriction on access to the storage account content, including:
- Allowed services - Blob, File, Queue, Table
- Allowed resource types - Service, Container, Object
- Allowed permissions - Read, Write, Delete, List, Add, Create, Update, Process
- Start and expiry date/time
- Allowed IP addresses from which the access request originates
- Allowed protocols - HTTPS only or HTTPS and HTTP
Details
There are two approaches to generating Shared Access Signatures. The first one involves specifying the criteria listed above directly in the SAS token string. This, however, makes the process of revoking (invalidating) SAS (in case it becomes compromised) disruptive, since it requires regenerating the storage account key with which the SAS was signed. To minimize the impact of revocation of individual SAS tokens, you can define criteria restricting access to the content of the storage account by using another mechanism known as Stored Access Policy. With one or more policies in place, you can then reference them when defining SAS. This, in turn, allows you to invalidate SAS (if needed) by modifying only the underlying policy (for example, by changing the expiry date/time within it).
Note that, for the sake of brevity and clarity, this is a somewhat simplified overview of SAS characteristics. For a more in-depth overview of this topic, refer to Using Shared Access Signatures (SAS)
One of the benefits of Azure File storage is its accessibility via SMB 3.0 (and SMB 2.1 for legacy operating systems). This allows you, for example, to map a drive to an Azure File storage share in the manner similar to the one you would employ when mapping a drive from your on-premises computer to a file share hosted on a departmental file server. However, at this point, SMB-based access supports only the storage account keys option, which does not allow you to provide more granular access by using SAS tokens. If this is your objective, then you can provide access to the content of an Azure File storage shares via programmatic or scripting means.
Example
Let's assume that you want to grant read permissions to a single file hosted on an Azure file share for the next couple of hours (with the location from which the access request will originate and the Azure region hosting the storage accounts residing in the same time zone). The following sample script generates a SAS token that provides such access (note that we are relying in this case on the .NET CloudFile class, described in details in CloudFile Class section of Azure Reference library):
#the name of the storage account hosting the share
$storageAccountName = 'storageaccount115992'
#the name of the resource group containing the storage account
$resourceGroupName = 'azureFilesRG'
#the name of the target share
$shareName = 'share1'
#the name of the directory within the share
$directoryName = 'directory1'
#the name of the file within the directory
$fileName = 'file1.txt'
#the path to the target file (relative to the share)
$fullPath = "$directoryName" + '\' + "$fileName"
#the target storage account
$storageAccount = Get-AzureRmStorageAccount -ResourceGroupName $resourceGroupName `
-Name $storageAccountName
#the first of the storage account access keys (to be used to sign the SAS token)
$storageAccountKey = (Get-AzureRmStorageAccountKey -ResourceGroupName $resourceGroupName `
-Name $storageAccountName).Value[0]
#the security context in which you will generate the SAS token
$context = New-AzureStorageContext -StorageAccountName $storageAccountName `
-StorageAccountKey $storageAccountKey
#the start time of SAS token validity period
$startTime = Get-Date
#the end time of SAS token validity period
$expiryTime = $startTime.AddHours(2.0)
#the SAS token that grants read access to the target file
# during the time period determined by $startTime and $expiryTime
$fileReadSasToken = New-AzureStorageFileSASToken -ShareName $shareName `
-Path $fullPath `
-Permission 'r' `
-StartTime $startTime `
-ExpiryTime $expiryTime `
-Context $context
#the reference to the target file
$cloudFile = New-Object `
Microsoft.WindowsAzure.Storage.File.CloudFile($file.Uri.OriginalString + `
$fileReadSasToken)
#this method will succeed, displaying the content of the file1.txt
$cloudFile.DownloadText()
#this method will fail with the error message
# "The remote server returned an error: (403) Forbidden."
$cloudFile.Delete()