K8s TLS Secret配置Postgres:GKE与Cloud SQL Postgres SSL连接异常
我之前也碰到过几乎一模一样的问题——用pgAdmin/DataGrip能正常连,但Spring Boot一启动就报org.postgresql.util.PSQLException: Could not read SSL key file /tls/tls.key。结合你的场景,大概率是这几个细节没处理好,咱们一步步排查:
1. 检查密钥文件的格式是否符合JDBC驱动要求
GCP下载的tls.key有时候会带一些额外注释或者格式差异,PostgreSQL的JDBC驱动对私钥格式要求很严格,必须是PEM格式的RSA私钥——也就是文件开头必须是-----BEGIN RSA PRIVATE KEY-----,结尾是-----END RSA PRIVATE KEY-----,中间是标准Base64编码内容。
你可以在容器里执行命令查看文件内容:
cat /tls/tls.key
如果格式不对(比如缺少头尾标识、有多余换行或乱码),直接复用pgAdmin/DataGrip能正常连接的那个密钥文件就行——工具能连说明它用的文件格式是符合要求的。
2. 确认容器内文件的权限
Spring Boot官方镜像(比如openjdk或spring-boot镜像)默认用非root用户(比如spring用户)运行,如果/tls/tls.key的权限设置得太严格(比如只有root可读),进程就会读不到文件。
先检查权限:
ls -l /tls/
确保tls.key的权限至少是644(所有者可读可写,其他用户可读),如果不是,修改权限:
chmod 644 /tls/tls.key
如果是Docker部署,也可以临时用--user root启动容器测试(不推荐生产环境),确认是不是权限问题。
3. 核对Spring Boot的数据库连接配置
检查你的application.properties或application.yml里的JDBC URL参数是否正确,尤其是SSL相关部分:
properties格式:
spring.datasource.url=jdbc:postgresql://<你的实例IP>:5432/<数据库名>?sslmode=verify-full&sslrootcert=/tls/root.crt&sslcert=/tls/tls.crt&sslkey=/tls/tls.key
yml格式:
spring: datasource: url: jdbc:postgresql://<你的实例IP>:5432/<数据库名>?sslmode=verify-full&sslrootcert=/tls/root.crt&sslcert=/tls/tls.crt&sslkey=/tls/tls.key
注意几个关键点:
sslmode必须设为verify-full(GCP要求的验证级别)- 三个证书/密钥的路径必须和容器内实际路径完全一致
- 如果你的密钥文件设置了密码(GCP默认没有,但如果自行添加了),要额外加上
sslpassword=<你的密码>参数
4. 验证容器内的文件是否存在
有时候是挂载目录的问题——你以为本地文件已经挂载到容器的/tls目录,但实际路径写错了,导致容器里找不到文件。
进入容器查看文件:
docker exec -it <你的容器名> ls /tls/
确认root.crt、tls.crt、tls.key这三个文件都存在,并且大小正常(不是空文件)。
最后一步:测试最小化配置
如果还是不行,可以写一个最简单的Java测试类(用相同的JDBC驱动版本),在容器里运行直接连接数据库,排查是不是Spring Boot的其他配置干扰了SSL连接:
import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; public class PostgresSslTest { public static void main(String[] args) { String url = "jdbc:postgresql://<实例IP>:5432/<数据库名>?sslmode=verify-full&sslrootcert=/tls/root.crt&sslcert=/tls/tls.crt&sslkey=/tls/tls.key"; String user = "<你的用户名>"; String password = "<你的密码>"; try (Connection conn = DriverManager.getConnection(url, user, password)) { System.out.println("连接成功!"); } catch (SQLException e) { e.printStackTrace(); } } }
如果这个测试类能成功连接,那问题大概率出在Spring Boot的自动配置上(比如有没有其他配置覆盖了SSL参数);如果测试类也报错,那还是回到前面的文件格式、权限、路径问题继续排查。
内容的提问来源于stack exchange,提问作者Bill Bensing

