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

Spring Cloud Gateway无法找到有效证书路径的原因及解决方法

Keycloak+Spring Cloud Gateway自签名证书PKIX路径问题排查与解决

问题背景

使用Keycloak对Spring Cloud Gateway做安全保护,Keycloak采用以下命令生成的自签名证书:

openssl genrsa -out ca.key 2048
openssl req -new -x509 -days 365 -key ca.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=Acme Root CA" -out ca.crt
openssl req -newkey rsa:2048 -nodes -keyout server.key -subj "/C=CN/ST=GD/L=SZ/O=Acme, Inc./CN=*my-site.com" -out server.csr
openssl x509 -req -extfile <(printf "subjectAltName=DNS:my-site.com") -days 365 -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt

在Spring Cloud Gateway的Dockerfile中已添加该自签名证书的CA证书:

USER root

# Copy the certificate file into the image
COPY --from=build /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt

# Change the permissions of the /etc/ssl/certs directory
RUN chmod a+w /etc/ssl/certs

# Update the certificate store
RUN update-ca-certificates

但登录输入凭据后,Spring Cloud Gateway抛出以下错误:

Caused by: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.validator.PKIXValidator.doBuild(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.validator.PKIXValidator.engineValidate(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.validator.Validator.validate(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.ssl.X509TrustManagerImpl.validate(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.ssl.X509TrustManagerImpl.checkTrusted(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.ssl.X509TrustManagerImpl.checkServerTrusted(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   ... 30 common frames omitted
core_api-gateway.1.4z2matjvgalf@ws002cfw    | Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.provider.certpath.SunCertPathBuilder.build(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/sun.security.provider.certpath.SunCertPathBuilder.engineBuild(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   at java.base/java.security.cert.CertPathBuilder.build(Unknown Source) ~[na:na]
core_api-gateway.1.4z2matjvgalf@ws002cfw    |   ... 36 common frames omitted

问题原因

  1. Java信任库未同步:update-ca-certificates更新的是系统级证书存储,但Java应用默认使用自身的cacerts信任库,不会自动读取系统证书。
  2. 证书域名不匹配:Keycloak的实际访问域名,未包含在证书的CN或subjectAltName字段中,导致证书身份验证失败。
  3. 证书链配置不完整:Keycloak仅配置了服务器证书,未关联CA根证书,Java无法追溯到可信的根证书节点。

解决方法

方法1:将CA证书导入Java信任库

修改Dockerfile,把CA证书导入Java自带的cacerts文件(注意路径随Java版本调整,示例为OpenJDK 17):

USER root

# 复制CA证书到临时目录
COPY --from=build /app/certs/ca.crt /tmp/ca.crt

# 导入到Java信任库,默认密码为changeit
RUN keytool -importcert -file /tmp/ca.crt -alias acme-root-ca -keystore /usr/local/openjdk-17/lib/security/cacerts -storepass changeit -noprompt

# 可选:更新系统证书存储,适配其他工具
COPY --from=build /app/certs/ca.crt /usr/local/share/ca-certificates/ca.crt
RUN update-ca-certificates

# 恢复非root用户,符合安全规范
USER nonroot

方法2:让Java使用系统证书存储

在Gateway启动参数中添加JVM参数,指定Java读取系统证书:

-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts
-Djavax.net.ssl.trustStorePassword=changeit

也可以在Dockerfile中通过环境变量配置:

ENV JAVA_OPTS="-Djavax.net.ssl.trustStore=/etc/ssl/certs/java/cacerts -Djavax.net.ssl.trustStorePassword=changeit"

方法3:修正证书与Keycloak配置

  • 调整证书域名:如果Keycloak访问域名是keycloak.my-site.com,重新生成证书时修改subjectAltName为DNS:my-site.com,DNS:keycloak.my-site.com。
  • 完善Keycloak证书链:确保Keycloak配置中同时加载server.crt、server.key和ca.crt,让证书链完整可追溯。

方法4:临时跳过证书验证(仅测试环境)

测试阶段可临时关闭证书验证,生产环境绝对禁止:
添加JVM参数:

-Djavax.net.ssl.trustStoreType=JKS
-Dcom.sun.net.ssl.checkRevocation=false
-Djdk.tls.disableEndpointIdentificationAlgorithm=true

或通过Spring配置自定义WebClient跳过验证:

@Bean
public WebClient webClient() {
    HttpClient httpClient = HttpClient.create().secure(sslContextSpec -> sslContextSpec
            .sslContext(SSLContextBuilder.create().loadTrustMaterial((chain, authType) -> true)));
    return WebClient.builder().clientConnector(new ReactorClientHttpConnector(httpClient)).build();
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.09 13:40:27