Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for Azure Key Vault #715

Merged
merged 6 commits into from
Oct 1, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions src/Skoruba.IdentityServer4.Admin.Api/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ private static IConfiguration GetConfiguration(string[] args)
configurationBuilder.AddUserSecrets<Startup>();
}

var configuration = configurationBuilder.Build();

configuration.AddAzureKeyVaultConfiguration(configurationBuilder);

configurationBuilder.AddCommandLine(args);
configurationBuilder.AddEnvironmentVariables();

Expand All @@ -60,6 +64,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostContext, configApp) =>
{
var configurationRoot = configApp.Build();

configApp.AddJsonFile("serilog.json", optional: true, reloadOnChange: true);

var env = hostContext.HostingEnvironment;
Expand All @@ -71,6 +77,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
configApp.AddUserSecrets<Startup>();
}

configurationRoot.AddAzureKeyVaultConfiguration(configApp);

configApp.AddEnvironmentVariables();
configApp.AddCommandLine(args);
})
Expand Down
4 changes: 1 addition & 3 deletions src/Skoruba.IdentityServer4.Admin.Api/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ public void ConfigureServices(IServiceCollection services)
// Add DbContexts
RegisterDbContexts(services);

services.AddDataProtection()
.SetApplicationName("Skoruba.IdentityServer4")
.PersistKeysToDbContext<IdentityServerDataProtectionDbContext>();
services.AddDataProtection<IdentityServerDataProtectionDbContext>(Configuration);

// Add email senders which is currently setup for SendGrid and SMTP
services.AddEmailSenders(Configuration);
Expand Down
17 changes: 14 additions & 3 deletions src/Skoruba.IdentityServer4.Admin.Api/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,13 +40,24 @@
},
"IdentityOptions": {
"Password": {
"RequiredLength": 8
"RequiredLength": 8
},
"User": {
"RequireUniqueEmail": true
"RequireUniqueEmail": true
},
"SignIn": {
"RequireConfirmedAccount": false
"RequireConfirmedAccount": false
}
},
"DataProtectionConfiguration": {
"ProtectKeysWithAzureKeyVault": false
},
"AzureKeyVaultConfiguration": {
"AzureKeyVaultEndpoint": "",
"ClientId": "",
"ClientSecret": "",
"UseClientCredentials": true,
"DataProtectionKeyIdentifier": "",
"ReadConfigurationFromKeyVault": false
}
}
14 changes: 13 additions & 1 deletion src/Skoruba.IdentityServer4.Admin/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -3,13 +3,17 @@
using System.Linq;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Azure.KeyVault;
using Microsoft.Azure.Services.AppAuthentication;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
using Microsoft.Extensions.Hosting;
using Serilog;
using Skoruba.IdentityServer4.Admin.Configuration;
using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.DbContexts;
using Skoruba.IdentityServer4.Admin.EntityFramework.Shared.Entities.Identity;
using Skoruba.IdentityServer4.Admin.Helpers;
using Skoruba.IdentityServer4.Shared.Configuration.Common;
using Skoruba.IdentityServer4.Shared.Helpers;

namespace Skoruba.IdentityServer4.Admin
Expand Down Expand Up @@ -49,7 +53,7 @@ public static async Task Main(string[] args)
private static async Task ApplyDbMigrationsWithDataSeedAsync(string[] args, IConfiguration configuration, IHost host)
{
var applyDbMigrationWithDataSeedFromProgramArguments = args.Any(x => x == SeedArgs);
if (applyDbMigrationWithDataSeedFromProgramArguments) args = args.Except(new[] {SeedArgs}).ToArray();
if (applyDbMigrationWithDataSeedFromProgramArguments) args = args.Except(new[] { SeedArgs }).ToArray();

var seedConfiguration = configuration.GetSection(nameof(SeedConfiguration)).Get<SeedConfiguration>();
var databaseMigrationsConfiguration = configuration.GetSection(nameof(DatabaseMigrationsConfiguration))
Expand Down Expand Up @@ -79,6 +83,10 @@ private static IConfiguration GetConfiguration(string[] args)
configurationBuilder.AddUserSecrets<Startup>();
}

var configuration = configurationBuilder.Build();

configuration.AddAzureKeyVaultConfiguration(configurationBuilder);

configurationBuilder.AddCommandLine(args);
configurationBuilder.AddEnvironmentVariables();

Expand All @@ -89,6 +97,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostContext, configApp) =>
{
var configurationRoot = configApp.Build();

configApp.AddJsonFile("serilog.json", optional: true, reloadOnChange: true);
configApp.AddJsonFile("identitydata.json", optional: true, reloadOnChange: true);
configApp.AddJsonFile("identityserverdata.json", optional: true, reloadOnChange: true);
Expand All @@ -104,6 +114,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
configApp.AddUserSecrets<Startup>();
}

configurationRoot.AddAzureKeyVaultConfiguration(configApp);

configApp.AddEnvironmentVariables();
configApp.AddCommandLine(args);
})
Expand Down
4 changes: 1 addition & 3 deletions src/Skoruba.IdentityServer4.Admin/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,7 @@ public void ConfigureServices(IServiceCollection services)
RegisterDbContexts(services);

