NetEscapades.Configuration
Additional configuration providers to use with ASP.NET Core Microsoft.Extensions.Configuration
.
YAML configuration provider
A YAML configuration provider that uses YamlDotNet to load and parse your YAML files.
Installing
Install using the NetEscapades.Configuration.Yaml NuGet package:
PM> Install-Package NetEscapades.Configuration.Yaml
Usage
When you install the package, it should be added to your csproj file. Alternatively, you can add it directly by adding:
<PackageReference Include="NetEscapades.Configuration.Yaml" Version="3.0.0" />
To load a YAML file as part of your config, just load it as part of your normal ConfigurationBuilder
setup in the Program
class of your ASP.NET Core app.
The simplest possible usage that loads a single YAML file called appsettings.yml
would be:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.AddYamlFile("appsettings.yml", optional: false);
})
.UseStartup<Startup>()
.Build();
}
A more complete Program
class that loads multiple files (overwriting config values) might look more like the following:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((context, builder) =>
{
var env = context.HostingEnvironment;
builder
.AddYamlFile("appsettings.yml", optional: false)
.AddJsonFile("appsettings.json", optional: true, reloadOnChange: true)
.AddJsonFile($"appsettings.{env.EnvironmentName}.json", optional: true);
})
.UseStartup<Startup>()
.Build();
}
There is a demo Web API project in the test folder of the GitHub project at https://github.com/andrewlock/NetEscapades.Configuration/tree/master/sample/WebDemoProject2_0
Troubleshooting
One thing to be aware of is that the YAML specification is case sensitive, so the following file is valid and has 3 distinct keys:
test: Value1
Test: Value2
TEST: Value3
However, the Microsoft.Extensions.Configuration
library is case insensitive. Attempting to load the provided file would throw an exception on attempting to load, complaining of a duplicate key.
Remote configuration provider
A Remote configuration provider that loads configuration from a remote endpoint.
Installing
Install using the NetEscapades.Configuration.Remote NuGet package:
PM> Install-Package NetEscapades.Configuration.Remote
Usage
When you install the package, it should be added to your csproj. Alternatively, you can add it directly by adding:
<PackageReference Include="NetEscapades.Configuration.Remote" Version="2.0.0" />
To load a file from a remote configuration source as part of your config, just load it as part of your normal ConfigurationBuilder
setup in the Program
class of your ASP.NET Core app.
The simplest possible usage that loads a single json file from a remote source http://localhost:5000
would be:
public class Program
{
public static void Main(string[] args)
{
BuildWebHost(args).Run();
}
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration(builder =>
{
builder.AddRemoteSource(new Uri("http://localhost"), optional: false);
})
.UseStartup<Startup>()
.Build();
}
Additional configuration
There are a number of properties available for configuration on the RemoteConfigurationSource
which allow customising the call to the remote endpoint:
ConfigurationKeyPrefix
- All Keys loaded from the source will be prefixed with this key"prefix"
and"prefix:123"
are valid prefixes, so a key loaded as<"key", "value">
will be added to the configuration as<"prefix:123:key", <value>"
.MediaType
- the media type that the remote source will send, by default"application/json"
Parser
- anIConfigurationParser
that will be used to parse the response. AJsonConfigurationParser
is included which is taken from the Microsoft.Extensions.Configuration.Json pacakge source code.
The Events
object provides hooks before sending the request using OnSendingRequest
and after the data has been processed using OnDataParsed
.
If the remote source does not return a success response, it will throw an exception, unless you set the Optional
flag to true.
HashiCorp Vault configuration provider
A configuration provider that loads configuration from an instance of HashiCorp Vault.
Installing
Install using the NetEscapades.Configuration.Vault NuGet package:
PM> Install-Package NetEscapades.Configuration.Vault
Usage
When you install the package, it should be added to your csproj. Alternatively, you can add it directly by adding:
<PackageReference Include="NetEscapades.Configuration.Vault" Version="0.9.0" />
You can load secrets from a Vault instance as part of your configuration build. You can use any supported authentication method supported by VaultSharp
, which is used under the hood, but an extension method exists for using AppRole
specifically.
In ASP.NET Core 2.0, add the provider as part of ConfigureAppConfiguration
in Program.cs:
public static IWebHost BuildWebHost(string[] args) =>
WebHost.CreateDefaultBuilder(args)
.ConfigureAppConfiguration((ctx, builder)=>
{
// build the initial config
var builtConfig = builder.Build();
builder.AddVaultWithAppRole(
builtConfig["VaultUri"], //The Vault uri with port
builtConfig["RoleId"], // The role_id for the app
builtConfig["SecretId"], // The secret_iId for the app
builtConfig["SecretPath"] // secret paths to load
);
})
.UseStartup<Startup>()
.Build();
To load a secret from Vault, configure the VaultConfigurationSource
as part of your normal ConfigurationBuilder
setup in the Program
class of your ASP.NET Core app. The approach to configure the builder is similar to the approach required for the Azure Key Vault provider, in which you partially build configuration to obtain the secret values like role_id
and secret_id
.
As well as the Vault URI and authentication info, you must provide the paths for secrets to load. For secrets using v2 of the KV secret store, these should include the data
path segment:
"/secret/myapp/secret1", // secret/myapp/secret1 using v1 of secret store, mounted at secret
"/secret/data/myapp/secret2", // secret/myapp/secret2 using v2 of secret store, mounted at secret
"/secret_v1/myapp/secret3", // secret_v1/myapp/secret3 using v1 of secret store, mounted at secret_v1
VaultSharp currently supports HashiCorp Vault 0.6.4, but due to the limited required APIs, it can work with many different versions.
To load a secret from Vault, configure the VaultConfigurationSource
as part of your normal ConfigurationBuilder
setup in the Program
class of your ASP.NET Core app. The approach to configure the builder is similar to the approach required for the Azure Key Vault provider.
Configure Vault to run the sample
The VaultSample sample app demonstrates how to use the Vault configuration provider. However, you wil also need to configure vault.
The following guide describes how to run Vault in dev mode, create the test secret, add an AppRole
and configure the required secrets:
- Start the server in dev mode:
vault server -dev -dev-root-token-id="root"
Verify the status
set VAULT_ADDR=http://127.0.0.1:8200
vault status
- Create a secret that we'll retrieve in the sample
vault kv put secret/sampleapp/thesecret foo=world excited=yes testlocation=thevalue
- Enable approle auth method
vault auth enable approle
- Create a policy giving access to the secrets required by the sample app
Either loading from an .hcl file (in the project root):
vault policy write sampleapp sampleapp-pol.hcl
or
cat sampleapp-pol.hcl | vault policy write sampleapp -
or using HEREDOC in bash:
vault policy write sampleapp -<<'EOF'
# Login with AppRole
path "auth/approle/login" {
capabilities = [ "create", "read" ]
}
# Read test data (v2)
path "secret/data/sampleapp/*" {
capabilities = [ "read" ]
}
# Read test data (v1)
path "secret_v1/sampleapp/*" {
capabilities = [ "read" ]
}
EOF
Note if you are using version 2 of the kv secrets (the default in Vault 0.10.0+), you need to provide permisions to the
secret/data/*
path, rather than justsecret/data
. You will also need to pass this location in theUseVault
extension method.
- Create a new role, sampleapp-role and attach the policy
vault write auth/approle/role/sampleapp-role policies="sampleapp"
- Get the RoleId for the role
vault read auth/approle/role/sampleapp-role/role-id
This will generate a UUID:
Key Value
--- -----
role_id 5b391a7a-8a09-5dd6-f76c-a34d65736f1f
- Generate a new Secret ID for the role
vault write -f auth/approle/role/sampleapp-role/secret-id
This will generate a SecretId and a SecretID Accessor:
Key Value
--- -----
secret_id 3a80eab2-ae81-40e9-072d-853a5af6b2b2
secret_id_accessor 4d0fe8b2-b1ab-6464-0026-d8700efd085b
- Make the RoleId and SecretId available to the app as configuration values. You should inject these into your app in a secure way, for example using environment variables