Skip to content

Commit 31ed5ca

Browse files
author
Patrick R. Vecchio
committed
- simplified, clarified, and fixed a code typo
1 parent b78326d commit 31ed5ca

File tree

1 file changed

+12
-8
lines changed

1 file changed

+12
-8
lines changed

README.md

Lines changed: 12 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,11 @@ Custom Configuration Providers is a collection of configuration providers for .N
77

88
### Overview
99

10-
Using this custom configuration provider, you can put AWS Secrets Manager keys into your appsettings files and the values stored in AWS Secrets Manager will be loaded into the config at startup time as if they were in the appsettings file already. What this auto-population of the secret configuration values allow us to do is to leverage the [Options pattern in .Net](https://docs.microsoft.com/en-us/dotnet/core/extensions/options) along with Dependency Injection to automatically load these settings into the classes that need them. In addition, having the settings pre-loaded at startup time means we can eliminate the need to mock an AwsSecretsManager and try to fake the settings at execution time. We can simply use a test version of our appsettings file or in-memory configuration provider with the test values pre-populated and leave AWS Secrets Manager out of our unit tests completely.
10+
Using this custom configuration provider, you can put AWS Secrets Manager keys into your appsettings files and the values stored in AWS Secrets Manager will be loaded into the config at startup time as if they were in the appsettings file already. Using single AWS secrets keys we can selectively load just the secrets our app needs.
1111

12-
So, here are the values in the "/dev/db/options" AWS secret:
12+
By resolving the secret values are startup allows us to do is to leverage the [Options pattern in .Net](https://docs.microsoft.com/en-us/dotnet/core/extensions/options) along with Dependency Injection to automatically load these settings into the classes that need them, meaning our code can be written in a way that it doesn't care where the settings come from. This simplifies our testing because our unit tests can use an in-memory configuration provider with the test values pre-populated leaving them without the need to mock Secrets Manager or make connections from our CI/CD pipeline to a test instance of Secrets Manager.
13+
14+
So, here is an example of some values stored in the "/dev/db/options" key of our AWS Secrets Manager instance:
1315

1416
```json
1517
{
@@ -21,7 +23,7 @@ So, here are the values in the "/dev/db/options" AWS secret:
2123
}
2224
```
2325

24-
Here are the appsettings:
26+
Here are our appsettings:
2527

2628
```json
2729
{
@@ -31,7 +33,7 @@ Here are the appsettings:
3133
}
3234
```
3335

34-
Here is what our IConfiguration values look like before and after we call .AddAwsSecretsManager:
36+
Here is what our IConfiguration values look like before and after we call .AddAwsSecretsManager, specifying "AwsSecret" as our placeholder key:
3537

3638
| IConfiguration before | IConfiguration after |
3739
|---|---|
@@ -43,7 +45,9 @@ Here is what our IConfiguration values look like before and after we call .AddAw
4345

4446
### How it works
4547

46-
Add the provider along with an AwsSecretsManager client (this is to allow for injecting mock versions or other versions of the client) and the name of the placeholder key you chose to put in your appsettings (e.g. "AwsSecret"):
48+
Custom configuration providers work as extension methods for ConfigurationBuilder. As long as the custom provider is included in your source and it's namespace is in your "using" statements, you should be able to just call ".AddAwsSecretsManager(...)".
49+
50+
In your app's startup code, add the provider to your configuration builder along with an AwsSecretsManager client (this is to allow for injecting mock versions or other versions of the client) and the name of the placeholder key you chose to put in your appsettings (e.g. "AwsSecret"):
4751

4852
```csharp
4953
var configurationBuilder = new ConfigurationBuilder();
@@ -61,7 +65,7 @@ Add the provider along with an AwsSecretsManager client (this is to allow for in
6165
> * We're supplying an AmazonSecretsManagerClient to simplify testing and to choose the region in our app startup.
6266
> * In `AddAwsSecretsManager()` we're specifying the placeholder key to search and replace (e.g. "AwsSecret") with AWS Secrets Manager values. You can choose whatever string you want.
6367
64-
When you build the config builder, the custom configuration provider will look in the appsettings files you've loaded for the placeholder key you specified (e.g. "AwsSecret") take it's value "/dev/db/options" and replace the value with the values retrieved from AWS Secrets Manager (i.e. in the IConfiguration tree in memory, not the appsettings file) like so:
68+
When you call "Build" on the config builder, the custom configuration provider will look in the appsettings files you've loaded for the placeholder key you specified (e.g. "AwsSecret") take it's value "/dev/db/options" and replace the value with the values retrieved from AWS Secrets Manager (i.e. in the IConfiguration tree in memory, not the appsettings file) like so:
6569

6670
| IConfiguration before | IConfiguration after |
6771
|---|---|
@@ -90,7 +94,7 @@ public class DatabaseOptions
9094

9195
> Note:
9296
>
93-
> Since AWS Secrets Manager stores key-value pairs as <string,string> options classes should contain strings. It is possible to add code to the Configuration Provider that parses the JSON into proper types, but it complicates the code that I think has more cost than benefit.
97+
> Since AWS Secrets Manager stores key-value pairs as <string,string> options classes should contain strings. It is possible to add code to the Configuration Provider that parses the JSON into proper types, but it complicates the code in a way that I think has more cost than benefit. Simpler to treat them as strings and convert them to the needed types by the classes that consume them.
9498
9599
#### Inject them into a Dependency Injection collection
96100

@@ -144,7 +148,7 @@ public DependencyInjectionMockUnitTests()
144148
{
145149
_configuration.GetSection("Database").Bind(settings);
146150
});
147-
_services.AddScoped<IServiceThatUsesDatabaseOptions, IServiceThatUsesDatabaseOptions>();
151+
_services.AddScoped<IServiceThatUsesDatabaseOptions, ServiceThatUsesDatabaseOptions>();
148152

149153
_serviceProvider = _services.BuildServiceProvider();
150154

0 commit comments

Comments
 (0)