// Save data protection keys to db, using a common application name shared between Admin and STS
services.AddDataProtection()
.SetApplicationName("Skoruba.IdentityServer4")
.PersistKeysToDbContext<IdentityServerDataProtectionDbContext>();
services.AddDataProtection<IdentityServerDataProtectionDbContext>(Configuration);

// Add email senders which is currently setup for SendGrid and SMTP
services.AddEmailSenders(Configuration);
Expand Down
22 changes: 17 additions & 5 deletions src/Skoruba.IdentityServer4.Admin/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -61,13 +61,25 @@
"BasePath": "",
"IdentityOptions": {
"Password": {
"RequiredLength": 8
"RequiredLength": 8
},
"User": {
"RequireUniqueEmail": true
"RequireUniqueEmail": true
},
"SignIn": {
"RequireConfirmedAccount": false
}
"SignIn": {
"RequireConfirmedAccount": false
}
},
"DataProtectionConfiguration": {
"ProtectKeysWithAzureKeyVault": false
},

"AzureKeyVaultConfiguration": {
"AzureKeyVaultEndpoint": "",
"ClientId": "",
"ClientSecret": "",
"UseClientCredentials": true,
"DataProtectionKeyIdentifier": "",
"ReadConfigurationFromKeyVault": false
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
using System.Security.Cryptography.X509Certificates;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging;
using Skoruba.IdentityServer4.Shared.Configuration.Common;
using Skoruba.IdentityServer4.Shared.Helpers;
using Skoruba.IdentityServer4.STS.Identity.Configuration;

namespace Skoruba.IdentityServer4.STS.Identity.Helpers
Expand All @@ -27,6 +29,7 @@ public static class IdentityServerBuilderExtensions
public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentityServerBuilder builder, IConfiguration configuration)
{
var certificateConfiguration = configuration.GetSection(nameof(CertificateConfiguration)).Get<CertificateConfiguration>();
var azureKeyVaultConfiguration = configuration.GetSection(nameof(AzureKeyVaultConfiguration)).Get<AzureKeyVaultConfiguration>();

if (certificateConfiguration.UseSigningCertificateThumbprint)
{
Expand Down Expand Up @@ -66,6 +69,12 @@ public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentitySe

builder.AddSigningCredential(certificate);
}
else if (certificateConfiguration.UseSigningCertificateForAzureKeyVault)
{
var x509Certificate2Certs = AzureKeyVaultHelpers.GetCertificates(azureKeyVaultConfiguration).GetAwaiter().GetResult();

builder.AddSigningCredential(x509Certificate2Certs.ActiveCertificate);
}
else if (certificateConfiguration.UseSigningCertificatePfxFile)
{
if (string.IsNullOrWhiteSpace(certificateConfiguration.SigningCertificatePfxFilePath))
Expand Down Expand Up @@ -112,6 +121,7 @@ public static IIdentityServerBuilder AddCustomSigningCredential(this IIdentitySe
public static IIdentityServerBuilder AddCustomValidationKey(this IIdentityServerBuilder builder, IConfiguration configuration)
{
var certificateConfiguration = configuration.GetSection(nameof(CertificateConfiguration)).Get<CertificateConfiguration>();
var azureKeyVaultConfiguration = configuration.GetSection(nameof(AzureKeyVaultConfiguration)).Get<AzureKeyVaultConfiguration>();

if (certificateConfiguration.UseValidationCertificateThumbprint)
{
Expand All @@ -134,6 +144,15 @@ public static IIdentityServerBuilder AddCustomValidationKey(this IIdentityServer
builder.AddValidationKey(certificate);

}
else if (certificateConfiguration.UseValidationCertificateForAzureKeyVault)
{
var x509Certificate2Certs = AzureKeyVaultHelpers.GetCertificates(azureKeyVaultConfiguration).GetAwaiter().GetResult();

if (x509Certificate2Certs.SecondaryCertificate != null)
{
builder.AddValidationKey(x509Certificate2Certs.SecondaryCertificate);
}
}
else if (certificateConfiguration.UseValidationCertificatePfxFile)
{
if (string.IsNullOrWhiteSpace(certificateConfiguration.ValidationCertificatePfxFilePath))
Expand All @@ -155,7 +174,7 @@ public static IIdentityServerBuilder AddCustomValidationKey(this IIdentityServer
}
else
{
throw new Exception($"Validation key file: {certificateConfiguration.SigningCertificatePfxFilePath} not found");
throw new Exception($"Validation key file: {certificateConfiguration.ValidationCertificatePfxFilePath} not found");
}
}

Expand Down
8 changes: 8 additions & 0 deletions src/Skoruba.IdentityServer4.STS.Identity/Program.cs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,10 @@ private static IConfiguration GetConfiguration(string[] args)
configurationBuilder.AddUserSecrets<Startup>();
}

var configuration = configurationBuilder.Build();

configuration.AddAzureKeyVaultConfiguration(configurationBuilder);

configurationBuilder.AddCommandLine(args);
configurationBuilder.AddEnvironmentVariables();

Expand All @@ -60,6 +64,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
Host.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((hostContext, configApp) =>
{
var configurationRoot = configApp.Build();

configApp.AddJsonFile("serilog.json", optional: true, reloadOnChange: true);

var env = hostContext.HostingEnvironment;
Expand All @@ -71,6 +77,8 @@ public static IHostBuilder CreateHostBuilder(string[] args) =>
configApp.AddUserSecrets<Startup>();
}

configurationRoot.AddAzureKeyVaultConfiguration(configApp);

configApp.AddEnvironmentVariables();
configApp.AddCommandLine(args);
})
Expand Down
4 changes: 1 addition & 3 deletions src/Skoruba.IdentityServer4.STS.Identity/Startup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,9 +36,7 @@ public void ConfigureServices(IServiceCollection services)
RegisterDbContexts(services);

// Save data protection keys to db, using a common application name shared between Admin and STS
services.AddDataProtection()
.SetApplicationName("Skoruba.IdentityServer4")
.PersistKeysToDbContext<IdentityServerDataProtectionDbContext>();
services.AddDataProtection<IdentityServerDataProtectionDbContext>(Configuration);

// Add email senders which is currently setup for SendGrid and SMTP
services.AddEmailSenders(Configuration);
Expand Down
23 changes: 19 additions & 4 deletions src/Skoruba.IdentityServer4.STS.Identity/appsettings.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,10 @@
"ValidationCertificatePfxFilePassword": "",

"UseValidationCertificateThumbprint": false,
"ValidationCertificateThumbprint": ""
"ValidationCertificateThumbprint": "",

"UseSigningCertificateForAzureKeyVault": false,
"UseValidationCertificateForAzureKeyVault": false
},
"RegisterConfiguration": {
"Enabled": true
Expand Down Expand Up @@ -67,13 +70,25 @@
"BasePath": "",
"IdentityOptions": {
"Password": {
"RequiredLength": 8
"RequiredLength": 8
},
"User": {
"RequireUniqueEmail": true
"RequireUniqueEmail": true
},
"SignIn": {
"RequireConfirmedAccount": false
"RequireConfirmedAccount": false
}
},
"DataProtectionConfiguration": {
"ProtectKeysWithAzureKeyVault": false
},
"AzureKeyVaultConfiguration": {
"AzureKeyVaultEndpoint": "",
"ClientId": "",
"ClientSecret": "",
"UseClientCredentials": true,
"IdentityServerCertificateName": "",
"DataProtectionKeyIdentifier": "",
"ReadConfigurationFromKeyVault": false
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
using System.Diagnostics;

namespace Skoruba.IdentityServer4.Shared.Configuration.Common
{
public class AzureKeyVaultConfiguration
{
public string AzureKeyVaultEndpoint { get; set; }

public string ClientId { get; set; }

public string ClientSecret { get; set; }

public bool UseClientCredentials { get; set; }

public string IdentityServerCertificateName { get; set; }

public string DataProtectionKeyIdentifier { get; set; }

public bool ReadConfigurationFromKeyVault { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
namespace Skoruba.IdentityServer4.STS.Identity.Configuration
namespace Skoruba.IdentityServer4.Shared.Configuration.Common
{
public class CertificateConfiguration
{
Expand Down Expand Up @@ -26,5 +26,9 @@ public class CertificateConfiguration
public string ValidationCertificatePfxFilePath { get; set; }

public string ValidationCertificatePfxFilePassword { get; set; }

public bool UseSigningCertificateForAzureKeyVault { get; set; }

public bool UseValidationCertificateForAzureKeyVault { get; set; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
namespace Skoruba.IdentityServer4.Shared.Configuration.Common
{
public class DataProtectionConfiguration
{
public bool ProtectKeysWithAzureKeyVault { get; set; }
}
}
27 changes: 27 additions & 0 deletions src/Skoruba.IdentityServer4.Shared/Helpers/AzureKeyVaultHelpers.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
// Original file comes from: https://github.com/damienbod/IdentityServer4AspNetCoreIdentityTemplate
// Modified by Jan Škoruba

using System.Security.Cryptography.X509Certificates;
using System.Threading.Tasks;
using Skoruba.IdentityServer4.Shared.Configuration.Common;
using Skoruba.IdentityServer4.Shared.Services;

namespace Skoruba.IdentityServer4.Shared.Helpers
{
public class AzureKeyVaultHelpers
{
public static async Task<(X509Certificate2 ActiveCertificate, X509Certificate2 SecondaryCertificate)> GetCertificates(AzureKeyVaultConfiguration certificateConfiguration)
{
(X509Certificate2 ActiveCertificate, X509Certificate2 SecondaryCertificate) certs = (null, null);

if (!string.IsNullOrEmpty(certificateConfiguration.AzureKeyVaultEndpoint))
{
var keyVaultCertificateService = new AzureKeyVaultService(certificateConfiguration);

certs = await keyVaultCertificateService.GetCertificatesFromKeyVault().ConfigureAwait(false);
}

return certs;
}
}
}
Loading