I have an Azure Function that has been assigned a System Identity:
I would like the Azure Function to access a Storage account. The Function has the Reader & Data Access
role on that storage account:
The Function has been configured with the name of the Storage account to use. The Function then tries to get an instance of CloudTableClient:
public async Task InitAsync(string accountsStorageName)
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
string accessToken = await azureServiceTokenProvider.GetAccessTokenAsync(accountsStorageName);
var storageCredential = new StorageCredentials(accessToken);
var storageAccount = new CloudStorageAccount(storageCredential, accountsStorageName, "core.windows.net", true);
// Gets the client to the account's Table storage.
m_tableClient = storageAccount.CreateCloudTableClient();
}
Question
The above code fails because it is unable to get an access token:
How can an Azure Function get a reference to Azure Table storage using Managed Identity?
Azure key vault can generate shared access signature tokens. A shared access signature provides delegated access to resources in your storage account. You can grant clients access to resources in your storage account without sharing your account keys. For more details, please refer to here
$storageAccountName = ""
$keyVaultName = ""
$storageContext = New-AzStorageContext -StorageAccountName $storageAccountName -Protocol Https -StorageAccountKey Key1
$start = [System.DateTime]::Now.AddDays(-1)
$end = [System.DateTime]::Now.AddMonths(1)
$sasToken = New-AzStorageAccountSasToken -Service blob,file,Table,Queue -ResourceType Service,Container,Object -Permission "racwdlup" -Protocol HttpsOnly -StartTime $start -ExpiryTime $end -Context $storageContext
Set-AzKeyVaultManagedStorageSasDefinition -AccountName $storageAccountName -VaultName $keyVaultName -Name "<YourSASDefinitionName>" -TemplateUri $sasToken -SasType 'account' -ValidityPeriod ([System.Timespan]::FromDays(30))
Set-AzKeyVaultAccessPolicy -VaultName $keyVaultName -ObjectId "Azure Function MSI object id" -PermissionsToSecrets get,list
public static class Http
{
[FunctionName("Http")]
public static async Task<IActionResult> Run(
[HttpTrigger(AuthorizationLevel.Anonymous, "get", "post", Route = null)] HttpRequest req,
ILogger log, ExecutionContext context)
{
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
SecretBundle sasToken =await kv.GetSecretAsync(secretIdentifier: "https://testkey02.vault.azure.net:443/secrets/teststorage08-sasToken");
var storageCredential = new StorageCredentials(sasToken.Value);
var accountsStorageName = "teststorage08";
var storageAccount = new CloudStorageAccount(storageCredential, accountsStorageName, "core.windows.net", true);
var tableClient = storageAccount.CreateCloudTableClient();
var table =tableClient.GetTableReference("Customer");
await table.CreateIfNotExistsAsync();
CustomerEntity customer = new CustomerEntity("Harp", "Walter")
{
Email = "[email protected]",
PhoneNumber = "425-555-0101"
};
TableOperation insertOrMergeOperation = TableOperation.InsertOrMerge(customer);
TableResult result = await table.ExecuteAsync(insertOrMergeOperation);
CustomerEntity insertedCustomer = result.Result as CustomerEntity;
return new OkObjectResult(insertedCustomer);
}
}
public class CustomerEntity : TableEntity
{
public CustomerEntity()
{
}
public CustomerEntity(string lastName, string firstName)
{
PartitionKey = lastName;
RowKey = firstName;
}
public string Email { get; set; }
public string PhoneNumber { get; set; }
}