If your application is hosted on AWS, this solution will probably be the simplest. It relies on the SecretConfiguration.AwsKms NuGet package.
Secrets are stored in a separate configuration file in encrypted form. The secrets are then decrypted at runtime using AWS Key Management Service. This way you can version your secrets along with your application's source code, while avoiding storing secrets in clear text.
Concretely, it's a configuration provider that integrates with the Microsoft.Extensions.Configuration
stack.
Here are the steps:
1. Create a KMS key
Use the AWS console or CLI to create a KMS key (symmetric encryption). Make sure your developers have the permission to encrypt but not decrypt, and that only the role used to run your application has decrypt permissions.
2. Encrypt your secrets
Use the AWS CLI to encrypt your secrets. The command to use is the following (replace the key-id
with the key ID of your KMS key):
aws kms encrypt --cli-binary-format raw-in-base64-out --key-id "11111111-0000-0000-0000-000000000000" --plaintext "SECRET_TO_ENCRYPT"
The output will contain the ciphertext:
{
"CiphertextBlob": "AQICAHhDR/VQh6Ap...rfyKsKCG2h6WVK8=",
"KeyId": "arn:aws:kms:eu-west-1:123456789:key/11111111-0000-0000-0000-000000000000",
"EncryptionAlgorithm": "SYMMETRIC_DEFAULT"
}
Repeat this step for all the secrets you have in your application.
3. Create a separate configuration file for secrets
This file looks like a normal configuration file you would have in an ASP.NET Core application, except the string values are encrypted. For example, it may looks like:
{
"Database": {
"Password": "AQICAHhDR/VQh6Ap...rfyKsKCG2h6WVK8="
},
"Redis": {
"Password": "AQICAHhDR/VQh6Ap...47iiHg/XifWcxvQ="
}
}
You can also have one file per environment if you like (e.g. secrets.Staging.json
and secrets.Production.json
).
4. Register the configuration at startup
In your application startup, where configuration sources are configured, add this new configuration source:
string keyId = "arn:aws:kms:eu-west-1:123456789:key/11111111-0000-0000-0000-000000000000";
builder.Configuration.AddAwsKmsEncryptedConfiguration(
new AmazonKeyManagementServiceClient(),
keyId,
encryptedSource => encryptedSource
.SetBasePath(builder.Environment.ContentRootPath)
.AddJsonFile($"secrets.{builder.Environment.EnvironmentName}.json"));
This will have the effect of transparently decrypting the secrets at runtime, and merging the key/value configuration pairs with the rest of the configuration sources already configured.
5. Access your secrets the same way you normally access configuration settings
Now you can use the configuration just like you are used to doing with IConfiguration
:
IConfiguration configuration;
// Comes from your regular configuration file
string databaseLogin = configuration["Database:Login"];
// Comes from the encrypted configuration file
string databasePassword = configuration["Database:Password"];