How to ask DefaultAzureCredential to use my user credential locally - azure

I'm trying to develop a web app on an Azure VM that uses Azure Key Vault. Later this app will also be deployed to Azure. As far as I know, the most straight forward way to make the app work, both locally and deployed, with the key vault, is to use the DefaultAzureCredential class. The code would be like this:
string kvUri = "https://" + keyvaultName + ".vault.azure.net";
SecretClient client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
KeyVaultSecret secret = await client.GetSecretAsync(secretName);
At runtime, the provider will try different credential types in order.
This sounds exactly what I want:
When developing locally (on the Azure VM, though), I want to use my user credential (user identity added to the key vault's permission) without any configuration, since I have already logged into the Visual Studio using the same user credential.
Once deployed to Azure, I want to use the app registration credential (also added to the key vault's permission).
But when running the app locally, I'm getting a 403 error The user, group or application .... does not have secrets get permission on key vault ...
After looking up the object id in the error message, I realize it's the dev machine Azure VM's credential that the application uses, not my user credential.
Is there a way to change this behavior?

To prevent the Azure VM from getting a token, you can exclude the ManagedIdentityCredential in your Development environment and only enable it in a Non-Development environment.
if (environment.IsDevelopment())
{
var credentials = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeManagedIdentityCredential = true,
ExcludeAzureCliCredential = true
});
}
else
{
var credentials = new DefaultAzureCredential(new DefaultAzureCredentialOptions
{
ExcludeVisualStudioCodeCredential = true,
ExcludeVisualStudioCredential = true
});
}
Once deployed to Azure, I want to use the app registration credential (also added to the key vault's permission).
An Azure App Service can use a managed identity as well. There is no need for a separate App Registration.
See https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme#key-concepts for more information.

Create and identity if you wish to use (default identity)
appservice -> select you application -> identity->enable it ->should give you a Id
and than add it to key Vault Access policy
alternatively app registration can be used with tenantId,clientId,secret to connect to keyvault

Related

Api-version must be specified when using azure keyvault SecretClient .net sdk

I am trying to set a secret in azure keyvault using managed identity. There are two problems which I am facing right now. Hope someone can help me with it.
Code:
var client = new SecretClient(new Uri("keyvaulturl"),
new DefaultAzureCredential(new DefaultAzureCredentialOptions()
{ ExcludeManagedIdentityCredential = true }));
await client.SetSecretAsync(new KeyVaultSecret(keyName,
serializer.SerializeObject(someobject)));
Problem 1:
DefaultAzureCrendetialOption is not working for managed identity but when I am setting ExcludeManagedIdentityCredential to true it is able to fallback to the next authentication provider (must be azure cli). I am not sure why this is happening because couple of days before the same code was working and I was able to set and retrieve keyvault secrets using the same code.(ofcourse without using any DefaultAzureCredentialOptions parameters).
Please note this problem only happens in my local env and managed identity works fine when deployed in azure.
Problem 2:
When setting ExcludeManagedIdentityCredential to true for local development, I started seeing another problem where it is giving me error that api-version is missing. I dont understand why and where do I need to specify the api version when using azure .net sdk.
Error:
Service request failed.
Status: 400 (Bad Request)
Content:
{"error":{"code":"BadParameter","message":"api-version must be specified"}}
Problem 1:
Managed Identity cannot be used to authenticate locally-running applications by design. Try to read the Important tip in the document.
Managed Identity cannot be used to authenticate locally-running
applications. Your application must be deployed to an Azure
service that supports Managed Identity.
Problem 2:
Please change the version of Azure Key Vault secret client library with the latest varsion.
dotnet add package Azure.Security.KeyVault.Secrets
I tried DefaultAzureCredential with environment variables in my local.
string keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = "https://" + keyVaultName + ".vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
KeyVaultSecret secret = new KeyVaultSecret("testdefault", "123456");
KeyVaultSecret result = await client.SetSecretAsync(secret);
Console.WriteLine(result.Name);

Get Secret from Azure Keyvault using nodejs

I need to read the list of users in the Azure active directory. The client has created a Graph API application but they do not want to share the client secret of the application, instead they asked us to use the Key vault. How to access from the node.js application the key to retrieve the list of users?
I tried the below one but gave error and I am not sure how to authenticate.
const { DefaultAzureCredential } = require("#azure/identity");
const { SecretClient } = require("#azure/keyvault-secrets");
const credential = new DefaultAzureCredential();
const vaultName = "lsm-keyvault";
const url = `https://${vaultName}.vault.azure.net`;
const client = new SecretClient(url, credential);
const secretName = "Demo";
async function main() {
const result = await client.setSecret(secretName, "MySecretValue", {
enabled: false
});
console.log(result)
}
Well, if you run the code in local, the DefaultAzureCredential will use the environmental variables automatically.
So in your case, you need to register an application with Azure AD, and get the tenant id, client id(i.e. application id), client secret(i.e. application secret), set the environmental variables, AZURE_CLIENT_ID, AZURE_CLIENT_SECRET, and AZURE_TENANT_ID.
For the 403 error you got, I notice you said It added as a compound entity, based on my experience, you did not add the correct service principal related to the AD App correctly to the Access policies of the keyvault. If you add it correctly, 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. I gave the details in this similar issue, you could refer to it.
To retrieve the secret, the Get permission is enough, the code should be
const retrievedSecret = await client.getSecret(secretName);
I notice you use client.setSecret in your code, it is used to save a secret, to use it, you may need the Set permission.
For more details, see Quickstart: Azure Key Vault client library for Node.js (v4).
Update:
I have to eventually need to deploy this but not in azure but in another environment. How do I set the environment variables and access it.
If so, you need to change your code to authenticate, use the three values directly in the code.
Change the lines
const { DefaultAzureCredential } = require("#azure/identity");
const credential = new DefaultAzureCredential();
To
const { ClientSecretCredential } = require("#azure/identity");
const credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
See - https://www.npmjs.com/package/#azure/identity/v/1.0.3#authenticating-as-a-service-principal
All you need to do is follow the below steps:
Create an App in the Azure Active Directory (Service Principal) from App Registrations.
Go to Key Vault resource, Access Policy blade, assign read access to this Azure AD App (Service Principal) that we created in the above step.
Set these 3 Environment variables AZURE_CLIENT_ID, AZURE_TENANT_ID, and AZURE_CLIENT_SECRET in your App Service. Get the values of these variables from the app that we created in step 1.
Use DefaultAzureCredential that we are already using now. This will automatically pick the credentials from the environment variables that we defined in App Service for the authentication.
Another way is to obtain Key Vault token dynamically and use that token to get the secrets from the Key Vault - https://learn.microsoft.com/en-us/samples/azure-samples/app-service-msi-keyvault-node/app-service-msi-keyvault-node/
Helpful Reference:
https://www.rahulpnath.com/blog/defaultazurecredential_from_azure_sdk/

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

Read secret stored in Key Vault from an App Service running a container

I've created an App Service that is running a container running Identity Server. This container needs a certificate that I'm loading from Key Vault. To get the content of the certificate what I've done is:
Upload the certificate into Key Vault
Access the content accessing the secret endpoint of the Key Vault (https://mykeyvault.vault.azure.net/secrets/IdentityCert)
In my first attempt, I was storing just the URI of the secret in the App Settings and try to get the value using the following code:
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var cert = keyVaultClient
.GetSecretAsync(
Env.GetString("CERTIFICATE_KEY_VAULT_KEY"))
.ConfigureAwait(false).GetAwaiter().GetResult();
identityServerBuilder.AddSigningCredential(new X509Certificate2(Convert.FromBase64String(cert.Value)));
This works if I deploy the code into a VM. But it doesn't if I deploy the code into an App Service running a container. So I decided to try another option which is to use the Key Vault reference thing. So, I've created a new App Settings like this:
CERTIFICATE_CONTENT = #Microsoft.KeyVault(SecretUri=https://mykeyvault.vault.azure.net/secrets/IdentityCert/5221036c6b734d5fa69cba29976a8592)
And then just use this value inside my code:
var certificateContent = Env.GetString("CERTIFICATE_CONTENT");
identityServerBuilder.AddSigningCredential(new X509Certificate2(Convert.FromBase64String(certificateContent)));
But this doesn't work either.
I've enabled the managed identity in the App Service and added it to the Access Policies in the Key Vault.
How can I get the value from Key Vault? Is there anything I'm missing?
So, the error was the way I was adding the new access policy. I was selecting the principal Id and the Authorized application. It turns out that I only need to select the principal, leaving the Authorized application as "None selected".

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;

Resources