如何在Spring Boot上下文启动前从自定义源(如AWS SSM)加载配置属性?
我之前刚好做过类似的需求——在Spring Boot上下文启动前从自定义源(这里就是AWS SSM Parameter Store)加载敏感配置,彻底避免把数据库密码这类敏感信息明文存在application.yaml或系统环境变量里,下面给你分享两种可行的实现方式,按需选择就行:
方式一:用Spring Cloud AWS自动配置(推荐,省心)
Spring Cloud已经帮我们封装好了SSM Parameter Store的整合逻辑,几步就能搞定:
1. 引入依赖
在你的pom.xml里添加Spring Cloud AWS的参数存储依赖(版本可以根据你的Spring Boot版本调整,比如Spring Boot 2.x对应2.2.x系列):
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-aws-parameter-store-config</artifactId> <version>2.2.6.RELEASE</version> </dependency>
如果是Gradle项目,对应的依赖配置是:
implementation 'org.springframework.cloud:spring-cloud-starter-aws-parameter-store-config:2.2.6.RELEASE'
2. 配置基础信息
创建bootstrap.yaml(注意是bootstrap不是application,因为要在上下文启动前加载),配置SSM的参数前缀和AWS区域:
spring: cloud: aws: parameterstore: prefix: /your-app/config # 你在SSM里给应用参数设置的前缀 region: ap-southeast-1 # 替换成你的AWS区域 enabled: true
比如你在SSM里存了/your-app/config/db.password和/your-app/config/db.username,Spring会自动把这些参数映射成spring.datasource.password和spring.datasource.username(前缀之后的路径对应配置键)。
3. 配置AWS权限
给运行应用的IAM角色(或用户)添加访问SSM的权限,比如写这样的IAM策略:
{ "Version": "2012-10-17", "Statement": [ { "Effect": "Allow", "Action": [ "ssm:GetParameter", "ssm:GetParametersByPath" ], "Resource": "arn:aws:ssm:你的区域:你的账号ID:parameter/your-app/config/*" } ] }
如果你的参数是用KMS加密存储的,还要给这个角色添加KMS的解密权限哦。
方式二:自定义EnvironmentPostProcessor(灵活可控)
如果不想依赖Spring Cloud,或者需要更定制化的读取逻辑,可以自己实现EnvironmentPostProcessor接口——这个接口能让我们在Spring上下文启动前,手动加载自定义源的属性。
1. 实现EnvironmentPostProcessor
写一个处理器类,手动调用AWS SSM SDK读取参数:
import org.springframework.boot.SpringApplication; import org.springframework.boot.env.EnvironmentPostProcessor; import org.springframework.core.env.ConfigurableEnvironment; import org.springframework.core.env.MapPropertySource; import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.services.ssm.SsmClient; import software.amazon.awssdk.services.ssm.model.GetParameterRequest; import software.amazon.awssdk.services.ssm.model.GetParameterResponse; import java.util.HashMap; import java.util.Map; public class SsmEnvPostProcessor implements EnvironmentPostProcessor { // 替换成你在SSM里的参数路径 private static final String DB_USER_PARAM = "/your-app/config/db.username"; private static final String DB_PWD_PARAM = "/your-app/config/db.password"; @Override public void postProcessEnvironment(ConfigurableEnvironment env, SpringApplication app) { // 初始化SSM客户端,用try-with-resources自动关闭 try (SsmClient ssmClient = SsmClient.builder() .region(Region.of("ap-southeast-1")) // 替换成你的AWS区域 .build()) { Map<String, Object> ssmProps = new HashMap<>(); // 读取加密的用户名参数(withDecryption必须设为true,否则拿不到明文) GetParameterResponse userResp = ssmClient.getParameter(GetParameterRequest.builder() .name(DB_USER_PARAM) .withDecryption(true) .build()); ssmProps.put("spring.datasource.username", userResp.parameter().value()); // 读取加密的密码参数 GetParameterResponse pwdResp = ssmClient.getParameter(GetParameterRequest.builder() .name(DB_PWD_PARAM) .withDecryption(true) .build()); ssmProps.put("spring.datasource.password", pwdResp.parameter().value()); // 把加载的属性放到环境最前面,确保优先级高于application.yaml里的配置 env.getPropertySources().addFirst(new MapPropertySource("ssmCustomSource", ssmProps)); } } }
2. 注册处理器
在src/main/resources/META-INF/spring.factories里添加以下内容,告诉Spring Boot要加载这个自定义处理器:
org.springframework.boot.env.EnvironmentPostProcessor=com.yourpackage.SsmEnvPostProcessor
记得把com.yourpackage替换成你实际的包路径。
最后注意事项
- 不管用哪种方式,都建议把SSM里的参数用KMS加密存储,这样即使有人拿到了SSM的访问权限,也需要KMS解密权限才能获取真实值,安全性更高。
- 如果应用是部署在AWS EC2或ECS上,尽量用IAM角色来授予权限,而不是在代码里硬编码AWS密钥,进一步降低泄露风险。
内容的提问来源于stack exchange,提问作者user1552545

