Verschillende Cloud diensten bieden oplossingen om instellingen met gevoelige informatie veilig op te slaan, zoals database connectie strings. Vandaag wil ik laten zien hoe je de Secret Manager van AWS makkelijk kunt implementeren in je .Net applicatie.
Je kunt de code uit dit artikel hier terugvinden.
Inrichten AWS Secrets Manager
Ervan uitgaande dat je al een AWS account tot je beschikking hebt, ga naar in de AWS Console naar:
Secrets Manager -> Secrets -> Store a new secret
Kies voor 'Other type of secret' en je krijgt nu de mogelijkheid om meerdere key-value pairs in te geven. Vanuit het oogpunt van kosten is het goed om zo veel mogelijk informatie in een secret op te slaan, omdat je per secret betaalt.
Voeg nu alle instellingen toe. Het is mogelijk om met geneste objecten te werken. Gebruik in dat geval de dubbele punt om een verdieping aan te geven, bijvoorbeeld:
Klik op de tab 'Plaintext' om te zien hoe het resultaat eruit zal als je de waarde opvraagt uit de Secrets Manager.
Het resultaat is een JSON string met alle keyvalue pairs.
Klik na het invoeren van de instellingen een paar keer op 'Next' en sla de secret op.
Opzetten extensie
We gaan een eigen extensie schrijven waarmee we de configuratie uit de Secrets Manager kunnen ophalen. Microsoft heeft al meerdere extensies voor het toevoegen van JSON bestanden aan de configuratie. De broncode hiervan kun je hier bekijken. We gaan de code van methode AddJsonStream() gebruiken en aanpassen voor onze extensie te schrijven. Het resultaat is als volgt:
public static class ConfigurationBuilderExtensions
{
/// <summary>
/// Adds an <see cref="IConfigurationProvider"/> that reads json configuration from a secret in AWS Secrets Manager.
/// </summary>
/// <param name="builder">The <see cref="IConfigurationBuilder"/> to add to.</param>
/// <param name="secretName">The name of the secret to read keys from.</param>
public static IConfigurationBuilder AddSecretsManager(
this IConfigurationBuilder builder,
string secretName) =>
builder.Add<JsonStreamConfigurationSource>(s => s.Stream = new MemoryStream(Encoding.Default.GetBytes(GetSecretKeysAsJson(secretName))));
#region Private
private static string GetSecretKeysAsJson(string secretName)
{
GetSecretValueRequest request = new GetSecretValueRequest
{
SecretId = secretName
};
using (var client = new AmazonSecretsManagerClient())
{
var response = Task.Run(() => client.GetSecretValueAsync(request)).GetAwaiter().GetResult();
string secretString;
if (response.SecretString != null)
{
secretString = response.SecretString;
}
else
{
var memoryStream = response.SecretBinary;
var reader = new StreamReader(memoryStream);
secretString = Encoding.UTF8.GetString(Convert.FromBase64String(reader.ReadToEnd()));
}
return secretString; // Key-value pairs are returned as plaintext json
}
}
#endregion Private
}
De JSON string met de key-value pairs wordt omgezet in een stream die vervolgens aan de configuratie worden toegevoegd. Dit is hetzelfde resultaat als direct een JSON bestand inlezen. De configuratie wordt alleen bij het opstarten van de applicatie gelezen. Als je wilt dat deze periodiek geladen wordt dan is dat ook mogelijk. Zie hier voor meer informatie (Step 5: Reloading secrets).
Implementeren in de code
Om de extensie in je applicatie te gebruiken kun je de package BD.Extension.Configuration.AWS.SecretsManager installeren vanuit de publieke Nuget repo of je kopieert de code van de extensie naar jouw applicatie.
Vervolgens kun je de extensie als volgt toepassen in de code:
var appConfigSecretName = "data-development";
IConfiguration config = new ConfigurationBuilder()
.AddJsonFile("appsettings.json", optional: false)
.AddSecretsManager(appConfigSecretName)
.Build();
De extensie maakt gebruik van de AWS regio die staat gedefinieerd in jouw AWS credentials bestand in de ontwikkelomgeving, of de regio waar de applicatie rechten voor heeft in een uitgerolde omgeving.