KeyVault HostingStartup (#114)
This commit is contained in:
parent
5f164857fa
commit
9a0064285d
|
|
@ -0,0 +1,6 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System.Runtime.CompilerServices;
|
||||
|
||||
[assembly: InternalsVisibleTo("Microsoft.AspNetCore.AzureAppServicesIntegration.Tests, PublicKey=0024000004800000940000000602000000240000525341310004000001000100f33a29044fa9d740c9b3213a93e57c84b472c84e0b8a0e1ae48e67a9f8f6de9d5f7f3d52ac23e48ac51801f1dc950abe901da34d2a9e3baadb141a17c77ef3c565dd5ee5054b91cf63bb3c6ab83f72ab3aafe93d0fc3c2348b764fafb0b1c0733de51459aeab46580384bf9d74c4e28164b7cde247f891ba07891c9d872ad2bb")]
|
||||
|
|
@ -5,9 +5,6 @@ using Microsoft.AspNetCore.Hosting;
|
|||
|
||||
[assembly: HostingStartup(typeof(Microsoft.AspNetCore.AzureAppServices.HostingStartup.AzureAppServicesHostingStartup))]
|
||||
|
||||
// To be able to build as <OutputType>Exe</OutputType>
|
||||
internal class Program { public static void Main() { } }
|
||||
|
||||
namespace Microsoft.AspNetCore.AzureAppServices.HostingStartup
|
||||
{
|
||||
/// <summary>
|
||||
|
|
@ -15,13 +12,21 @@ namespace Microsoft.AspNetCore.AzureAppServices.HostingStartup
|
|||
/// </summary>
|
||||
public class AzureAppServicesHostingStartup : IHostingStartup
|
||||
{
|
||||
private const string HostingStartupName = "AppServices";
|
||||
private const string DiagnosticsFeatureName = "DiagnosticsEnabled";
|
||||
|
||||
/// <summary>
|
||||
/// Calls UseAzureAppServices
|
||||
/// </summary>
|
||||
/// <param name="builder"></param>
|
||||
public void Configure(IWebHostBuilder builder)
|
||||
{
|
||||
builder.UseAzureAppServices();
|
||||
var baseConfiguration = HostingStartupConfigurationExtensions.GetBaseConfiguration();
|
||||
|
||||
if (baseConfiguration.IsEnabled(HostingStartupName, DiagnosticsFeatureName))
|
||||
{
|
||||
builder.UseAzureAppServices();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
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.DependencyInjection;
|
||||
|
||||
[assembly: HostingStartup(typeof(Microsoft.AspNetCore.AzureKeyVault.HostingStartup.AzureKeyVaultHostingStartup))]
|
||||
|
||||
namespace Microsoft.AspNetCore.AzureKeyVault.HostingStartup
|
||||
{
|
||||
/// <summary>
|
||||
/// A dynamic KeyVault lightup experience
|
||||
/// </summary>
|
||||
public class AzureKeyVaultHostingStartup : IHostingStartup
|
||||
{
|
||||
private const string HostingStartupName = "KeyVault";
|
||||
private const string ConfigurationFeatureName = "ConfigurationEnabled";
|
||||
private const string ConfigurationVaultName = "ConfigurationVault";
|
||||
private const string DataProtectionFeatureName = "DataProtectionEnabled";
|
||||
private const string DataProtectionKeyName = "DataProtectionKey";
|
||||
|
||||
/// <inheritdoc />
|
||||
public void Configure(IWebHostBuilder builder)
|
||||
{
|
||||
var azureServiceTokenProvider = new AzureServiceTokenProvider();
|
||||
var authenticationCallback = new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback);
|
||||
var keyVaultClient = new KeyVaultClient(authenticationCallback);
|
||||
|
||||
var baseConfiguration = HostingStartupConfigurationExtensions.GetBaseConfiguration();
|
||||
|
||||
builder.ConfigureServices((context, collection) =>
|
||||
{
|
||||
var configuration = new ConfigurationBuilder()
|
||||
.AddConfiguration(baseConfiguration)
|
||||
.AddConfiguration(context.Configuration)
|
||||
.Build();
|
||||
|
||||
if (configuration.IsEnabled(HostingStartupName, DataProtectionFeatureName) &&
|
||||
configuration.TryGetOption(HostingStartupName, DataProtectionKeyName, out var protectionKey))
|
||||
{
|
||||
AddDataProtection(collection, keyVaultClient, protectionKey);
|
||||
}
|
||||
});
|
||||
|
||||
if (baseConfiguration.IsEnabled(HostingStartupName, ConfigurationFeatureName) &&
|
||||
baseConfiguration.TryGetOption(HostingStartupName, ConfigurationVaultName, out var vault))
|
||||
{
|
||||
builder.ConfigureAppConfiguration((context, configurationBuilder) =>
|
||||
{
|
||||
AddConfiguration(configurationBuilder, keyVaultClient, vault);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
internal virtual void AddDataProtection(IServiceCollection serviceCollection, KeyVaultClient client, string protectionKey)
|
||||
{
|
||||
serviceCollection.AddDataProtection().ProtectKeysWithAzureKeyVault(client, protectionKey);
|
||||
}
|
||||
|
||||
internal virtual void AddConfiguration(IConfigurationBuilder configurationBuilder, KeyVaultClient client, string keyVault)
|
||||
{
|
||||
configurationBuilder.AddAzureKeyVault(keyVault, client, new DefaultKeyVaultSecretManager());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using Microsoft.Extensions.Configuration;
|
||||
|
||||
namespace Microsoft.AspNetCore.Hosting
|
||||
{
|
||||
internal static class HostingStartupConfigurationExtensions
|
||||
{
|
||||
public static IConfiguration GetBaseConfiguration()
|
||||
{
|
||||
return new ConfigurationBuilder()
|
||||
.AddEnvironmentVariables(prefix: "ASPNETCORE_")
|
||||
.Build();
|
||||
}
|
||||
public static bool IsEnabled(this IConfiguration configuration, string hostingStartupName, string featureName)
|
||||
{
|
||||
if (configuration.TryGetOption(hostingStartupName, featureName, out var value))
|
||||
{
|
||||
value = value.ToLowerInvariant();
|
||||
return value != "false" && value != "0";
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public static bool TryGetOption(this IConfiguration configuration, string hostingStartupName, string featureName, out string value)
|
||||
{
|
||||
value = configuration[$"HostingStartup:{hostingStartupName}:{featureName}"];
|
||||
return !string.IsNullOrEmpty(value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -17,4 +17,12 @@
|
|||
<ProjectReference Include="..\Microsoft.AspNetCore.AzureAppServicesIntegration\Microsoft.AspNetCore.AzureAppServicesIntegration.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.EnvironmentVariables" />
|
||||
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.DataProtection.AzureKeyVault" />
|
||||
<PackageReference Include="Microsoft.AspNetCore.Identity.Service.AzureKeyVault" />
|
||||
<PackageReference Include="Microsoft.Azure.Services.AppAuthentication" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<Description>This extension enables additional functionality for ASP.NET Core on Azure WebSites, such as enabling Azure logging.</Description>
|
||||
<TargetFramework>net461</TargetFramework>
|
||||
<GenerateDocumentationFile>false</GenerateDocumentationFile>
|
||||
<PackageTags>aspnet;logging;aspnetcore;AzureSiteExtension</PackageTags>
|
||||
<PackageTags>aspnet;logging;aspnetcore;AzureSiteExtension;keyvault;configuration;dataprotection</PackageTags>
|
||||
<PackageType>AzureSiteExtension</PackageType>
|
||||
<IncludeBuildOutput>false</IncludeBuildOutput>
|
||||
<ContentTargetFolders>content</ContentTargetFolders>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,144 @@
|
|||
// Copyright (c) .NET Foundation. All rights reserved.
|
||||
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Microsoft.Azure.KeyVault;
|
||||
using Microsoft.Extensions.Configuration;
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Xunit;
|
||||
|
||||
namespace Microsoft.AspNetCore.AzureKeyVault.HostingStartup.Tests
|
||||
{
|
||||
public class HostinStartupTests
|
||||
{
|
||||
[Fact]
|
||||
public void Configure_AddsDataProtection()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__DataProtectionEnabled", null);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__DataProtectionKey", "http://vault");
|
||||
|
||||
var callbackCalled = false;
|
||||
var builder = new WebHostBuilder().Configure(app => { });
|
||||
var mockHostingStartup = new MockAzureKeyVaultHostingStartup(
|
||||
(collection, client, key) =>
|
||||
{
|
||||
callbackCalled = true;
|
||||
Assert.NotNull(collection);
|
||||
Assert.NotNull(client);
|
||||
Assert.Equal("http://vault", key);
|
||||
},
|
||||
(configurationBuilder, client, vault) => {}
|
||||
);
|
||||
|
||||
mockHostingStartup.Configure(builder);
|
||||
var _ = new TestServer(builder);
|
||||
|
||||
Assert.True(callbackCalled);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0")]
|
||||
[InlineData("FALSE")]
|
||||
[InlineData("false")]
|
||||
public void Configure_SkipsAddsDataProtection_IfDisabled(string value)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__DataProtectionEnabled", value);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__DataProtectionKey", "http://vault");
|
||||
|
||||
var callbackCalled = false;
|
||||
var builder = new WebHostBuilder().Configure(app => { });
|
||||
var mockHostingStartup = new MockAzureKeyVaultHostingStartup(
|
||||
(collection, client, key) =>
|
||||
{
|
||||
callbackCalled = true;
|
||||
},
|
||||
(configurationBuilder, client, vault) => {}
|
||||
);
|
||||
|
||||
mockHostingStartup.Configure(builder);
|
||||
var _ = new TestServer(builder);
|
||||
|
||||
Assert.False(callbackCalled);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Configure_AddsConfiguration()
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__ConfigurationEnabled", null);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__ConfigurationVault", "http://vault");
|
||||
|
||||
var callbackCalled = false;
|
||||
var builder = new WebHostBuilder().Configure(app => { });
|
||||
|
||||
var mockHostingStartup = new MockAzureKeyVaultHostingStartup(
|
||||
(collection, client, key) => { },
|
||||
(configurationBuilder, client, vault) =>
|
||||
{
|
||||
callbackCalled = true;
|
||||
Assert.NotNull(configurationBuilder);
|
||||
Assert.NotNull(client);
|
||||
Assert.Equal("http://vault", vault);
|
||||
}
|
||||
);
|
||||
|
||||
mockHostingStartup.Configure(builder);
|
||||
var _ = new TestServer(builder);
|
||||
|
||||
Assert.True(callbackCalled);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData("0")]
|
||||
[InlineData("FALSE")]
|
||||
[InlineData("false")]
|
||||
public void Configure_SkipsConfiguration_IfDisabled(string value)
|
||||
{
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__ConfigurationEnabled", value);
|
||||
Environment.SetEnvironmentVariable("ASPNETCORE_HostingStartup__KeyVault__ConfigurationVault", "http://vault");
|
||||
|
||||
var callbackCalled = false;
|
||||
var builder = new WebHostBuilder().Configure(app => { });
|
||||
|
||||
var mockHostingStartup = new MockAzureKeyVaultHostingStartup(
|
||||
(collection, client, key) => { },
|
||||
(configurationBuilder, client, vault) =>
|
||||
{
|
||||
callbackCalled = true;
|
||||
}
|
||||
);
|
||||
|
||||
mockHostingStartup.Configure(builder);
|
||||
var _ = new TestServer(builder);
|
||||
|
||||
Assert.False(callbackCalled);
|
||||
}
|
||||
|
||||
private class MockAzureKeyVaultHostingStartup : AzureKeyVaultHostingStartup
|
||||
{
|
||||
private readonly Action<IServiceCollection, KeyVaultClient, string> _dataProtectionCallback;
|
||||
|
||||
private readonly Action<IConfigurationBuilder, KeyVaultClient, string> _configurationCallback;
|
||||
|
||||
public MockAzureKeyVaultHostingStartup(
|
||||
Action<IServiceCollection, KeyVaultClient, string> dataProtectionCallback,
|
||||
Action<IConfigurationBuilder, KeyVaultClient, string> configurationCallback)
|
||||
{
|
||||
_dataProtectionCallback = dataProtectionCallback;
|
||||
_configurationCallback = configurationCallback;
|
||||
}
|
||||
|
||||
internal override void AddDataProtection(IServiceCollection serviceCollection, KeyVaultClient client, string protectionKey)
|
||||
{
|
||||
_dataProtectionCallback(serviceCollection, client, protectionKey);
|
||||
}
|
||||
|
||||
internal override void AddConfiguration(IConfigurationBuilder configurationBuilder, KeyVaultClient client, string keyVault)
|
||||
{
|
||||
_configurationCallback(configurationBuilder, client, keyVault);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -7,6 +7,7 @@
|
|||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.AzureAppServicesIntegration\Microsoft.AspNetCore.AzureAppServicesIntegration.csproj" />
|
||||
<ProjectReference Include="..\..\src\Microsoft.AspNetCore.AzureAppServices.HostingStartup\Microsoft.AspNetCore.AzureAppServices.HostingStartup.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
<ItemGroup>
|
||||
|
|
|
|||
Loading…
Reference in New Issue