How to retrieve Secret from Azure Key Vault using DefaultAzureCredential - c#

I have setup my keyVault in Azure, and add the secret there. I am now following instructions from Microsoft located here.
My current code looks like below:
var keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = "https://" + keyVaultName + "vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
var secret = (await client.GetSecretAsync("my-secret-key")).Value.Value;
I already set up the environment variable (system setting) to hold the name of the key vault with the variable name KEY_VAULT_NAME.
With the code above I am getting a exceptions: The requested name is valid, but no data of the requested type was found
I have a feeling I am using DefaultAzureCredential wrongly and that there is something I am missing?

I ended up using this resource by Microsoft, which uses virtually identical code but also has details on setting up a managed identity for your web app and giving it access to the specific Key Vault.
The code in my question is also now working having set up that managed identity access.

Related

Using C#, how to programmatically enable Azure Key Vault secret?

I need to programmatically enable / disable Azure Key Vault secrets in C#. I am able to disable a secret but I cannot figure out how to enable it. Here is the code:
//Setup client from Azure.Security.KeyVault.Secrets version 4.4.0
string keyVaultUrl = "…";
string tenantId = "…";
string clientId = "…";
string clientSecret = "…";
ClientSecretCredential credential = new ClientSecretCredential(tenantId, clientId, clientSecret);
_client = new SecretClient(new Uri(keyVaultUrl), credential);
//I am able to disable a secret
Azure.Response<KeyVaultSecret> response = await _client.GetSecretAsync(secretName, version: null, cancellationToken);
KeyVaultSecret secret = response.Value;
secret.Properties.Enabled = false;
_client.UpdateSecretProperties(secret.Properties);
//I am not able to enable a secret. Get error "Value cannot be null. (Parameter 'Version')"
AsyncPageable<SecretProperties> secretPropertiesCollection = _client.GetPropertiesOfSecretsAsync(cancellationToken);
await foreach (SecretProperties secretProperties in secretPropertiesCollection)
{
if (secretProperties.Name.ToUpperInvariant() == secretName.ToUpperInvariant())
{
secretProperties.Enabled = true;
_client.UpdateSecretProperties(secretProperties);
return;
}
}
I work on the Java offering for the Key Vault SDK but can shed some light on this. It looks that the UpdateSecretProperties method expects a version of the secret to be included in the SecretProperties passed to it. We don't do this in Java so I would have to have a chat with my C# counterpart to figure if this is a bug or the intended behavior. That said, you should still be able to enable a disabled secret programatically. If you know the name of the secret in question, you can call a SecretClient.GetPropertiesOfSecretVersions() method to obtain the SecretProperties of each version of the secret, which also include the version itself. You can then update the Enabled property to true and use the UpdateSecretProperties as you originally intended.
I'm not a C# expert but I think this is what it should look like:
AsyncPageable<SecretProperties> secretPropertiesCollection =
_client.GetPropertiesOfSecretVersionsAsync("secretName", cancellationToken);
await foreach (SecretProperties secretProperties in secretPropertiesCollection)
{
secretProperties.Enabled = true;
_client.UpdateSecretProperties(secretProperties);
return;
}
Alternatively, if you still have a handle for the original KeyVaultSecret object, you can set its Enabled property back to true and use the SetSecret() operation to update it, although this would not create a new version for the secret as opposed to the option I laid out above.
"Value cannot be null. (Parameter 'Version')
As commented by #Ralf, This is a known exception caused when the UpdateSecretProperties() method is returned with a null version which is because the GetPropertiesOfSecrets() method doesn't return individual secret's versions which is returned as null.
Individual secret versions are not listed in the response. This operation requires the secrets/list permission.
Currently, the get() permissions only work for enabled secrets. The only way that worked for me is to enable the secrets from portal.

C# ASP.NET MVC Use of Azure Key Vault Runtime Initialized Variables

I am looking for the most appropriate way to store and/or use variables initialized during startup (Program.cs) throughout the application as needed, or an acceptable alternative process if there's a better way to accomplish this.
I.e., the following code snippet in Program.cs initializes the Azure Key Vault connectionString variable at runtime with a correct value retrieved from the designated Azure Key Vault:
var keyVaultUrl = builder.Configuration.GetValue<string>("KeyVault:KeyVaultUrl");
if (app.Environment.IsDevelopment())
{
app.UseMigrationsEndPoint();
SecretClientOptions options = new SecretClientOptions()
{
Retry =
{
Delay= TimeSpan.FromSeconds(2),
MaxDelay = TimeSpan.FromSeconds(16),
MaxRetries = 5,
Mode = RetryMode.Exponential
}
};
var client = new SecretClient(new Uri(keyVaultUrl), new DefaultAzureCredential(), options);
KeyVaultSecret secretConnectionString = client.GetSecret("ConnectionString");
string connectionString = secretConnectionString.Value;
}
The objective is to use this variable or others on-demand without having to call the code another time. Any thoughts are appreciated.
Check the below steps to store the KeyVault Connection string in Azure Appsettings.
I do agree with #Dai, yes instead of getting the ConnectionString/Varaibles from KeyVault , we can store the values in Azure App Service => Configuration => Application Settings.
My appsettings.json
"ConnectionStrings": {
"MyVal": "DummyString"
}
Create a secret in KeyVault and copy the Secret Identifier.
Azure App Settings
Thanks to #Jayant Kulkarni - reference taken from c-sharpcorner.

