Resolving Spring Boot Properties Using the AWS Parameter Store (SSM)

Last Updated:  June 16, 2022 | Published: April 18, 2020

If you are familiar with the AWS services landscape, you might already know the Parameter Store (part of the AWS System Manager, in short, SSM). This service allows us to store parameters for our application as a String, StringList or SecureString (encrypted using KMS keys). We can use this AWS service to configure both plain text properties (e.g., name of a queue) and secrets (e.g., database passwords, OAuth2 credentials, etc.). With this blog post, you'll learn how to configure your Spring Boot application to retrieve configuration properties from the AWS Systems Manager Parameter Store.

UPDATE: The configuration processing slightly changed with Spring Boot 2.4. Take a look at the last section that discusses how to include this functionality for recent Spring Boot versions.

Spring Boot Application Setup

For the demo application, we're using Spring Boot 2.2.6 and Java 11. Besides the spring-boot-starter-web, the application includes two Spring Cloud AWS dependencies:

Configure Credentials to Access the AWS Parameter Store

First, we need to configure proper access from our Spring Boot application to AWS. For this, you'll need to obtain credentials from your AWS account. You can follow the steps mentioned in this blog post to get them.

There are multiple ways to configure credentials for the underlying Amazon Java SDK. As we are using the Spring Cloud AWS Starter, we can specify the AWS access and secret key inside our application.properties or application.yml file using the cloud.aws.credentials namespace.

While this works well for other Spring Cloud AWS components (like SQS, S3, SNS, etc.), we can't use it for the Parameter Store and Secrets Manager configuration.  This is because both rely on the DefaultAWSCredentialsProviderChain by default. There are ways to override this (read the docs for more information), but for the sake of simplicity, we'll use one of the providers of the default AWS provider chain.

The default AWS provider chain looks for the AWS credentials at the following places:

  1. Environment variables (AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY or AWS_ACCESS_KEY and AWS_SECRET_KEY)
  2. Java System Properties (aws.accessKeyId and aws.secretKey)
  3. Credentials profile (default location is (~/.aws/credentials)
  4. Credentials delivered through the Amazon EC2 container service
  5. Instance profile credentials delivered through the Amazon EC2 metadata service

We're going with the first approach and add two environment variables AWS_ACCESS_KEY_ID & AWS_SECRET_ACCESS_KEY to the launch configuration of the Spring Boot application in IntelliJ.

We can also set these variables in our current shell session (from which we start our application) or our whole system.

Setting AWS Credentials in IntelliJ

Resolve AWS Properties Inside Our Spring Boot Application

First, it's important to configure the correct AWS region.

Make sure to use the same region where you created the parameters; otherwise, our Spring application won't find them.

For the demo application, we're using the AWS region eu-central-1 (Frankfurt, Germany) and set the region using the configuration property cloud.aws.region.static inside our application.yml:

Following the default convention, the parameters inside the Parameter Store require a specific naming structure:

We can configure the name of our Spring application inside the application.yml

Given this structure, let's define two parameters as SecretString for the default and production profile inside the AWS Systems Manager:

AWS Systems Manager set parameter

Note: You can omit the profile name for properties targeting the default profile.

Before we can start the application on a local machine, we ensure to disable the automatic stack detection inside the application.yml as we are not starting the application inside an AWS stack (e.g., on EC2):

Given this setup, the spring-cloud-starter-aws-parameter-store-config will now autoconfigure a AwsParameterStorePropertySourceLocator.

This class implements the PropertySourceLocator interface and Spring will use it to locate properties requested by the application e.g. @Value("${my.property}").

For a quick demo, let's request both Parameter Store properties and print them during application startup:

Running the application with the default profile results in the following log output:

… and using the production profile in the following:

Overriding the Default AWS Parameter Store Configuration

If the default parameter convention does not fit our needs, we can override it using a bootstrap.yml or bootstrap.properties file inside src/main/resources.

This allows us to e.g., override the prefix (default is /config), the name of the application (default is Spring application name) and the profile separator between name and application profile (default is _):

Updates For Spring Boot 2.4.0

Starting with version 2.4.0, Spring Boot changed some internals in regards to config file processing. There's a blog post available that discusses the reasoning and changes in detail and also a migration guide.

This change impacts this feature, and from now on, we have to explicitly import the aws-parameterstore as a possible configuration property location:

Summary

Using the Parameter Store of the AWS Systems Manager (SSM), we can easily configure our Spring Boot application thanks to Spring Cloud AWS. With this functionality, we can outsource the configuration of sensitive values to a central place inside AWS.

With the Spring Cloud AWS dependencies, there is almost no further setup required. If you plan to start using it for your application, ensure the following:

  • use one of the default provider chains to configure the AWS credentials (e.g., using environment variables)
  • configure the same AWS region you used to configure the parameters in the AWS console
  • follow the default property naming structure or define your own

You can find the application for this blog post on GitHub.

PS: If your application uses Eclipse MicroProfile, you can achieve something similar by creating a custom ConfigSource using the MicroProfile Config specification.

For more practical hands-on advice on developing Spring Boot applications on AWS, take a look at the Stratospheric project where we develop a real-world application while integrating several AWS services.

Have fun retrieving your Spring Boot application properties using the AWS Parameter Store,

Phil

  • The value mentioned as this @Value(“${spring.datasource.password}”)
    private String dataSourcePassword;

    Comes and populates this attribute with clear text. Is it possible to get the encrypted value and set the encrypted value to this attribute.

  • This is very nice article. Due to some security issues, we are moving from Consul to Paramstore, while migrating this I found that Paramstore is not having @RefreshScope functionality. Please let me know if I am missing any and if not having that out of the box then how can I achieve it? Thank you!

      • Sure, Consul is just like a property holder for application. If we update any property value for that application, then it will reload values without redeploying/rebuilding the application. Please let me know if you need more information on it.

        • I’m not aware of any support for this from Spring Cloud AWS Parameter Store.

          The implementation is also rather simple, as it basically registers another PropertySourceLocator for Spring to retrieve properties. So to have such a refresh feature, you most probably have to implement it on your own.

          Maybe the AWS Parameter Store publishes events whenever a config value changes, to which you can subscribe from your application and refresh the properties.

          • Thank you for letting me know about those options. We did verify having publishing events, but that is to do with CloudWatch. I don’t want to go on that route.

  • Hello, trying to get this to work locally. I’m getting this error when trying to run locally.

    org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'awsParamStorePropertySourceLocator'...
    ...
    Caused by: com.amazonaws.SdkClientException: Unable to find a region via the region provider chain. Must provide an explicit region in the builder or setup environment to supply a region.

    It looks like the auto-configuration is not picking up the region I set. Any insight would be appreciated

  • Hi, thanks for this article.

    Just trying to make the code work but it always gives me this error

    org.springframework.beans.factory.BeanCreationException: Error creating bean with name ‘parameterResolveDemo’: Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder ‘message’ in value “${message}”

    Do I need to set the value or path of the message in application.yml?

    Thanks in Advance.

    • Hey Ryan,

      in this example I’m setting this configuration property inside the AWS Parameter Store (SSM) to demonstrate the parameter injection. The name as to be /config/demo/message.

      For this, to work, you need an AWS account and configure the access as described in the article. If you just want to start the application without the parameters being resolved by the AWS Parameter Store, you can temporarily hard code them inside your application.yml.

      Have a nice day,
      Philip

      • Oh, I see. Noted on this. By the way, I managed to figure out the issue I forgot to change the AWS region in the properties file. Thanks for the Help, Philip.

  • {"email":"Email address invalid","url":"Website address invalid","required":"Required field missing"}
    >