Spring Boot多应用用Azure Key Vault时数据源凭据异常问题
已成功配置一个Spring Boot应用(应用1)使用Azure Key Vault获取数据库用户名和密码。现在配置另一个连接同一数据库地址但不同schema的同类应用(应用2),在同一Key Vault中存储了带"APP2"后缀的凭据密钥,但该应用仍使用应用1的SPRING-DATASOURCE-USERNAME和SPRING-DATASOURCE-PASSWORD凭据连接到应用1的数据库。删除APP2后缀的密钥后,应用2仍能正常运行;删除应用1的密钥后,两个应用均因凭据错误启动失败。请问是否存在Spring Boot/JPA默认优先使用无后缀密钥的逻辑?
应用配置
应用1配置
spring: datasource: url: <datasource url> type: com.zaxxer.hikari.HikariDataSource username: "${SPRING-DATASOURCE-USERNAME}" password: "${SPRING-DATASOURCE-PASSWORD}" cloud: azure: keyvault: secret: property-sources[0]: credential: managed-identity-enabled: true endpoint: <key vault url>
应用2配置
spring: datasource: url: <datasource url> type: com.zaxxer.hikari.HikariDataSource username: "${SPRING-DATASOURCE-USERNAME-APP2}" password: "${SPRING-DATASOURCE-PASSWORD-APP2}" cloud: azure: keyvault: secret: property-sources[0]: credential: managed-identity-enabled: true endpoint: <key vault url>
问题分析与解答
不存在Spring Boot/JPA默认优先使用无后缀密钥的逻辑,问题根源在于Azure Key Vault密钥的标准化处理规则和Spring配置属性的加载优先级:
Azure Key Vault的密钥标准化:Spring Cloud Azure Key Vault默认会将密钥名称转换为符合Spring配置规范的格式——大写转小写,短横线/下划线替换为点。例如:
- 密钥
SPRING-DATASOURCE-USERNAME会被转换为配置属性spring.datasource.username - 密钥
SPRING-DATASOURCE-USERNAME-APP2会被转换为配置属性spring.datasource.username.app2
- 密钥
占位符解析不匹配:应用2配置中使用的
${SPRING-DATASOURCE-USERNAME-APP2}是按照环境变量格式编写的,但标准化后的密钥并未生成对应格式的环境变量(正确的环境变量格式应为SPRING_DATASOURCE_USERNAME_APP2),导致占位符无法匹配到目标密钥。配置属性的 fallback 逻辑:由于应用2连接的是同一Key Vault,应用1的密钥
SPRING-DATASOURCE-USERNAME会被加载为spring.datasource.username属性并存在于应用2的环境中。当应用2的占位符解析失败时,Spring Boot的数据源自动配置会直接使用已存在的spring.datasource.username属性值,最终导致应用2使用了应用1的凭据。
解决方法
- 调整密钥命名格式:将Key Vault中的APP2后缀密钥改为下划线分隔的格式(如
SPRING_DATASOURCE_USERNAME_APP2),同时将应用2配置中的占位符改为${SPRING_DATASOURCE_USERNAME_APP2}。 - 使用标准化后的配置属性:应用2配置中直接使用Spring配置属性格式的占位符,如
username: "${spring.datasource.username.app2}"。 - 关闭密钥标准化:在应用2的配置中添加
spring.cloud.azure.keyvault.secret.normalize=false,让Key Vault密钥原样作为环境变量加载,此时配置中的${SPRING-DATASOURCE-USERNAME-APP2}可正常匹配。
内容的提问来源于stack exchange,提问作者itsDeepak

