解决容器类部程序间的https调用,无证书问题

203 阅读2分钟

解决思路,生成一个根证书,然后再用根证书签发具体的域名证书,把根证书导入容器中的授信证书中,把域名证书导入nginx

最终目标

  • 生成一个自签的根证书(Root CA)
  • 根证书签发一个域名证书(如 x.abc.edu.cn
  • 根证书导入 Docker 容器 / 系统 / JDK truststore
  • 让 Java 应用访问该 HTTPS 域名时,不报证书错误

🧱 一、生成 Root CA(根证书)

# 1. 生成 Root 私钥
openssl genrsa -out rootCA.key 2048

# 2. 生成 Root CA 证书(有效期10年)
openssl req -x509 -new -nodes -key rootCA.key -sha256 -days 3650 \
  -out rootCA.crt \
  -subj "/C=CN/ST=Test/L=Test/O=TestOrg/OU=TestUnit/CN=MyCustomRootCA"

📜 二、为目标域名签发证书

你要签发的是 x.abc.edu.cn 的证书:

1. 创建域名私钥

openssl genrsa -out x.abc.edu.cn.key 2048

2. 创建 CSR(证书签名请求)

openssl req -new -key x.abc.edu.cn.key -out x.abc.edu.cn.csr \
  -subj "/C=CN/ST=Test/L=Test/O=MyOrg/CN=x.abc.edu.cn"

3. 创建 SAN 配置(x.abc.edu.cn 的 Subject Alternative Name)

创建文件 san.ext

authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName = @alt_names

[alt_names]
DNS.1 = x.abc.edu.cn

4. 用 Root CA 签发域名证书

openssl x509 -req -in x.abc.edu.cn.csr \
  -CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
  -out x.abc.edu.cn.crt -days 365 -sha256 -extfile san.ext

内联式

openssl x509 -req -in x.abc.edu.cn.csr \
-CA rootCA.crt -CAkey rootCA.key -CAcreateserial \
-out x.abc.edu.cn.crt -days 365 -sha256 \
-extfile <(cat <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=CA:FALSE
keyUsage = digitalSignature, keyEncipherment
subjectAltName=DNS:x.abc.edu.cn
EOF
)

你现在有了:

  • 根证书(rootCA.crt
  • 域名私钥(x.abc.edu.cn.key
  • 域名证书(x.abc.edu.cn.crt

🧪 三、验证证书(可选)

openssl verify -CAfile rootCA.crt x.abc.edu.cn.crt
# 输出应为:x.abc.edu.cn.crt: OK

查看证书

openssl x509 -in x.abc.edu.cn.crt -text -noout

📦 四、导入 Root CA 到容器或系统信任链

🐳 A. 容器(Debian / Ubuntu 系列)

  1. 复制 rootCA.crt 到容器 /usr/local/share/ca-certificates/
docker cp rootCA.crt container_id:/usr/local/share/ca-certificates/myroot.crt
  1. 更新 CA 信任列表:
docker exec container_id update-ca-certificates

或者在 Dockerfile 中写:

COPY rootCA.crt /usr/local/share/ca-certificates/myroot.crt
RUN update-ca-certificates

☕ B. 如果容器内有其它应用,也可采用JDK 的 truststore 导入(容器或宿主)

# 默认 truststore 路径
$JAVA_HOME/jre/lib/security/cacerts

# 导入根证书到 JDK cacerts(密码默认是 changeit)
keytool -import -trustcacerts -keystore $JAVA_HOME/jre/lib/security/cacerts \
  -storepass changeit \
  -alias myrootca \
  -file rootCA.crt

可通过以下命令验证是否成功导入:

keytool -list -keystore $JAVA_HOME/jre/lib/security/cacerts -storepass changeit | grep myrootca

🌐 五、部署 nginx 使用你签发的域名证书

server {
    listen 443 ssl;
    server_name x.abc.edu.cn;

    ssl_certificate     /path/to/x.abc.edu.cn.crt;
    ssl_certificate_key /path/to/x.abc.edu.cn.key;

    location / {
        proxy_pass https://REAL_SERVER;
        proxy_ssl_verify off;
    }
}

然后加一条本地 /etc/hosts(容器内也可):

127.0.0.1 x.abc.edu.cn

✅ 最终效果

  • 你构造了一套自定义的 PKI 系统(Root + Leaf Cert)
  • 用根CA签发了相关域名的证书,构成了证书信任链,最终base容器只需导入根CA并授信,后续用根CA签发的域名,容器都能采用https访问
  • 不修改 Java 源码,访问 https://x.abc.edu.cn 成功通过 TLS 校验
  • 容器或系统内的所有 Java 应用将信任你伪造的证书