Skip to content

Commit

Permalink
Update Azure Key Vault Config Provider topic and sample (#3896)
Browse files Browse the repository at this point in the history
* [WIP] Update Azure Key Vault Config Provider topic and sample

@Rick-Anderson @tdykstra Would you mind marking this **WIP** right now.
I'll need to make a few passes on it prior to getting review underway.

cc/ @anurse (partner in crime on this topic), @blowdart, @pakrym,
@olavt, @Coderrob

Fixes #3369

:flame: *HOT!* :flame: updates in this one:
* 2.0 samples added (note that tabs aren't required, because the topic's
examples are the same thus far across 1.x and 2.x). However, the 1.1 and
2.0 samples are linked when mentioning to the reader what they can
download.
* Re-organized the topic a bit to accomodate the two samples.
* Reacted to the feedback in #3369 and the discussion in
#3525.
* Samples are refactored into an example of placing secrets into a
single key vault for different app *versions*, not app names. Using app
names or the environment isn't a security best practice.

Update

Update

Updates

Updates

Update

Updates

Update

Updates

Updates

* Condition the ItemGroup for netcoreapp2.0

* React to feedback

* Update version references and sample folders

Add one

Minor text change

More minor changes

Even better

One more

* Remove dependency statement

* Update net462 deps

* Even better!

* Reverse order for 2.x tab first

* Update 2.0 samples: Only target netcoreapp
  • Loading branch information
guardrex authored and Rick-Anderson committed Aug 23, 2017
1 parent 135b535 commit 70089de
Show file tree
Hide file tree
Showing 35 changed files with 672 additions and 121 deletions.
152 changes: 79 additions & 73 deletions aspnetcore/security/key-vault-configuration.md

Large diffs are not rendered by default.

Binary file not shown.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

This file was deleted.

17 changes: 0 additions & 17 deletions aspnetcore/security/key-vault-configuration/sample/README.md

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
<PropertyGroup>
<TargetFrameworks>net451;netcoreapp1.1</TargetFrameworks>
<OutputType>Exe</OutputType>
<!-- TODO remove rid when https://github.com/dotnet/sdk/issues/396 is resolved -->
<RuntimeIdentifier Condition=" '$(TargetFramework)' == 'net451' ">win7-x64</RuntimeIdentifier>
</PropertyGroup>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ internal static class Markup
<head>
<meta charset=""utf-8"" />
<title>Key Vault Configuration Provider Sample</title>
<style>body{{font-family:sans-serif}}div{{overflow-x:auto}}table{{border-collapse:collapse}}th,td{{padding:8px;border-bottom:1px solid black}}td:nth-child(1),td:nth-child(2){{text-align:center}}th{{background-color:#4CAF50;color:white}}</style>
<style>body{{font-family:sans-serif}}div{{overflow-x:auto}}table{{border-collapse:collapse}}th,td{{padding:8px;border-bottom:1px solid black}}th{{background-color:#4CAF50;color:white}}</style>
</head>
<body>
<h1>Key Vault Configuration Provider Sample</h1>
Expand All @@ -23,19 +23,19 @@ internal static class Markup
</thead>
<tbody>
<tr>
<td>MySecret</td>
<td><b>MySecret</b></td>
<td><code>Configuration[""MySecret""]</code></td>
<td>SecretName</td>
<td><b>SecretName</b></td>
<td><code>Configuration[""SecretName""]</code></td>
<td>{0}</td>
</tr>
<tr>
<td rowSpan=""2"">Section:MySecret</td>
<td rowSpan=""2""><b>Section--MySecret</b></td>
<td><code>Configuration[""Section:MySecret""]</code></td>
<td rowSpan=""2"">Section:SecretName</td>
<td rowSpan=""2""><b>Section--SecretName</b></td>
<td><code>Configuration[""Section:SecretName""]</code></td>
<td>{1}</td>
</tr>
<tr>
<td><code>Configuration.GetSection(""Section"")[""MySecret""]</code></td>
<td><code>Configuration.GetSection(""Section"")[""SecretName""]</code></td>
<td>{2}</td>
</tr>
</tbody>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
# Key Vault Configuration Provider sample application (ASP.NET Core 1.x)

This sample illustrates the use of the Azure Key Vault Configuration Provider for ASP.NET Core 1.x. For the ASP.NET Core 2.x sample, see [Key Vault Configuration Provider sample application (ASP.NET Core 2.x)](https://github.com/aspnet/Docs/tree/master/aspnetcore/security/key-vault-configuration/samples/basic-sample/2.x).

> [!NOTE]
> The configuration provider isn't available for ASP.NET Core 1.0. If you want to implement the configuration provider and the app is an ASP.NET Core 1.0 app, upgrade the app to 1.1 or later first.
For more information on how the sample works, see the [Azure Key Vault configuration provider](xref:security/key-vault-configuration) topic.

## Using the sample
1. Create a key vault and set up Azure Active Directory (Azure AD) for the application following the guidance in [Get started with Azure Key Vault](https://azure.microsoft.com/documentation/articles/key-vault-get-started/).
* Add secrets to the key vault using the [AzureRM Key Vault PowerShell Module](/powershell/module/azurerm.keyvault) available from the [PowerShell Gallery](https://www.powershellgallery.com/packages/AzureRM.KeyVault), the [Azure Key Vault REST API](/rest/api/keyvault/), or the [Azure Portal](https://portal.azure.com/). Secrets are created as either *Manual* or *Certificate* secrets. *Certificate* secrets are certificates for use by apps and services but are not supported by the configuration provider. You should use the *Manual* option to create name-value pair secrets for use with the configuration provider.
* Simple secrets are created as name-value pairs. Azure Key Vault secret names are limited to alphanumeric characters and dashes.
* Hierarchical values (configuration sections) use `--` (two dashes) as a separator in the sample. Colons, which are normally used to delimit a section from a subkey in [ASP.NET Core configuration](xref:fundamentals/configuration), aren't allowed in secret names. Therefore, two dashes are used and swapped for a colon when the secrets are loaded into the app's configuration.
* Create two *Manual* secrets with the following name-value pairs. The first secret is a simple name and value, and the second secret creates a secret value with a section and subkey in the secret name:
* `SecretName`: `secret_value_1`
* `Section--SecretName`: `secret_value_2`
* Register the sample app with Azure Active Directory.
* Authorize the app to access the key vault. When you use the `Set-AzureRmKeyVaultAccessPolicy` PowerShell cmdlet to authorize the app to access the key vault, provide `List` and `Get` access to secrets with `-PermissionsToKeys list,get`.
2. Update the app's *appsettings.json* file with the values of `Vault`, `ClientId`, and `ClientSecret`.
3. Run the sample app, which obtains its configuration values from `IConfigurationRoot` with the same name as the secret name.
* Non-hierarchical values: The value for `SecretName` is obtained with `config["SecretName"]`.
* Hierarchical values (sections): Use `:` (colon) notation or the `GetSection` extension method. Use either of these approaches to obtain the configuration value:
* `config["Section:SecretName"]`
* `config.GetSection("Section")["SecretName"]`
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ public void Configure(IApplicationBuilder app)
app.Run(async context =>
{
var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var document = string.Format(Markup.Text, Configuration["MySecret"], Configuration["Section:MySecret"], Configuration.GetSection("Section")["MySecret"]);
var document = string.Format(Markup.Text, Configuration["SecretName"], Configuration["Section:SecretName"], Configuration.GetSection("Section")["SecretName"]);
context.Response.ContentLength = encoding.GetByteCount(document);
context.Response.ContentType = "text/html";
await context.Response.WriteAsync(document);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,6 @@
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\aspnetcore-stdout" forwardWindowsAuthToken="false" />
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>netcoreapp2.0</TargetFrameworks>
<OutputType>Exe</OutputType>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.All" Version="2.0.0" />
</ItemGroup>

</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
namespace KeyVaultConfigProviderSample
{
internal static class Markup
{
internal const string Text = @"<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""utf-8"" />
<title>Key Vault Configuration Provider Sample</title>
<style>body{{font-family:sans-serif}}div{{overflow-x:auto}}table{{border-collapse:collapse}}th,td{{padding:8px;border-bottom:1px solid black}}th{{background-color:#4CAF50;color:white}}</style>
</head>
<body>
<h1>Key Vault Configuration Provider Sample</h1>
<div>
<table>
<thead>
<tr>
<th>Secret</th>
<th>Name in Key Vault</th>
<th>Obtained from Configuration</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>SecretName</td>
<td><b>SecretName</b></td>
<td><code>Configuration[""SecretName""]</code></td>
<td>{0}</td>
</tr>
<tr>
<td rowSpan=""2"">Section:SecretName</td>
<td rowSpan=""2""><b>Section--SecretName</b></td>
<td><code>Configuration[""Section:SecretName""]</code></td>
<td>{1}</td>
</tr>
<tr>
<td><code>Configuration.GetSection(""Section"")[""SecretName""]</code></td>
<td>{2}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
using Microsoft.AspNetCore;
using Microsoft.AspNetCore.Hosting;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
using System.IO;

namespace KeyVaultConfigProviderSample
{
public static class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}

public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, config) =>
{
#region snippet1
config.SetBasePath(Directory.GetCurrentDirectory())
.AddJsonFile("appsettings.json", optional: false)
.AddEnvironmentVariables();

var builtConfig = config.Build();

config.AddAzureKeyVault(
$"https://{builtConfig["Vault"]}.vault.azure.net/",
builtConfig["ClientId"],
builtConfig["ClientSecret"]);
#endregion
})
.UseStartup<Startup>()
.Build();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Key Vault Configuration Provider sample application (ASP.NET Core 2.x)

This sample illustrates the use of the Azure Key Vault Configuration Provider for ASP.NET Core 2.x. For the ASP.NET Core 1.x sample, see [Key Vault Configuration Provider sample application (ASP.NET Core 1.x)](https://github.com/aspnet/Docs/tree/master/aspnetcore/security/key-vault-configuration/samples/basic-sample/1.x).

For more information on how the sample works, see the [Azure Key Vault configuration provider](xref:security/key-vault-configuration) topic.

## Using the sample
1. Create a key vault and set up Azure Active Directory (Azure AD) for the application following the guidance in [Get started with Azure Key Vault](https://azure.microsoft.com/documentation/articles/key-vault-get-started/).
* Add secrets to the key vault using the [AzureRM Key Vault PowerShell Module](/powershell/module/azurerm.keyvault) available from the [PowerShell Gallery](https://www.powershellgallery.com/packages/AzureRM.KeyVault), the [Azure Key Vault REST API](/rest/api/keyvault/), or the [Azure Portal](https://portal.azure.com/). Secrets are created as either *Manual* or *Certificate* secrets. *Certificate* secrets are certificates for use by apps and services but are not supported by the configuration provider. You should use the *Manual* option to create name-value pair secrets for use with the configuration provider.
* Simple secrets are created as name-value pairs. Azure Key Vault secret names are limited to alphanumeric characters and dashes.
* Hierarchical values (configuration sections) use `--` (two dashes) as a separator in the sample. Colons, which are normally used to delimit a section from a subkey in [ASP.NET Core configuration](xref:fundamentals/configuration), aren't allowed in secret names. Therefore, two dashes are used and swapped for a colon when the secrets are loaded into the app's configuration.
* Create two *Manual* secrets with the following name-value pairs. The first secret is a simple name and value, and the second secret creates a secret value with a section and subkey in the secret name:
* `SecretName`: `secret_value_1`
* `Section--SecretName`: `secret_value_2`
* Register the sample app with Azure Active Directory.
* Authorize the app to access the key vault. When you use the `Set-AzureRmKeyVaultAccessPolicy` PowerShell cmdlet to authorize the app to access the key vault, provide `List` and `Get` access to secrets with `-PermissionsToKeys list,get`.
2. Update the app's *appsettings.json* file with the values of `Vault`, `ClientId`, and `ClientSecret`.
3. Run the sample app, which obtains its configuration values from `IConfigurationRoot` with the same name as the secret name.
* Non-hierarchical values: The value for `SecretName` is obtained with `config["SecretName"]`.
* Hierarchical values (sections): Use `:` (colon) notation or the `GetSection` extension method. Use either of these approaches to obtain the configuration value:
* `config["Section:SecretName"]`
* `config.GetSection("Section")["SecretName"]`
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
using Microsoft.AspNetCore.Builder;
using Microsoft.AspNetCore.Http;
using Microsoft.Azure.KeyVault.Models;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.AzureKeyVault;
using System.Reflection;
using System.Text;

namespace KeyVaultConfigProviderSample
{
public class Startup
{
public Startup(IConfiguration configuration)
{
Configuration = configuration;
}

public IConfiguration Configuration { get; set; }

public void Configure(IApplicationBuilder app)
{
app.Run(async context =>
{
var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: false);
var document = string.Format(Markup.Text, Configuration["SecretName"], Configuration["Section:SecretName"], Configuration.GetSection("Section")["SecretName"]);
context.Response.ContentLength = encoding.GetByteCount(document);
context.Response.ContentType = "text/html";
await context.Response.WriteAsync(document);
});
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"Vault": "Azure Key Vault name (for example: contosovault)",
"ClientId": "Azure Active Directory Application Id (for example: 627e911e-43cc-61d4-992e-12db9c81b413)",
"ClientSecret": "Azure Active Directory Key (for example: g58K3dtg59o1Pa+e59v2Tx829w6VxTB2yv9sv/101di=)"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.webServer>
<handlers>
<add name="aspNetCore" path="*" verb="*" modules="AspNetCoreModule" resourceType="Unspecified" />
</handlers>
<aspNetCore processPath="%LAUNCHER_PATH%" arguments="%LAUNCHER_ARGS%" stdoutLogEnabled="false" stdoutLogFile=".\logs\stdout" />
</system.webServer>
</configuration>
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
namespace KeyVaultConfigProviderSample
{
internal static class Markup
{
internal const string Text = @"<!DOCTYPE html>
<html lang=""en"">
<head>
<meta charset=""utf-8"" />
<title>Key Vault Configuration Provider Sample</title>
<style>body{{font-family:sans-serif}}div{{overflow-x:auto}}table{{border-collapse:collapse}}th,td{{padding:8px;border-bottom:1px solid black}}th{{background-color:#4CAF50;color:white}}</style>
</head>
<body>
<h1>Key Vault Configuration Provider Sample</h1>
<div>
<table>
<thead>
<tr>
<th>Secret</th>
<th>Name in Key Vault</th>
<th>Obtained from Configuration</th>
<th>Value</th>
</tr>
</thead>
<tbody>
<tr>
<td>AppSecret</td>
<td><b>{0}-AppSecret</b></td>
<td><code>Configuration[""AppSecret""]</code></td>
<td>{1}</td>
</tr>
</tbody>
</table>
</div>
</body>
</html>";
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
<Project Sdk="Microsoft.NET.Sdk.Web">

<PropertyGroup>
<TargetFrameworks>net451;netcoreapp1.1</TargetFrameworks>
<OutputType>Exe</OutputType>
<RuntimeIdentifier Condition=" '$(TargetFramework)' == 'net451' ">win7-x64</RuntimeIdentifier>
<Version>5.0.0.0</Version>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.AspNetCore.Server.Kestrel" Version="1.1.0" />
<PackageReference Include="Microsoft.AspNetCore.Server.IISIntegration" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.AzureKeyVault" Version="1.0.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.FileExtensions" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="1.1.0" />
<PackageReference Include="Microsoft.Extensions.Logging.Console" Version="1.1.0" />
</ItemGroup>

<ItemGroup Condition=" '$(TargetFramework)' == 'net451' ">
<Reference Include="System" />
<Reference Include="Microsoft.CSharp" />
</ItemGroup>

</Project>
Loading

0 comments on commit 70089de

Please sign in to comment.