Learn How To Manage Credentials When Building .NET Application on AWS

AWS Security Credentials authenticates and authorizes requests to AWS resources. Managing and keeping them secure throughout application development is essential.

In this post, let’s learn different ways to set up and manage credentials and sensitive information when building .NET applications on AWS. We will also touch upon some of the tools and utilities that I have set up on my local development machine to make working with AWS easier.

Setting Up Yout AWS Account & Users

If you are new to AWS and want to set up a free account to learn and understand how things work, check out the AWS Free Tier. It gives enough free credit across various services to try it out.

The credential you use to set up your AWS account is the root account. As a best practice, do not use this account for any tasks if it’s not required. Create separate Administrator accounts and use those accounts instead.

Creating an Administrator User Group and assigning all users with administrator access to that Group is recommended. It makes managing administrator accounts more manageable and centralized.

Create the User and the Group from the IAM console.

Create administrator accounts and use them instead of the root user account.

Connecting to AWS Services

When building applications that connect with other AWS services, you must authenticate using credentials. Avoid using root or administrator accounts. Create specific user accounts and roles based on your application requirements, and limit the permissions associated with them.

Let’s look at a sample application scenario where the application needs to send a message to a Amazon Simple Queue Service. Let’s go through different ways to manage the credentials required to connect to the SQS service.

Hard-code Credentials

Most of the .NET SDKs support passing in the credentials explicitly. Below I use the BasicAWSCredentials class to pass the Access Key and Secret to the AmazonSQSClient to connect to Amazon SQS.

[HttpPost]
public async Task<string> FunctionHandler(string input, ILambdaContext context)
{
    var credentials = new BasicAWSCredentials("ACCESSKEY", "SECRET");
    var client = new AmazonSQSClient(
                credentials, RegionEndpoint.APSoutheast2);
    var request = new SendMessageRequest()
    {
        MessageBody = JsonSerializer.Serialize(data),
        QueueUrl = "QUEUE_URL"
    };

    var response= await client.SendMessageAsync(request);
    return response.HttpStatusCode.ToString();
}

If you are a seasoned developer, you would already know that hard-coding credential is terrible.

.NET Configuration

The immediate step to avoid hard-coding credentials in the application code is to move it to an application configuration file.

.NET has built-in Configuration support that you can use to remove the credentials from the application code.

Using the IConfiguration instance, we can retrieve configuration values from it using the key for the appropriate config value.

The below code sets up different configuration sources for the configuration. The order is important, as the source coming later in the chain will override any previously existing values in the chain.

It allows us to set and override the configuration value using different sources based on the application’s environment.

var configuration = new ConfigurationBuilder()
            .SetBasePath(Directory.GetCurrentDirectory())
            .AddJsonFile("appsettings.json", false)
            .AddEnvironmentVariables()
            .AddUserSecrets<Function>()
                        .Build();

var accessKey = configuration.GetValue<string>("AccessKey");
var secret = configuration.GetValue<string>("Secret");

Configuration File

For example, you can define the keys in the appsettings.json file and have the application code read from there.

{
  "AccessKey": "ACCESS KEY",
  "Secret": "SECRET"
}

But since the appsettings.json is also a file checked into the source control, we cannot keep the credentials there. However, we can have the values replaced in the configuration file when setting up a build/deploy pipeline for your application.

Secrets Manager

The app settings files are usually stored as part of the source code and available in your git repository. It makes it the wrong place to store any sensitive information.

To avoid committing configuration files with sensitive information into the source code repository, you can use the Secrets Manager Feature available as part of ASP NET.

Secrets Manager is intended for use only in the local development environment.

To add values to Secrets Manager in a local development environment, you can either use the UI (through Visual Studio) or the command-line tool.

Values defined in the Secrets Manager override those in the app settings file (global and environment-specific ones).

https://www.youtube.com/watch?v=PkLLP2tcd28

The below value in secrets.json (part of the Secrets Manager) overrides the ’Secret’ value.

{
  "Secret": "SECRET FROM SECRET MANAGER"
}

Environment Variables

You can also override application configuration by setting values as environment variables. Any key set as an environment variable in the above configuration setup will override both the configuration file and the secrets manager.

Using environment variables is particularly useful for applications deployed to the AWS infrastructure. You can directly set up environment variables values manually or use an automated build/deploy pipeline.

Shared AWS Credentials File

.NET SDKs also support providing the credentials as part of a Shared AWS Credentials File.

Using the credentials file removes the need to explicitly pass in the AccessKey and Secret at an application level. Instead, it’s specified as part of a file stored in a know location. By default, it’s located in the .aws directory within your home directory and is named credentials; that is, ~/.aws/credentials (Linux or macOS) or %USERPROFILE%\.aws\credentials (Windows).

Below is an example of a sample file.

[default]
aws_access_key_id = AKIAIOSFODNN7EXAMPLE
aws_secret_access_key = wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY

You can define different named profiles in the credentials file; however, the default one is named default. When connecting from .NET SDK, you can either specify the profile name to use explicitly, or it picks up the default one automatically. You can also use the AWS_PROFILE environment variable value to override the default profile name.

Managing the profiles can be done with a plain text editor, AWS CLI, AWS Toolkit for the various editors, etc. If you have the AWS CLI installed, use the `aws configure command to set up the profile.

With the profiles setup, the .NET SDK clients no longer require the credentials to be passed in. It will use the FallbackCredentialsFactory to retrieve the credentials from the shared credential file.

    var client = new AmazonSQSClient();

Windows SDK Store

The shared credentials files created in the previous step are plain text files. You can use the SDK Store on Windows machines, an encrypted store that replaces the shared credentials. By default, it’s located in %USERPROFILE%\AppData\Local\AWSToolkit\RegisteredAccounts.json

This file is specific to the computer it’s created in and can’t be copied to other machines.

You can create an encrypted file using the Visual Studio AWS Toolkit using the ‘Add AWS Credentials Profile’ button and selecting ‘.NET Encrypted Store’ as the option.

Windows Only SDK Store allows storing encrypted credentials

Using the credentials from SDK Store is very similar to using one from the Shared Credentials File. You can either have the default one picked up automatically or specify a named profile.

When deployed to AWS Infrastructure, based on the services you are using, you can set up the appropriate IAM roles to connect to other services and ensure the roles have the required access. You can use the AWS Parameter Store or the Secrets Manager to store credentials and keys for external services.

Quickly Integrate AWS Parameter Store from .NET Applications!

Learn how to get started with AWS Parameter Store and use it from a .NET application to store and retrieve configuration data.

I hope this helps you manage the credentials better when connecting and using AWS resources from a .NET Application!

Photo by olieman.eth on Unsplash

Buy Me A Coffee