Jake
Jake

Reputation: 41

Unable to Access Azure Key Vault from Function - Returns Forbidden

I'm trying to get a secret from a key vault using an Azure function, but the key vault returns forbidden when I try to access it. Clearly I'm missing something, but I haven't been able to find another post with the same problem. Code below:

AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient kvClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));

//(https://keyvaultname.vault.azure.net/)
var keyVaultUrl = Environment.GetEnvironmentVariable("KeyVaultLocation"); 

//(name of the secret)
var vaultSecretKey = Environment.GetEnvironmentVariable("VaultSecretKey"); 

var value = (await kvClient.GetSecretAsync(keyVaultUrl, vaultSecretKey)).Value;

I'm outputting exceptions to the log, and the last line where I await the value of the secret throws this exception:

Operation returned an invalid status code 'Forbidden'.

I have already registered the function in the key vault's access policies and given it permissions to get secrets, and I've enabled Managed Service Identity for the function. Is there something else I'm missing? I'm at a loss as to why the function can't access the vault.

Upvotes: 4

Views: 7224

Answers (7)

Sid DeLuca
Sid DeLuca

Reputation: 29

I neglected to grant "List" secrets permission (in addition to "Get" secret). The following issue helped clue me in: https://github.com/aspnet/Extensions/issues/856

Upvotes: 1

Nunzio Ewald
Nunzio Ewald

Reputation: 63

I had a similar issue, although I was implementing an App Service instead of Azure Functions.

The cause of my problem was that when I was adding permissions to my Key Vault to allow my App Service to access it (via the Access Policies blade on the Key Vault page), I was mistakenly adding permissions for my App Service instead of my App Service Active Directory app.

When I navigated to "Add New access policy->Select principal" and searched for the name of my App Service, the search results included both items, and choosing the wrong one resulted in "Forbidden" when my App Service code attempted to access the Key Vault. Once I went back and selected the Active Directory item (which includes the word "APPLICATION" once it's added to the list of access policies), the Key Vault worked.

Upvotes: 0

regrebud
regrebud

Reputation: 11

I had a similar issue. I was working in 2 different web browser tabs: one for editing the Azure function app settings, the other to assign the role on the resource. Not sure if it is related, but when I closed the second tab and reconfigured everything from a single tab, things started working properly.

Upvotes: 0

Mike K
Mike K

Reputation: 11

you must have your automation account and the credential account added to your access policy for it to run in a runbook with Powershell. That was news to me. Didn't realize it was 2 accounts vs 1. I kept getting forbidden, just didn't know which accounts needed access.

Upvotes: 1

Stephen
Stephen

Reputation: 1

Also double check your AppId and AppSecret passed to the ClientCredential function. We have multiple key vaults, and the wrong vault credentials were stored in the Azure function application settings.

Upvotes: 0

Kayes
Kayes

Reputation: 1096

Ok, this is how I got it working, thanks to Dom:

I tried enabling and disabling MSI for the function app several times. Then went to the KeyVault access policy and assigned the required permissions to the corresponding service principal for the function app.

I've also found that assigning the identity with the PowerShell script worked straightaway, so it's probably better than enabling and disabling MSI several times in the portal:

Set-AzureRmWebApp -AssignIdentity $true -Name $webappname -ResourceGroupName myResourceGroup

Upvotes: 1

Kzryzstof
Kzryzstof

Reputation: 8392

Here is how I use the KeyVaultClient in my Azure Function (v2). I have a method that returns an access token based on the app ID and secret configured for the Vault:

/// <summary>
/// Called by the KeyVaultClient instance.
/// </summary>
/// <param name="authority"></param>
/// <param name="resource"></param>
/// <param name="scope"></param>
/// <returns></returns>
private static async Task<string> GetAccessTokenAsync(string authority, string resource, string scope)
{
    var clientCredential = new ClientCredential(Constants.Vault.AppId, Constants.Vault.AppSecret);

    var context = new AuthenticationContext(authority, TokenCache.DefaultShared);

    AuthenticationResult result = await context.AcquireTokenAsync(resource, clientCredential);

    return result.AccessToken;
}

Then, when I actually need to access the vault, I call the following constructor:

...
//  Pushes the encryption to the Key-Vault.
var client = new KeyVaultClient(GetAccessTokenAsync, new HttpClient());

await client.GetSecretAsync(Constants.Vault.Url, vaultSecretKey);

Upvotes: 3

Related Questions