How To Retrieve Secrets From AWS Secrets Manager In .NET 6 Web API

Introduction

In this article, you will learn how to retrieve secrets from AWS Secrets Manager in .NET 6 Web API.

AWS Secrets Manager helps you to store secrets needed to access your applications. Refer this link for more details.

Topics Covered

This article demonstrates how to build the following:

  • Create secrets in Secrets Manager using Console
  • Create a sample ASP.NET Core Web API
  • Testing
  • Clean up resources

Pre-requisites

  1. Download and install Visual Studio 2022.
  2. Download and install AWS Toolkit for Visual Studio 2022.
  3. An Active AWS Account. (See AWS Account Page.)
  4. User with sufficient access to create AWS resources for this article. (See IAM role in AWS IAM Roles Documentation.)
  5. User should have programmatic access keys.(See IAM user and Access in the AWS IAM documentation.)
  6. Download and install Amazon command line interface (AWS CLI). Configure AWS CLI.

Tools

  1. AWS Console
  2. Visual Studio 2022

Task 1 - Create secrets in Secrets Manager using Console/AWS CLI

In this task, you will see how to create sample secrets using Console/CLI.

Step 1

Follow this link to create the secrets using Console/CLI.

Step 2

The following secrets are created for this article.

How to retrieve secrets from AWS Secrets Manager

How to retrieve secrets from AWS Secrets Manager

Task 2 - Create a sample ASP.NET Core Web API

In this task, you will see how to create a new sample .NET 6 ASP.NET Core Web API using Visual Studio 2022.

Step 1

Open Visual Studio 2022, click Create a new project.

Step 2

Search ASP.NET in the search bar, select ASP.NET Core Web API project template and click Next.

Step 3

Enter the project name as AWSSecretsManagerNETAPIDemo. Click Next.

Step 4

Select .NET 6.0 (Long-term support) as Framework. Click Create.

Step 5

Add AWSSDK.SecretsManager and Newtonsoft.Json NuGet package

Step 6

Right click the solution, click Add->Class.

Step 7

Name the class as SecretsManager.cs and click Add.

Step 8

Update the class with following code.

using Amazon;
using Amazon.SecretsManager;
using Amazon.SecretsManager.Model;
namespace AWSSecretsManagerNETAPIDemo {
    public class SecretsManager {
        public static string GetSecret() {
            string secretName = "dev/myapp/config";
            string region = "us-west-2";
            string secret = "";
            MemoryStream memoryStream = new MemoryStream();
            IAmazonSecretsManager client = new AmazonSecretsManagerClient(RegionEndpoint.GetBySystemName(region));
            GetSecretValueRequest request = new GetSecretValueRequest();
            request.SecretId = secretName;
            request.VersionStage = "AWSCURRENT"; // VersionStage defaults to AWSCURRENT if unspecified.
            GetSecretValueResponse response = null;
            // In this sample we only handle the specific exceptions for the 'GetSecretValue' API.
            // See https://docs.aws.amazon.com/secretsmanager/latest/apireference/API_GetSecretValue.html
            // We rethrow the exception by default.
            try {
                response = client.GetSecretValueAsync(request).Result;
            } catch (DecryptionFailureException e) {
                // Secrets Manager can't decrypt the protected secret text using the provided KMS key.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw;
            } catch (InternalServiceErrorException e) {
                // An error occurred on the server side.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw;
            } catch (InvalidParameterException e) {
                // You provided an invalid value for a parameter.
                // Deal with the exception here, and/or rethrow at your discretion
                throw;
            } catch (InvalidRequestException e) {
                // You provided a parameter value that is not valid for the current state of the resource.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw;
            } catch (ResourceNotFoundException e) {
                // We can't find the resource that you asked for.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw;
            } catch (System.AggregateException ae) {
                // More than one of the above exceptions were triggered.
                // Deal with the exception here, and/or rethrow at your discretion.
                throw;
            }
            // Decrypts secret using the associated KMS key.
            // Depending on whether the secret is a string or binary, one of these fields will be populated.
            if (response.SecretString != null) {
                return secret = response.SecretString;
            } else {
                memoryStream = response.SecretBinary;
                StreamReader reader = new StreamReader(memoryStream);
                string decodedBinarySecret = System.Text.Encoding.UTF8.GetString(Convert.FromBase64String(reader.ReadToEnd()));
                return decodedBinarySecret;
            }
            // Your code goes here.
        }
    }
}

Step 9

Add a new class to the solution and name it as ConfigSettings.cs and click Add.

Step 10

Update the class with following code.

using Newtonsoft.Json.Linq;
namespace AWSSecretsManagerNETAPIDemo {
    public class ConfigSettings: IConfigSettings {
        private string _key1;
        private string _key2;
        public ConfigSettings() {
            Init();
        }
        public void Init() {
            var secretValues = JObject.Parse(SecretsManager.GetSecret());
            if (secretValues != null) {
                _key1 = secretValues["key1"].ToString();
                _key2 = secretValues["key2"].ToString();
            }
        }
        public string Key1 {
            get {
                return _key1;
            }
            set {
                _key1 = value;
            }
        }
        public string Key2 {
            get {
                return _key2;
            }
            set {
                _key2 = value;
            }
        }
    }
    public interface IConfigSettings {
        string Key1 {
            get;
            set;
        }
        string Key2 {
            get;
            set;
        }
    }
}

Step 11

Open Program.cs and add the service as shown below.

using AWSSecretsManagerNETAPIDemo;
var builder = WebApplication.CreateBuilder(args);
// Add services to the container.
builder.Services.AddControllers();
// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen();
builder.Services.AddSingleton < IConfigSettings, ConfigSettings > ();
var app = builder.Build();
// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment()) {
    app.UseSwagger();
    app.UseSwaggerUI();
}
app.UseHttpsRedirection();
app.UseAuthorization();
app.MapControllers();
app.Run();

Step 12

Open WeatherForecastController.cs and update the code as shown below.

using Microsoft.AspNetCore.Mvc;
namespace AWSSecretsManagerNETAPIDemo.Controllers {
    [ApiController]
    [Route("[controller]")]
    public class WeatherForecastController: ControllerBase {
        private static readonly string[] Summaries = new [] {
            "Freezing",
            "Bracing",
            "Chilly",
            "Cool",
            "Mild",
            "Warm",
            "Balmy",
            "Hot",
            "Sweltering",
            "Scorching"
        };
        private readonly ILogger < WeatherForecastController > _logger;
        private readonly IConfigSettings _configSettings;
        public WeatherForecastController(ILogger < WeatherForecastController > logger, IConfigSettings configSettings) {
                _logger = logger;
                _configSettings = configSettings;
            }
            [HttpGet(Name = "GetWeatherForecast")]
        public string Get() {
            var result = "key 1 - " + _configSettings.Key1 + " : Key 2 - " + _configSettings.Key2;
            return result;
        }
    }
}

NOTE
Hard-coded values are used only for testing purpose and this should NOT be used in PRODUCTION environment. The values should be retrieved dynamically.

Task 3 - Testing

In this task, you will see how to test the API to retrieve the secrets from AWS Secrets Manager.

Hit F5 to run the API locally and Swagger will be displayed. Expand /WeatherForecast and click Try it out. Click Execute to get the response as shown below.

How to retrieve secrets from AWS Secrets Manager

Task 4 - Clean up resources

Delete all the resources to ensure that you're not charged for any services you aren't using.

Summary

This article describes how to retrieve secrets from AWS Secrets Manager in .NET 6 Web API.