Configuration parameters not correctly loaded from AWS Parameter Store when profile-specific config files are present
Type: Bug
Component: Parameter Store
Describe the bug
My Spring Boot application uses Spring Cloud AWS to access AWS Parameter Store. The following versions are used:
- Spring Boot 3.4.6
- Spring Cloud 2024.0.1
- Spring Cloud AWS 3.3.1
The application has 2 configuration files:
application.ymlfor basic configurationapplication-aws.ymlfor profile-specific configuration for a profile named "aws"
At runtime, the environment variable SPRING_PROFILES_ACTIVE is set to the value "aws".
The file application.yml contains a general parameter named foo:
spring.config.import:
- optional:aws-parameterstore:/myapplication
foo: Foo
The file application-aws.yml contains an additional parameter named foo-aws:
foo-aws: Foo-AWS
At runtime, both parameters are supposed to be overwritten with new values from AWS Parameter Store :
/myapplication/foo:=Foo-ParameterStore/myapplication/foo-aws:=Foo-AWS-ParameterStore
However, at runtime, the application still sees the original values from the 2 static configuration files. Neither of the values defined in AWS Parameter Store is injected.
Moreover, the behaviour seems to depend on the location of the spring.config.import setting shown above:
- If the
spring.config.importis configured only inapplication.yml(as shown above), then the behaviour is as described. - If the
spring.config.importis configured both inapplication.ymland inapplication-aws.yml, then the behaviour is also as described. - However, if the
spring.config.importis only inapplication-aws.yml(but not inapplication.yml), then the parameterfoo-aws(originating fromapplication-aws.yml) is overwritten with the value from AWS parameter store, butfoo(originating fromapplication.yml) is still not overwritten.
Expected behaviour
It should be possible to overwrite parameters from all (general or profile-specific) configuration files with values from AWS Parameter Store.
Additional information
This issue is probably related to #1224, but provides some additional information regarding the location of spring.config.import.
Hey @mrnst ,
What you are seeing is actually correct way of determining properties since file is loaded first and has priority over spring.config.import meaning any value in application.yaml has priority over things that is imported.
Link to Spring Boot Docs
Config data files are considered in the following order:
[Application properties](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files) packaged inside your jar (application.properties and YAML variants).
[Profile-specific application properties](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files.profile-specific) packaged inside your jar (application-{profile}.properties and YAML variants).
[Application properties](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files) outside of your packaged jar (application.properties and YAML variants).
[Profile-specific application properties](https://docs.spring.io/spring-boot/reference/features/external-config.html#features.external-config.files.profile-specific) outside of your packaged jar (application-{profile}.properties and YAML variants).
As you can see our parameter store values are under 3 and 4. Outside packaged jar meaning application.properties which are in resources take higher priority. Hope this helped to explain it.
There is good explanation by Phillip Webb about loading and describes how ConfigResources are built in a tree structure and loaded. This also describes why profile loading is not changing value of application.yaml -> Issue
Thanks @MatejNedic, your explanation was helpful to understand how the location of the spring.config.import statement influences the resulting configuration.
But I'm still not convinced that the import from AWS Parameter Store works correctly.
My updated application setup is now as follows:
application.yml is:
foo: foo_from_application.yml
application-aws.yml is:
spring.config.import:
- optional:aws-parameterstore:/myapplication
foo: foo_from_application-aws.yml
foo-aws: foo-aws_from_application-aws.yml
At runtime, the environment variable SPRING_PROFILES_ACTIVE is set to the value "aws".
The configuration values stored in AWS Parameter Store are:
/myapplication/foo:=foo_from_ParameterStore/myapplication/foo-aws:=foo-aws_from_ParameterStore
When I run my application with this setup (and using @Value to inject configured values), my observation is:
- The value of
foo-awsis:foo-aws_from_ParameterStore(as in AWS Parameter Store) - The value of
foois:foo_from_application-aws.yml(as inapplication-aws.yml)
The observed value of foo is not what I would expect from this description of how importing external config files works: Values from the imported dev.properties will take precedence over the file that triggered the import.
I cross-checked: If in application-aws.yml, additional configuration is imported from a file instead, using e.g.
spring.config.import:
- optional:file:/path/to/config.yml
then my application sees the values in /path/to/config.yml, as I would expect.
Hey @mrnst ,
Sorry on late reply. Spring Docs are worded little bit weird and I have not worded any better sorry.
When I run my application with this setup (and using @Value to inject configured values), my observation is:
The value of foo-aws is: foo-aws_from_ParameterStore (as in AWS Parameter Store) The value of foo is: foo_from_application-aws.yml (as in application-aws.yml)
It is other way around right? foo-was: is foo_from_application-aws.yml and foo is foo-aws_from_ParameterStore
If you mean that than yes. When loading we are not taking profile into account meaning we are loading of following in your example:
/myapplication/*
Now if we you have /myapplication/foo and /myapplication/foo-aws We will load it and save as foo-aws: value foo: otherValue
foo-aws won't be resolved to foo and should be activated on profile AWS. I am not sure if you meant that so please correct me!
If you check Spring Docs when importing something with spring.config.import it should take priority over anything.
I have tried locally with 3.3.1 version and so far I am seeing exact that behaviour. Even for profile spring.config.import loaded parameter take priority. I have used @ConfigurationProperties for this and simple GetMapping.
Would you be so kind to provide me sample please so I check it out? Since I cannot reproduce it.
Hello @MatejNedic,
you can find the requested sample in this repository.
I run this application in AWS ECS with the following parameter values in AWS Parameter Store:
| Parameter Name | Value |
|---|---|
/mrnst/playground/foo |
foo_from_ParameterStore |
/mrnst/playground/foo-aws |
foo-aws_from_ParameterStore |
The profile "aws" is activated.
The application produces the following output:
. ____ _ __ _ _
/\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
\\/ ___)| |_)| | | | | || (_| | ) ) ) )
' |____| .__|_| |_|_| |_\__, | / / / /
=========|_|==============|___/=/_/_/_/
:: Spring Boot :: (v3.4.6)
2025-06-17T10:19:59.382+02:00 INFO 1 --- [ main] mrnst.playground.PlaygroundApplication : Starting PlaygroundApplication v1.0-SNAPSHOT using Java 21.0.7 with PID 1 (/application/BOOT-INF/classes started by root in /application)
2025-06-17T10:19:59.481+02:00 INFO 1 --- [ main] mrnst.playground.PlaygroundApplication : The following 1 profile is active: "aws"
2025-06-17T10:20:00.281+02:00 INFO 1 --- [ main] .a.c.a.c.p.ParameterStorePropertySources : Loading property from AWS Parameter Store with name: /mrnst/playground, optional: true
2025-06-17T10:20:00.282+02:00 DEBUG 1 --- [ main] i.a.c.p.ParameterStorePropertySource : Populating property retrieved from AWS Parameter Store: .foo
2025-06-17T10:20:00.282+02:00 DEBUG 1 --- [ main] i.a.c.p.ParameterStorePropertySource : Populating property retrieved from AWS Parameter Store: .foo-aws
2025-06-17T10:20:17.091+02:00 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat initialized with port 8080 (http)
2025-06-17T10:20:17.282+02:00 INFO 1 --- [ main] o.apache.catalina.core.StandardService : Starting service [Tomcat]
2025-06-17T10:20:17.283+02:00 INFO 1 --- [ main] o.apache.catalina.core.StandardEngine : Starting Servlet engine: [Apache Tomcat/10.1.41]
2025-06-17T10:20:17.593+02:00 INFO 1 --- [ main] o.a.c.c.C.[.[.[/mrnst/playground/api] : Initializing Spring embedded WebApplicationContext
2025-06-17T10:20:17.676+02:00 INFO 1 --- [ main] w.s.c.ServletWebServerApplicationContext : Root WebApplicationContext: initialization completed in 17390 ms
2025-06-17T10:20:25.278+02:00 INFO 1 --- [ main] o.s.b.a.e.web.EndpointLinksResolver : Exposing 1 endpoint beneath base path '/actuator'
2025-06-17T10:20:27.384+02:00 INFO 1 --- [ main] o.s.b.w.embedded.tomcat.TomcatWebServer : Tomcat started on port 8080 (http) with context path '/mrnst/playground/api'
2025-06-17T10:20:27.582+02:00 INFO 1 --- [ main] mrnst.playground.PlaygroundApplication : Started PlaygroundApplication in 66.796 seconds (process running for 72.597)
2025-06-17T10:20:30.011+02:00 INFO 1 --- [ scheduling-1] mrnst.playground.ScheduledService : Starting scheduled task
2025-06-17T10:20:30.011+02:00 INFO 1 --- [ scheduling-1] mrnst.playground.ScheduledService : foo : foo_from_application-aws.yml
2025-06-17T10:20:30.015+02:00 INFO 1 --- [ scheduling-1] mrnst.playground.ScheduledService : foo-aws : foo-aws_from_ParameterStore
2025-06-17T10:20:30.015+02:00 INFO 1 --- [ scheduling-1] mrnst.playground.ScheduledService : Scheduled task finished
The output shows that both properties foo and foo-aws are retrieved from AWS parameter store. Therefore, I would expect the property foo to have the value foo_from_ParameterStore.
I hope this helps to reproduce.
Hey @mrnst ,
Thanks so much on sample and sorry on late reply again I was not available.
When loading in your yaml you are missing / on then end since currently your variables are stored with a .foo
You can see this in logs as well.
spring.config.import:
- optional:aws-parameterstore:/mrnst/playground
To fix your problem simply add slash at the end. This will load by the path since we are loading by the path and it ends with a / ->
spring.config.import:
- optional:aws-parameterstore:/mrnst/playground/
Thank you @MatejNedic. I was able to solve my configuration problem with your explanations in this thread.
I'm aware that everything you explained is already contained in the documentation. But maybe a little hint on significance of the trailing "/" in spring.config.import statement for AWS Parameter Store would be helpful to address uncareful readers like me.
This issue can be closed.
Happy to help!
I will leave this issue opened. We can add in logs warning about trailing slash.