How To Manage ASP.Net Core App Secrets With AWS Parameter Store

How To Manage ASP.Net Core App Secrets With AWS Parameter Store

In my last article, I have talked about how we can make use of AWS environment variables to manage connections strings for databases, in a multi-environment ecosystem. We saw that we can dynamically load the right connection string for the right database, thanks to Elastic Beanstalk environment properties. If you want to know more, just click here.

But in an app, we also need to deal with more critical and sensitive data. We need data that can be encrypted so that it can transit safely across the requests. This can be useful for passwords, license keys, etc ... For security sake, we cannot store those kinds of values in our application code. In an ASP[.]Net Core MVC application, we can use the secrets.json file, but it's just a local file. Then we have an issue when we want to go online. I personally ran into that issue when I needed to store my databases passwords in a secure way that can be accessed over the network. That's where AWS Parameter Store comes to the rescue.

1. AWS Parameter Store briefly

AWS Parameter Store is attached to the AWS Systems Manager service and provides secure storage for secrets management. It can store values as plain text strings or encrypted data. We can then get access to the values in our code safely. You can learn more about AWS Parameter Store in the AWS official documentation here. In this article, we'll learn how to do so in an ASP[.]Net core MVC app. I will store the database user and password in the parameter store, and then get access to it in the code.

2. Create a parameter in the Parameter Store

In the AWS console, search for the Systems Manager service. On the left, choose the "Parameter Store" sub-menu in the "Application Manager" menu. The page displays the list of created parameters. Click on the "Create parameter" button at the top right. The parameter creation page is displayed, as below:

CreateParameter.png

Let's take a close look at some fields:

Name: We need to give our parameter a name. It's can be a simple single name or a path. For example, we can create a parameter named "/database/dbuser". The parameter Store knows how to deal with hierarchy. "database" will be considered as a container and "dbuser" will be the parameter name.

Type: There are 3 possible data types. In our case, we need our data to be encrypted. So the right choice is the SecureString type. The String type will NOT encrypt the data. So we need to be careful when choosing the type, as String is the default selected type.

Value: We specify the value here.

As we can see on the screenshot below, the parameters are successfully created. I've created one for the database user id, and another one for the password.

CreatedParameters.png

Now, let's get the values in our app.

3. Get access to parameter store values in C# code

Our ASP[.]Net Core app needs to get the credentials, in order to make a proper connection to the database. To do this, we need to follow three steps :

  • First of all, we need to install the package Amazon.Extensions.Configuration.SystemsManager, available on nuget.org. It's the .NET configuration extension for the AWS Systems Manager. It exposes an AddSystemsManager extension method on the Configuration builder that helps us to have access to the data in the AWS parameter store.

  • Secondly, let's update the Program class as below :

using Microsoft.AspNetCore.Hosting;

//Do not forget to include the using directive below. 
//It gives access to the AddSystemsManager method.
using Microsoft.Extensions.Configuration;  

using Microsoft.Extensions.Hosting

public class Program
    {
        public static void Main(string[] args)
        {
            CreateHostBuilder(args).Build().Run();
        }

        public static IHostBuilder CreateHostBuilder(string[] args) =>
            Host.CreateDefaultBuilder(args)
            .ConfigureAppConfiguration((context, builder) =>
            {
                builder.AddSystemsManager("/database");
            })
            .ConfigureWebHostDefaults(webBuilder =>
            {
                webBuilder.UseStartup<Startup>();
            });
    }

builder.AddSystemsManager("/database") will connect our app to the "/database" hierarchy we have previously created. We can now retrieve all the values in that "folder".

  • Finally, Let's get the database user id and the password. In the startup.cs file, in the ConfigureServices method, let's do this :
var connectionBuilder = new MySqlConnectionStringBuilder(
                Environment.GetEnvironmentVariable("CONNECTION_STRING"))
            {
                Password = Configuration["dbpassword"],
                UserID = Configuration["dbuser"]
            };

            services.AddDbContext<IntranetDbContext>(options =>
                    options.UseMySql(connectionBuilder.ConnectionString));

Configuration["dbpassword"] will get the "/database/dbpassword" value and Configuration["dbuser"] will get the "/database/dbuser" value. We can then construct a proper connection string and get connected to the database in a safe and secure way. The data is encrypted using the Key Management System (KMS) of AWS. But can we also provide our own encryption key.

I have not talked about pricing in this article but it's important to notice that AWS Systems Manager is free in its standard type. The advanced type costs $0.05 per month per parameter created. Click here to learn more about AWS Systems Manager pricing.

In this article, we saw how we can rely on the AWS Parameter Store to secure our database credentials. this is not the only use case, and you are free to reuse this process for other credentials you may need to store. It will work just fine! I hope this article brings you enough information to start using Systems Manager in your C# Code on AWS. If you have any questions, feel free to leave them below.

Happy coding !

Did you find this article valuable?

Support Daniel Lawson - C# .NET, AWS and More .. by becoming a sponsor. Any amount is appreciated!