Three ways to integrate Spring Boot with AWS Secrets Manager

Spyros Angelopoulos
XM Global
Published in
5 min readFeb 1, 2023
Photo by Jason Dent on Unsplash

Spring Boot externalized configuration is not a new thing. We love being able to work with the same application in different environments as the magic of Spring combines property files, environment variables, and settings from multiple other sources.

But as much as we love to put everything in our application property files there are some things that simply should not be put there: Database keys, API keys, credentials of any sort, etc. Stuff that should be kept secure and secret.

If you live in the AWS ecosystem the best place to store such information is obviously the AWS Secrets Manager. Its secure & encrypted storage, central audit, IAM integration, and automatic secret rotation make your Spring Boot property files look like post-it notes and keep your DevOps team happy.

Here are three ways to integrate Spring Boot with the AWS Secrets Manager rated in terms of ease of use, flexibility, and… magic!

1. Using the AWS Secrets Manager SDK

The most basic way is to just use the good old Secrets Manager Java SDK. We only need to add the necessary imports in our build.gradle file

 implementation platform('software.amazon.awssdk:bom:2.15.0')
implementation 'software.amazon.awssdk:secretsmanager'

Hint: always use the awssdk:bom when using multiple AWS SDK packages instead of explicit versions for each one. It will make your life easier down the road.

The code to fetch and decrypt the secret is relatively straightforward:

public void fetchSecrets() {

try (SecretsManagerClient secretsManagerClient = SecretsManagerClient.create()) {
GetSecretValueRequest valueRequest = GetSecretValueRequest.builder()
.secretId("secretId")
.build();

GetSecretValueResponse valueResponse = secretsManagerClient.getSecretValue(valueRequest);
String secret = valueResponse.secretString();
logger.debug("Secret: {}", secret);

// Secret processing

} catch (SecretsManagerException e) {
logger.error(e.awsErrorDetails().errorMessage());
System.exit(1);
}
}

If you want you can easily add client side caching for your secrets using the AWS Secrets Manager Java caching client. It hasn’t been updated to use the 2.x AWS SDK yet, but you can use 1.x and 2.x SDKs in the same project.

The downside of this method is that you have to code and orchestrate everything yourself, but this gives you the advantage that you can make it work in every scenario.

Ease of use 😊: 2/5

Flexibility 💪: 5/5

Magic 🔮: 1/5

2. Using Spring Cloud AWS

If you’ve never heard of Spring Cloud before, it’s a suite of opinionated tools that makes building common microservices patterns (eg service registration, load balancing, service-to-service calls) very easy. If you’re running multiple Spring Boot microservices, then Spring Cloud certainly has something to make your life easier.

A core feature of Spring Cloud is distributed and versioned configuration through Spring Cloud Config. This means that your configuration for all your services can live outside your application property files, in a central place and your microservices can also reload upon property changes.

The community-run Spring Cloud AWS project is a way to easily use AWS with the various features that Spring Cloud offers. One such integration is between AWS Secrets Manager and Spring Cloud.

All you need to do is add the starter module into your build.gradle file:

implementation 'io.awspring.cloud:spring-cloud-starter-aws-secrets-manager-config'

Spring Cloud will automatically fetch and decrypt specific secrets from the AWS Secrets Manager and will add the configuration property key-value pairs from inside of them. Essentially it will use the AWS Secrets Manager as your Spring Cloud Config central repo.

So, you can access the properties from an AWS Secret…

…exactly like you would if it was in your local property files:

@Value("${cloud.password.key}")
private String secretValue;

The downside is that it will only fetch specific secrets with specific paths according to the application name, profile, etc. For example, for an application named awesomeApp running with the production profile, the secret with path /secret/awesomeApp_production will be checked (among others). These paths are somewhat configurable but there are specific patterns and rules in the secret’s paths that you have to follow.

This means that if at some point you need to add extra properties, then you have to add them to specific secrets. You cannot, for example, have a secret with database credentials that is in a completely random path.

Ease of use 😊: 4/5

Flexibility 💪: 3/5

Magic 🔮: 4/5

3. Using the AWS Secrets Manager JDBC Library

There’s a big chance that you only want some database credentials securely stored inside the AWS Secrets Manager. In this case, and if your database is SQL, you can use AWS Secrets Manager JDBC Library.

This library wraps the most common JDBC drivers and when it registers JDBC calls, it automatically fetches the credentials from an AWS Secret.

First, add the dependency in the build.gradle file:

implementation group: 'com.amazonaws.secretsmanager', name: 'aws-secretsmanager-jdbc', version: '1.0.10'

Then substitute the JDBC driver with the wrapper from the library, the user property with the AWS Secret id, and the password value will be automatically fetched from that secret.

For example, if the hardcoded application properties were:

database.driverClass=com.mysql.cj.jdbc.Driver
database.user=dbUserName
database.password=secretDbPassword
database.url=jdbc:mysql://dbpath

The new properties will be:

database.driverClass=com.amazonaws.secretsmanager.sql.AWSSecretsManagerMySQLDriver
database.user=appJdbcSecret
#The database.password is not needed anymore.
database.url=jdbc:mysql://dbpath

This will automatically fetch and use the username and password stored in an AWS Secret with the id appJdbcSecret and secret value :

Unfortunately, this can be used only for SQL databases and only for their credentials, but sometimes that’s the only thing needed to store in an AWS Secret.

Ease of use 😊: 5/5

Flexibility 💪: 1/5

Magic 🔮: 5/5

Summary

Storing your confidential properties inside your application property files is just a recipe for disaster. A much better place for them is the AWS Secrets Manager. The Spring Boot framework gives us multiple ways of integrating with the AWS Secrets Manager depending on the developer’s and the app’s needs.

Here at XM / Trading.com we are building leading Forex platforms and we love writing about it. If you want to learn more about developing on AWS with cloud native technologies make sure to follow us @XM Global for our future articles.

--

--

Spyros Angelopoulos
XM Global

Senior Developer @ XM.com / Trading.com. Most of the times I write code. Sometimes I write about writing code.