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

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.

Related

Add Value to Azure App Configuration using Pulumi

I created an App Configuration using Pulumi:
_configurationStore = new ConfigurationStore(appConfigurationName, new ConfigurationStoreArgs
{
ResourceGroupName = _resourceGroup.Name,
Location = _resourceGroup.Location,
Sku = "standard"
});
Now I am stuck adding values to it. The docs don't mention any method to read or write settings into my ConfigurationStore (or I simply cannot find it).
How can I store simple key/value-Pairs?
How can I store "links" to values from an existing keyvault? Do I simply create the connectionstring manually?
Adding key-values was introduced by Azure Resource Manager (ARM) just recently in the 2020-07-01-preview version and there's no "stable" API version with them yet. So, you should use that version to define key-values
new Pulumi.AzureNextGen.AppConfiguration.V20200701Preview.KeyValue("kv",
new Pulumi.AzureNextGen.AppConfiguration.V20200701Preview.KeyValueArgs
{
ResourceGroupName = _resourceGroup.Name,
ConfigStoreName = _configurationStore.Name,
KeyValueName = "key1",
Value = "value1",
});
You can read more in the docs: https://www.pulumi.com/docs/reference/pkg/azure-nextgen/appconfiguration/keyvalue/
Also, discussed in this issue: https://github.com/pulumi/pulumi-azure-nextgen/issues/62

How to retrieve Secret from Azure Key Vault using DefaultAzureCredential

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.

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.

Azure KeyVault Configuration Provider reload values on change

I'm using Azure Key Vault Configuration Provider to read some secrets at app startup. The secrets however keep rotating throughout the day and I want to be able to reload the new values when this rotation happens.
What I'm talking about is similar to the reloadOnChange api
.ConfigureAppConfiguration((context, config) =>
{
config.AddJsonFile("appsettings.json", reloadOnChange: true);
})
Is this possible at all?
This is a webapi project so in practice, I could get away with manually reloading the values for every HttpRequest if that's better/more feasibe.
Using Microsoft.Extensions.Configuration.AzureKeyVault (v3) you can do the following:
configurationBuilder.AddAzureKeyVault(new AzureKeyVaultConfigurationOptions
{
Vault = configuration["KeyVaultUrl"],
ReloadInterval = TimeSpan.FromMinutes(10),
Client = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(
new AzureServiceTokenProvider().KeyVaultTokenCallback))
});
Now when you request for IConfiguration in your services, the KeyVault secrets will be available and refreshed based on your reload interval.
Secrets are cached until IConfigurationRoot.Reload() is called. Expired, disabled, and updated secrets in the key vault are not respected by the app until Reload is executed.
Configuration.Reload();
For more details, you could refer to this article.
Same thing as Bobby Koteski proposed, but with a newer Azure.Extensions.AspNetCore.Configuration.Secrets package, as Microsoft.Extensions.Configuration.AzureKeyVault is deprecated.
ReloadInterval is a time to wait between attempts at polling the Azure Key Vault for changes.
configurationBuilder.AddAzureKeyVault(
new SecretClient(
new Uri(configuration["KeyVaultBaseUrl"]),
new ManagedIdentityCredential(configuration["UserAssignedManagedIdentityClientId"])
),
new AzureKeyVaultConfigurationOptions()
{
ReloadInterval = TimeSpan.FromSeconds(1000)
}
);
And a link to a source code to see how it actually works :)

How to connect to Cloud Firestore DB with .net core?

So far all the examples of using Google Cloud Firestore with .net show that you connect to your Firestore db by using this command:
FirestoreDb db = FirestoreDb.Create(projectId);
But is this skipping the step of authentication? I can't seem to find an example of wiring it up to use a Google service account. I'm guessing you need to connect using the service account's private_key/private_key_id/client_email?
You can also use the credentials stored in a json file:
GoogleCredential cred = GoogleCredential.FromFile("credentials.json");
Channel channel = new Channel(FirestoreClient.DefaultEndpoint.Host,
FirestoreClient.DefaultEndpoint.Port,
cred.ToChannelCredentials());
FirestoreClient client = FirestoreClient.Create(channel);
FirestoreDb db = FirestoreDb.Create("my-project", client);
I could not compile #Michael Bleterman's code, however the following worked for me:
using Google.Cloud.Firestore;
using Google.Cloud.Firestore.V1;
var jsonString = File.ReadAllText(_keyFilepath);
var builder = new FirestoreClientBuilder {JsonCredentials = jsonString};
FirestoreDb db = FirestoreDb.Create(_projectId, builder.Build());
Packages I use:
<PackageReference Include="Google.Cloud.Firestore" Version="2.0.0-beta02" />
<PackageReference Include="Google.Cloud.Storage.V1" Version="2.5.0" />
But is this skipping the step of authentication?
No. It will use the default application credentials. If you're running on Google Cloud Platform (AppEngine, GCE or GKE), they will just be the default service account credentials for the instance. Otherwise, you should set the GOOGLE_APPLICATION_CREDENTIALS environment variable to refer to a service account credential file.
From the home page of the user guide you referred to:
When running on Google Cloud Platform, no action needs to be taken to authenticate.
Otherwise, the simplest way of authenticating your API calls is to download a service account JSON file then set the GOOGLE_APPLICATION_CREDENTIALS environment variable to refer to it. The credentials will automatically be used to authenticate. See the Getting Started With Authentication guide for more details.
It's somewhat more awkward to use non-default credentials; this recent issue gives an example.
This worked for me.
https://pieterdlinde.medium.com/netcore-and-cloud-firestore-94628943eb3c
string filepath = "/Users/user/Downloads/user-a4166-firebase-adminsdk-ivk8q-d072fdf334.json";
Environment.SetEnvironmentVariable("GOOGLE_APPLICATION_CREDENTIALS", filepath);
fireStoreDb = FirestoreDb.Create("user-a4166");
The simplest way:
Get service account json file and hardcode values into a class:
public class FirebaseSettings
{
[JsonPropertyName("project_id")]
public string ProjectId => "that-rug-really-tied-the-room-together-72daa";
[JsonPropertyName("private_key_id")]
public string PrivateKeyId => "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx";
// ... and so on
}
Add it Startup.cs
var firebaseJson = JsonSerializer.Serialize(new FirebaseSettings());
services.AddSingleton(_ => new FirestoreProvider(
new FirestoreDbBuilder
{
ProjectId = firebaseSettings.ProjectId,
JsonCredentials = firebaseJson // <-- service account json file
}.Build()
));
Add wrapper FirebaseProvider
public class FirestoreProvider
{
private readonly FirestoreDb _fireStoreDb = null!;
public FirestoreProvider(FirestoreDb fireStoreDb)
{
_fireStoreDb = fireStoreDb;
}
// ... your methods here
}
Here is a full example of a generic provider.
https://dev.to/kedzior_io/simple-net-core-and-cloud-firestore-setup-1pf9

Categories