Azure KeyVault throws 401 unauthorized error but the response still has 200 status and correct data

I registered an app with name TestApp1 to azure active directory using Accounts in this organizational directory only (Default Directory only - Single tenant) and no Redirect URI.
Along with the application I created an application secret.
Afterwards i created an Azure Key Vault with name KVtest and created a certificate.
Then i went to KVtest Access Control (IAM) option and added a role of contributor to my TestApp1.
After that, i went to access policy option and added a policy with template Key,Secret & Certificate Management and selected as Principal my TestApp1
Right now i am testing this Azure configuration using the following :
const string certificate = "testCertificate";
var myKeyVaultName = "KVtest";
var kvUri = $"https://KVtest.vault.azure.net/";
string clientId = ConfigurationManager.AppSettings["ClientId"];
string clientSecret = ConfigurationManager.AppSettings["ClientSecret"];
string tenantId = ConfigurationManager.AppSettings["AzureTenantId"];
var clientSecretCred = new ClientSecretCredential(tenantId, clientId, clientSecret);
var certClient = new CertificateClient(new Uri(kvUri), clientSecretCred);
var AZcertificate = certClient.GetCertificate(certificate);
The last line throws a 401 (unauthorized) exception but when i continue with debugging step by step the value stored at AZcertificate has an Azure.Response object with status 200 and correct data.
Is this the correct behavior?
Is this an error to azure configuration?
Nuget packages used:
As far as I know, the reason behind getting 401 error is using trailing slash at the end of the Key Vault resource URI
var kvUri = $"https://KVtest.vault.azure.net/";
Other resource URIs can work with or without trailing slash but Key Vault resource URI doesn't work with it.
To resolve it, try removing the trailing slash as below:
var kvUri = $"https://KVtest.vault.azure.net";
Other reasons for getting 401 unauthorized error are:
Lack of access token : Make sure whether the client is sending access token with every request to the Key Vault, Otherwise it will reject the request with 401 error.
Bad token : If the token is expired , invalid or incorrect resource URI, then it causes 401 error.
For more information in detail, please refer these links if they are helpful:
AZIdentity | Azure Key Vault OAuth Resource Value: https://vault.azure.net (no slash!)
AZIdentity | Key Vault Client: Why am I seeing HTTP 401?

Azure keyvault from on prem .net app without exposing clientid/clientsecret?

I've registered my app in azure AD and created a client secret and then created a vault and added a secret for the dbconnectionstring below. It works ok but I need the "client-id" and "client-secret" since the identity is managed as service principal. Is there a way to get thos values through an API so that my app doesn't have to save those in the config? It's kind of defeating the purpose since thos whole exercise was to avoid having to save connection strings in the web.config/appsettings.json; as now I can save those in the vault but I would need to save the clientid/secret in the config.
var kvClient = new KeyVaultClient(async (authority, resource, scope) =>
{
var context = new AuthenticationContext(authority);
var credential = new ClientCredential("client-id", "client-secret");
AuthenticationResult result = await context.AcquireTokenAsync(resource, credential);
return result.AccessToken;
});
try
{
var connStrENTT = kvClient.GetSecretAsync("https://myvault.vault.azure.net/", "DBConfigConnection").Result.Value;
}
Why do you need to acquire token via your code if you are using managed identity? Managed identity is supposed to hide this for you.
Please use the guidance provided in a sample like this to take the correct steps.

Generate Azure KeyVault SecretIdentifier (Url) with Version

We are creating secrets dynamically in azure key vault and now we want to get Secret Identifier / Uri with version so that secrets can be retrieved ?
Is there any built in method or easy way to generate Secret Identifier ? Mainly I am getting challenge to retrieve secret version.
Sample : https://YourVaultName.vault.azure.net/keys/YourKeyName/01234567890123456789012345678901
We are using keyvaultclient C# class to manage keyVault in our application
To get the current version of the secret, you could use GetSecretAsync .
I use Microsoft.Azure.Services.AppAuthentication to create a keyvault client, sample here.
var azureServiceTokenProvider1 = new AzureServiceTokenProvider();
var kv = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider1.KeyVaultTokenCallback));
var secret = kv.GetSecretAsync("https://<keyvault-name>.vault.azure.net/", "<secret-name>").GetAwaiter().GetResult();
Console.WriteLine(secret.SecretIdentifier.Version);
If you want to get all the versions of the secret, you could use GetSecretVersionsAsync.
var versions = kv.GetSecretVersionsAsync("https://<keyvault-name>.vault.azure.net/", "<secret-name>").GetAwaiter().GetResult();

Categories