You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Boot Cloud Config无法解析Google Secret Manager令牌问题排查

问题

我运行着一个基于Spring Boot 2.6.10的Web应用,采用外部配置方案。配置服务器需要安全验证,凭证存储在Google Cloud Secret Manager中。但application.yml里Spring Cloud Config配置段的sm://标识无法被识别,配置段外的属性却能正常解析Secret Manager令牌。输入明文凭证时,配置可正常加载。想问是不是缺少依赖或者需要升级Spring Boot/Spring Cloud版本?

相关配置文件

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>io.my</groupId>
    <artifactId>smtest</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>Secret Manager Test</name>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.6.10</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>2021.0.3</spring-cloud.version>
        <spring-cloud-gcp.version>3.3.0</spring-cloud.version>
    </properties>

    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-config</artifactId>
        </dependency>
        <dependency>
            <groupId>com.google.cloud</groupId>
            <artifactId>spring-cloud-gcp-starter-secretmanager</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-configuration-processor</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <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>
            <dependency>
                <groupId>com.google.cloud</groupId>
                <artifactId>spring-cloud-gcp-dependencies</artifactId>
                <version>${spring-cloud-gcp.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.6.10</version>
            </plugin>
        </plugins>
    </build>
</project>

application.yml

io:
  my:
    data:
      # 这些令牌可以正常解析
      user: "${sm://my-gcp-project/my-data-user/latest}"
      password: "${sm://my-gcp-project/my-data-password/latest}"
spring:
  application:
    name: smtest
  cloud:
    config:
      uri: https://my-external-config.io
      # 这些令牌无法解析
      username: "${sm://my-gcp-project/ext-config-user/latest}"
      password: "${sm://my-gcp-project/ext-config-password/latest}"
  config:
    import: "configserver:"

原因与解决办法

核心原因

Spring Cloud Config客户端的配置加载优先级高于Spring Cloud GCP Secret Manager的属性解析器,导致spring.cloud.config.username、spring.cloud.config.password这类核心配置在Secret Manager解析器生效前就被读取,因此无法识别sm://标识。

方案1:通过环境变量/启动参数传递凭证

将Config服务器的凭证通过环境变量或JVM启动参数传入,这类参数会在更早的阶段被解析:

  • 环境变量方式:
    export SPRING_CLOUD_CONFIG_USERNAME=$(gcloud secrets versions access latest --secret="ext-config-user")
    export SPRING_CLOUD_CONFIG_PASSWORD=$(gcloud secrets versions access latest --secret="ext-config-password")
    
  • JVM参数方式:
    java -jar smtest-0.0.1-SNAPSHOT.jar \
      --spring.cloud.config.username=${sm://my-gcp-project/ext-config-user/latest} \
      --spring.cloud.config.password=${sm://my-gcp-project/ext-config-password/latest}
    

方案2:升级Spring Cloud版本

当前使用的Spring Cloud版本是2021.0.3(Jubilee),升级到2021.0.4及以上版本,新版本优化了配置加载顺序,让Secret Manager解析器能够优先处理Config客户端的凭证配置。

方案3:自定义配置初始化器

创建一个配置初始化器,手动从Secret Manager获取凭证并注入到Spring Cloud Config属性中:

import com.google.cloud.spring.secretmanager.SecretManagerTemplate;
import org.springframework.boot.context.event.ApplicationEnvironmentPreparedEvent;
import org.springframework.context.ApplicationListener;
import org.springframework.core.env.ConfigurableEnvironment;

public class ConfigServerCredentialsInitializer implements ApplicationListener<ApplicationEnvironmentPreparedEvent> {

    private final SecretManagerTemplate secretManagerTemplate;

    public ConfigServerCredentialsInitializer(SecretManagerTemplate secretManagerTemplate) {
        this.secretManagerTemplate = secretManagerTemplate;
    }

    @Override
    public void onApplicationEvent(ApplicationEnvironmentPreparedEvent event) {
        ConfigurableEnvironment environment = event.getEnvironment();
        // 从Secret Manager获取凭证
        String configUser = secretManagerTemplate.getSecretString("my-gcp-project/ext-config-user/latest");
        String configPassword = secretManagerTemplate.getSecretString("my-gcp-project/ext-config-password/latest");
        
        // 将凭证设置到系统属性中,供Spring Cloud Config读取
        environment.getSystemProperties().put("spring.cloud.config.username", configUser);
        environment.getSystemProperties().put("spring.cloud.config.password", configPassword);
    }
}

在启动类中注册这个初始化器:

import com.google.cloud.spring.secretmanager.SecretManagerTemplate;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SmtestApplication {

    public static void main(String[] args) {
        SpringApplication app = new SpringApplication(SmtestApplication.class);
        app.addListeners(new ConfigServerCredentialsInitializer(new SecretManagerTemplate()));
        app.run(args);
    }
}

内容的提问来源于stack exchange,提问作者MiseryMachine

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.24 14:06:20