Introduction
Azure Key Vault Implementation in ASP.NET core site hosted on On-Premise Azure VM.
This article covers how to implement key vault part of application design, architecture and development, the cloud configurations to consume key vault is out of this topic coverage, however the required essential information is provided part of pre-requistes to consume key vault for on-premise web app setup.
Background
When keyvault is needed for storing client secrets, credentials for host VMS in cloud specially Azure.
Pre-requistes
Using the Code
Code to Implement Key Vault in ASP.NET Core Program.cs File
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
var builder = config.Build();
var keyVaultEndpoint = builder["KeyVault:Vault"];
var azureServiceTokenProvider = new AzureServiceTokenProvider();
var keyVaultClient = new KeyVaultClient(
new KeyVaultClient.AuthenticationCallback(
azureServiceTokenProvider.KeyVaultTokenCallback)
);
config.AddAzureKeyVault(keyVaultEndpoint,keyVaultClient,
new DefaultKeyVaultSecretManager());
})
.UseStartup<Startup>()
.Build();
Sample environment based appSettings file which has reference to say example crm, social logins, custom password, etc.
"KeyVault": {
"Vault": "https://nameofkeyvault.vault.azure.net/",
"Authentication": {
"Microsoft": {
"ApplicationId": "appidkey",
"Password": "nameofpasswordkeyvault"
},
"Google": {
"ClientId": "appidkey",
"ClientSecret": "nameofpasswordkeyvault"
},
"Facebook": {
"AppId": "appidkey",
"AppSecret": "nameofpasswordkeyvault"
},
"LinkedIn": {
"AppId": "appidkey",
"AppSecret": "nameofpasswordkeyvault"
}
},
"Xrm": {
"Configuration": {
"SVCEndpoint": "https://client.myblog.com:443/OnlineService.svc",
"ServiceUrl": "http://client.myblog.com/api/data/v8.0/",
"ClientId": "",
"Domain": "myblog.com",
"UserName": "crm",
"Password": "crm",
"IsWebAPIEndpoint": true,
"IsSVCEndpoint": true
}
}
}
- Access the key vault values via Startup.cs or any other classes if referencing any external login or any other dependencies like API, etc.
Example for Startup.cs:
services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
.AddCookie(options => { options.LoginPath = "/Account/Login/"; })
.AddMicrosoftAccount(microsoftOptions =>
{
microsoftOptions.ClientId =
Configuration["KeyVault:Authentication:Microsoft:ApplicationId"];
var password= Configuration["KeyVault:Authentication:Microsoft:Password"];
microsoftOptions.ClientSecret = Configuration[password];
})
.AddGoogle(googleOptions =>
{
googleOptions.ClientId = Configuration["KeyVault:Authentication:Google:ClientId"];
var clientSecret= Configuration["KeyVault:Authentication:Google:ClientSecret"];
googleOptions.ClientSecret = Configuration[clientSecret];
})
.AddFacebook(facebookOptions =>
{
facebookOptions.AppId = Configuration["KeyVault:Authentication:Facebook:AppId"];
var appSecret= Configuration["KeyVault:Authentication:Facebook:AppSecret"];
facebookOptions.AppSecret = Configuration[appSecret];
});
Inside any controller or any class file, the configuration values can be accessed via the IOptions
Configuration interface.
In controller via Constructor injection like below:
public class SampleController : Controller
{
#region Variables
private readonly IConfiguration _configuration;
#endregion #region constructors
public SampleController(IConfiguration configuration)
{
_configuration = configuration;
}
#Methods
public async Task<ActionResult> SampleMethod(string fileUri, string fileName)
{
try
{
if (User.Identity.IsAuthenticated)
{
var vault = _configuration.GetSection
("KeyVault:Xrm: COnfiguration:UserName");
}
}
catch (Exception ex)
{
ViewData["message"] = ex.Message;
View("~/Views/Shared/Error.cshtml");
}
return null;
}
Known Issues
- There will be known issues for projects after 2.1 due to the below package upgrade required.
Microsoft.Azure.Services.AppAuthentication v1.3.1
is required, add the nuget and publish. - Please add this package and build, publish to the website on the VM to test, for any issue, enable logging in web.config (
stdout ~ true
)