Today's applications are broken into smaller and smaller pieces. We've been slowly transitioning away from managing our own infrastructure; from using virtual instances to deploying to clusters. Your environment may have one or more clusters. Those clusters have many services. Those services have many tasks. Each task is an application running in its own container. And more than likely, that application requires configuration.
I want to share with you a simple way to store your sensitive configuration and to have your application retrieve it at startup. This solution is appealing because there's no infrastructure to manage, has little maintenance, and scales beautifully. So let's get started.
Storing your configuration
For a contrived example, I'll store a GitHub Token in AWS Parameter Store and make it available to our Spring Boot application.
Pre-reqs
What you need to get started, or most likely, what you already have in place:
- A Spring Boot application
- Deployed on AWS
Store your secrets in AWS Parameter Store
Open up AWS Systems Manager then go to Parameter Store under Application Management.
- Click
Create Parameter
. - In the name field, enter
/config/application/github.token
. - In the description field, enter
GitHub API Token
- Select
SecureString
from the type field. Accept the default KMS key source. - In the text field, enter
ABC123
. - Click
Create Parameter
to save it.
A few things to note, for the type field I could have used a String but instead I chose SecureString to keep the value encrypted at rest. You can do either, and it will be transparently decrypted when it is retrieved. For the name field, the prefix /config/application/
is important but everything else is just made up. I'll go into why the prefix is important in just a bit.
Retrieving Secrets
The "secret" sauce of this solution is in the integration. Now that your configuration is securely stored in AWS, you need a reliable way to retrieve it. A poor way to integrate would be to specifiy each property in the ECS task definition using ValueFrom mappings. That ends up requiring more configuration with more to maintain. Unsurprisingly, there's a great Spring integration that can help us out called Spring Cloud Starter AWS Parameter Store Config.
Add the Spring Boot starter dependency
In your application's pom.xml, add:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-parameter-store-config</artifactId>
</dependency>
Additionally, if Spring Cloud isn't set up in the project yet, add the following to the pom.xml as well:
<project>
...
<properties>
...
<!-- This is the latest version as of the 7/7/2020 -->
<spring-cloud.version>Hoxton.SR6</spring-cloud.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>${spring-cloud.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
</project>
Deploy
That's it! And now, there is some magic happening as is the case with most Spring integrations.
Deploy your application to AWS and Spring Cloud will access the Parameter Store on AWS. Properties are retrieved and injected based on the following prefix conventions:
/config/application/
- applies to all applications/config/application_dev/
- applies to all applications with an activedev
profile/config/my-api/
- applies to only themy-api
application (defined byspring.application.name
in your application properties)/config/my-api_dev/
- applies to only themy-api
application with an activedev
profile
These conventions provide the flexibility to define global, application-specific, and environment-specific parameters. An added benefit is that parameters can be added/changed/removed in AWS Parameter Store and will sync on application restart. There's no middle layers or task definitions to update.
Access the injected property
The github.token
property should now be retrieved at application startup from Parameter Store. The parameter's full key is /config/application/github.token
. The prefix, /config/application
, is omitted and what is left is our application property key. The value, ABC123
, is transparently decrypted and provided to the application at runtime.
Wrapping Up
If this seems simple, it's because it is! Spring Boot's starter packages tend to do a good job out-of-the-box with little to no configuration.
I hope you found this to be easy to follow and beneficial. And remember, keep your secrets out of your source code!