Access Azure KeyVault from Xamarin Form - azure

I need to get a secret from the keyVault (functionKey) so that I can access my functions.
I use the below code that works
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient =
new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("mysecretIdentifier").ConfigureAwait(false);
var key = secret.Value;
but the above requires in Visual Studio 2019 tool-options- Azure service Authentication I have to choose an account
How does it work once the app is deployed?
How does it know which subscription to use?
Just trying to figure out how it will authenticate the azure keyvault?
Any ideas?
thanks

I think your mobile application should never have to query directly the keyvault. Because if you do so your secrets could be retrieved (your secrets will be present in the memory of your mobile application). Check this post about that.
I don't know what you are trying to do but best is to use Azure Functions Easy Auth. Basically it is you will request a token for your identified user on your xamarin application and use this token to query the Azure Function.

Related

Retrieve Azure KeyVault secret using client secret

I'm experimenting with various Azure features and currently want to retrieve a secret from KeyVault.
Straight to the case:
I'm using this nuget package to interact with my azure resources.
I've developed a simple .NET Core console app and run it locally.
I have a KeyVault resource with one secret defined which is active and not expired.
I've registered an App in AAD so my locally shipped .NET Core console app has an identity within AAD.
Than I've created a "client secret" within this registered app in AAD to use it to authenticate myself as an app.
After that I've added access policy in my KeyVault resource to allow GET operation for secrets for this registered app:
Then I've developed a small piece of code which should retrieve the desired secret:
public class AzureAuthentication
{
public async Task<string> GetAdminPasswordFromKeyVault()
{
const string clientId = "--my-client-id--";
const string tenantId = "--my-tenant-id--";
const string clientSecret = "--my-client-secret--";
var credentials = new ClientSecretCredential(tenantId, clientId, clientSecret);
var client = new SecretClient(new Uri("https://mykeyvaultresource.vault.azure.net"), credentials);
var secret = await client.GetSecretAsync("admincreds");
return secret.Value.Value;
}
}
However when I'm trying to do this I'm getting an AccessDenied error:
Am I missing something painfully obvious here? Or there is some latency (>30 min for this moment) for which changes from Access policies screen in KeyVault resource are applied?
I test your code and Get permission, it works fine.
From your screenshot, it looks you didn't add the correct service principal related to the AD App to the Access policies.
If you add the service principal related to the AD App, it will appear as APPLICATION, not COMPOUND IDENTITY.
So when you add it, you could search for the client Id(i.e. application Id) or the name of your App Registration directly, make sure you add the correct one.
Make sure your AD App(service principal) has the correct permission in your keyvault -> Access policies

Is the KeyVaultClient method GetSecret() safe?

I'm working with Azure Key Vault and I'm testing the "Managed Identities" for Azure Resource. Long story short: with this feature we can easily access to a KeyVault secrets from (e.g.) VM, App Service... I wrote this simple code:
private void GetKeyVaultSecrets()
{
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
var akvCallback = new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback);
var keyVaultClient = new KeyVaultClient(akvCallback);
var secret = keyVaultClient.GetSecretAsync("https://mykeyvault.vault.azure.net/secrets/mySecret").GetAwaiter().GetResult();
string superSecret = secret.Value;
}
And I'm able to access my "Secret" without any kind of Authorization. Is it safe? Am I missing something? It looks so strange that with those 7 lines of code you have access to all your secrets. Thanks for your attention.
If you are running this on a service with a system-assigned Managed Identity, here's what actually happens (example for App Service, VM is slightly different):
Your app reads IDENTITY_ENDPOINT and IDENTITY_HEADER environment variables
HTTP call to IDENTITY_ENDPOINT using the IDENTITY_HEADER as authentication
This endpoint cannot be called from the outside, only from within the instance.
Its port is also random
In the call, your app specifies it wants a token for Key Vault (resource https://vault.azure.net)
The Managed Identity endpoint uses the certificate it has created to authenticate to Azure Active Directory with the Client Credentials flow
Azure AD verifies the request and issues a token
Managed Identity endpoint returns the token to your app
KeyVaultClient uses the token to authorize the call to Key Vault
On Virtual Machines, the Instance Metadata Service is used to get tokens.
The main thing to understand is that any process running on the instance itself is capable of getting tokens from the Managed Identity.
Though if you were to get malicious code running on your instance,
other approaches could be in trouble as well :)
If you run that code locally, it can work as well.
AzureServiceTokenProvider also attempts Visual Studio authentication as well as Azure CLI authentication.
So if you are logged in to e.g. AZ CLI, it is able to get an access token for your user to Azure Key Vault and access it.
Reference: https://learn.microsoft.com/en-us/azure/app-service/overview-managed-identity?context=azure%2Factive-directory%2Fmanaged-identities-azure-resources%2Fcontext%2Fmsi-context&tabs=dotnet#rest-protocol-examples
Example request done in VMs: https://learn.microsoft.com/en-us/azure/active-directory/managed-identities-azure-resources/tutorial-windows-vm-access-nonaad#access-data

Unable to connect to Azure Key Vault from Azure Web App

