Three ways to integrate Spring Boot with AWS Secrets Manager
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.