I am trying to access Azure Key Vault from my Azure App Service. I followed the steps outlined on this documentation: https://learn.microsoft.com/en-us/azure/key-vault/managed-identity (turned on system assigned identity for the app service, updated the access policy of the key vault to include the app with Get,List secret permissions).
However, when I run the web application, it is not able to get the secret from the key vault and my web service hits the following error:
502 - Web server received an invalid response while acting as a gateway or proxy server.
There is a problem with the page you are looking for, and it cannot be displayed. When the Web server (while acting as a gateway or proxy) contacted the upstream content server, it received an invalid response from the content server.
This is what my code looks like:
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = keyVaultClient.GetSecretAsync(KeyVaultUrl);
authenticationKey = secret.Result.Value;
The service gets stuck on the secret.Result.Value line. Is there something else I need to do?
This is much easier with the new package, like Azure.Security.KeyVault.Secrets. Together with Azure.Identity, you can just pass a DefaultAzureCredential like in our samples.
var client = new SecretClient(
new Uri("https://myvault.vault.azure.net"),
new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync("secret-name");
string authenticationKey = secret.Value;
The DefaultAzureCredential is optimized to work for managed identity, service principals from the environment, and interactive logins to support the same code running both in production and on developer machines. The new libraries are also faster with fewer allocations, and have much better diagnostics - defaulted to on when using Azure Application Monitor.
They target netstandard2.0 so should be compatible with the older packages these replace. Would you be able to upgrade? We're only making critical fixes for the older packages, and recommending people upgrade to Azure.* packages intead of the older Microosft.Azure.* packages.
As for the problem itself, it's hard to say without knowing when you're calling this in your application. During startup? What version of .NET? What are you using for your ASP.NET application framework?
While it's probably not the cause of the problem, it's hard to ignore that you're calling an async method synchronously, which can also cause problems. If you're in an async method, you should write your code like so:
var secret = await keyVaultClient.GetSecretAsync(KeyVaultUrl);
authenticationKey = secret.Value;
If not, call:
var secret = keyVaultClient.GetSecretAsnc(KeyVaultUrl).GetAwaiter().GetResult();
This is not recommended, though. In the new packages I mentioned above, we have both sync and async versions that are either sync or async all the way through the call stack and safer to use. Generally, though, you should use async calls - especially for network traffic like accessing Key Vault because, depending on what thread you call it, it can hang your UI.
When you test in local:
Add your vs signed account into azure keyvault. Go to keyvault> Access policy> add your account with get secret permmission.
When you publish to azure:
1.Enable webapp MSI.
2.Go to keyvault> Access policy> add your webapp's service principal with get secret permission.
The code:
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new Microsoft.Azure.KeyVault.KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = keyVaultClient.GetSecretAsync("https://yourkevaultname.vault.azure.net/secrets/secretname/437d301daxxxxxx");
var authenticationKey = secret.Result.Value;
ViewBag.Message = authenticationKey.ToString();

Use Azure Vault Secret from onpremise Web Application

I would like to use an Azure Key Vault secret from an on-premise web application.
I created a Key Vault with a Secret, but in Access Policies I should specify an Authorized Application and in the samples is used an Azure WebApp.
I want instead use the Secret from on-premise MVC web app: shoud i specify nothing and it works ? i specified the Azure Vault and as Principal myself but i'm not sure if this is correct.
Well, something will need to authenticate to access the secret.
Either the current user, or you can use a service principal.
Since we are talking about an MVC app, the service principal is probably easier.
You will need to register a new app in Azure Active Directory via the Azure Portal.
Find Azure AD, and register a new app via App registrations.
The name and URLs don't really matter, but it needs to be of type Web app/API.
The sign-on URL can be https://localhost for example.
Then add a key in the Keys blade to the app (click Settings after the app is created, then Keys).
Copy the client id (application id) and the key somewhere.
Now you can go to your Key Vault, and create a new access policy, and choose the app you created as the principal.
Give it the rights you want, like Secrets -> Get.
Then you can save the policy.
In your app, you can then use the Key Vault library + ADAL like so:
var kvClient = new KeyVaultClient(async (authority, resource, scope) =>
{
var context = new AuthenticationContext(authority);
var credential = new ClientCredential("client-id-here", "key-here");
AuthenticationResult result = await context.AcquireTokenAsync(resource, credential);
return result.AccessToken;
});
SecretBundle secret = await kvClient.GetSecretAsync("https://yourvault.vault.azure.net/", "secret-name");
string secretValue = secret.Value;

How to give MSI enabled Function App access to Key Vault?

I have a Function App with Managed service identity (MSI) enabled.
I'm trying to use this Function App to access a secret from my Key Vault.
I have added the code into my Function App to retrieve the secret.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("https://test-prototype-vault.vault.azure.net/secrets/batman/guidhere").ConfigureAwait(false);
I receive the following error:
Microsoft.Azure.WebJobs.Script: One or more errors occurred. Microsoft.Azure.KeyVault: Access denied.
I think this is because I need to (as described in the link above).
You may need to configure the target resource to allow access from
your application. For example, if you request a token to Key Vault,
you need to make sure you have added an access policy that includes
your application's identity.
I don't know how to do that. I have gone to my Key Vault and tried to add an Access Policy - I can't find the application to Select Principle option.
Setup of Azure Function.
What happens when I try to add the principal.
This blog has details but you need to go into key vault and give the function app access to secrets in a new access policy
https://medium.com/#jeffhollan/getting-key-vault-secrets-in-azure-functions-37620fd20a0b
The name of your function app should show in list of users

Resources