# 一、背景

V8 入口NGINX 配置为HTTPS,采用自签名 Root CA 证书,Java 容器中的 Chromium(JVPuppeteer)访问页面时会出现如下异常:

com.ruiyun.jvppeteer.exception.NavigateException:
net::ERR_CERT_AUTHORITY_INVALID

原因:

  • Chromium 不信任服务器证书
  • JVM 默认也不信任内部 Root CA
  • 需要同时导入 Linux 系统证书库JVM cacerts

研发在代码中其实可以配置类似skip-verify证书的相关操作,但是目前多数服务并没有进行配置。因此现场还是需要利用一些手段进行绕过。后续是具体如果自签证书并信任证书的一个操作过程。

# 二、生成证书

#!/bin/bash
set -e

mkdir -p certs
cd certs

echo "========== 1. 生成 Root CA 私钥 =========="
openssl genrsa -out rootCA.key 4096

cat > root-ca.cnf <<EOF
[req]
distinguished_name=req_distinguished_name
x509_extensions=v3_ca
prompt=no

[req_distinguished_name]
C=CN
ST=Beijing
L=Beijing
O=Internal
OU=IT
CN=Internal Root CA

[v3_ca]
basicConstraints=critical,CA:true
keyUsage=critical,keyCertSign,cRLSign
subjectKeyIdentifier=hash
authorityKeyIdentifier=keyid:always
EOF

echo "========== 2. 生成 Root CA =========="

openssl req \
-x509 \
-new \
-nodes \
-key rootCA.key \
-sha256 \
-days 3650 \
-config root-ca.cnf \
-out rootCA.crt

echo "========== 3. 生成 Server 私钥 =========="

openssl genrsa -out server.key 2048

cat > server.cnf <<EOF
[req]
distinguished_name=req_distinguished_name
req_extensions=req_ext
prompt=no

[req_distinguished_name]
C=CN
ST=Beijing
L=Beijing
O=Internal
OU=IT
CN=10.12.43.166   # 根据实际情况调整

[req_ext]
subjectAltName=@alt_names

[alt_names]
IP.1=10.12.43.166  # 根据实际情况调整
IP.2=10.12.43.98  # 根据实际情况调整
IP.3=10.12.43.120  # 根据实际情况调整
IP.4=192.168.11.14  # 根据实际情况调整
IP.5=192.168.11.30  # 根据实际情况调整
IP.6=172.18.32.188  # 根据实际情况调整
EOF

echo "========== 4. 生成 CSR =========="

openssl req \
-new \
-key server.key \
-config server.cnf \
-out server.csr

cat > server-ext.cnf <<EOF
authorityKeyIdentifier=keyid,issuer
basicConstraints=critical,CA:false
keyUsage=critical,digitalSignature,keyEncipherment
extendedKeyUsage=serverAuth
subjectAltName=@alt_names

[alt_names]
IP.1=10.12.43.166  # 根据实际情况调整
IP.2=10.12.43.98  # 根据实际情况调整
IP.3=10.12.43.120  # 根据实际情况调整
IP.4=192.168.11.14  # 根据实际情况调整
IP.5=192.168.11.30 # 根据实际情况调整
IP.6=172.18.32.188 # 根据实际情况调整
EOF

echo "========== 5. Root CA 签发 Server =========="

openssl x509 \
-req \
-in server.csr \
-CA rootCA.crt \
-CAkey rootCA.key \
-CAcreateserial \
-out server.crt \
-days 3650 \
-sha256 \
-extfile server-ext.cnf

echo
echo "========== 完成 =========="
echo
echo "生成文件:"
echo "rootCA.crt"
echo "rootCA.key"
echo "server.crt"
echo "server.key"

echo
echo "验证 Root CA:"
openssl x509 -in rootCA.crt -text -noout | grep -A4 "Basic Constraints"

echo
echo "验证 Server:"
openssl x509 -in server.crt -text -noout | grep -A10 "X509v3 extensions"

执行生成脚本:

chmod +x gen-certs.sh
./gen-certs.sh

生成如下文件:

rootCA.crt      # Root CA 根证书
rootCA.key      # Root CA 私钥(请妥善保管)
server.crt      # 服务端证书
server.key      # 服务端私钥

Nginx(或 synginx)配置:

ssl_certificate     server.crt;
ssl_certificate_key server.key;

注意

服务端必须使用 server.crt,不要直接使用 rootCA.crt


# 三、Kubernetes 启动时自动导入 Root CA

在 Deployment 的 commandargs 中增加如下命令:

# 我是把证书放到了公共桶里,一定要放在java启动命令之前
wget http://<MinioIP>/seeyon-public/rootCA.crt \
    -O /etc/pki/ca-trust/source/anchors/rootCA.crt \
&& update-ca-trust extract \
&& keytool \
    -importcert \
    -noprompt \
    -trustcacerts \
    -alias internal-root \
    -file /etc/pki/ca-trust/source/anchors/rootCA.crt \
    -keystore /apps/jdk/jre/lib/security/cacerts \
    -storepass changeit

作用:

  1. 下载 Root CA
  2. 导入 Linux 系统证书
  3. 导入 JVM cacerts

# 四、手动导入 Root CA(调试使用)

# 1、导入 Linux 系统证书

复制证书:

cp rootCA.crt /etc/pki/ca-trust/source/anchors/

刷新系统证书:

update-ca-trust extract

# 2、导入 JVM

# Java 8

keytool \
-importcert \
-noprompt \
-trustcacerts \
-alias internal-root \
-file /etc/pki/ca-trust/source/anchors/rootCA.crt \
-keystore /apps/jdk/jre/lib/security/cacerts \
-storepass changeit

# Java 11+

keytool \
-importcert \
-noprompt \
-trustcacerts \
-alias internal-root \
-file /etc/pki/ca-trust/source/anchors/rootCA.crt \
-keystore $JAVA_HOME/lib/security/cacerts \
-storepass changeit

# 五、验证

# 1、验证系统证书

trust list | grep -A3 "Internal Root CA"

应看到:

label: Internal Root CA
trust: anchor

# 2、验证 JVM

keytool -list \
-keystore /apps/jdk/jre/lib/security/cacerts \
-storepass changeit | grep internal-root

应输出:

internal-root

# 3、验证 HTTPS

curl https://10.12.43.166

如果返回页面(例如 302 跳转),说明系统已经信任 Root CA。


# 六、注意事项

  1. rootCA.key 为 Root CA 私钥,仅用于签发服务器证书,严禁部署到业务服务器或容器中
  2. 服务端仅部署 server.crtserver.key
  3. 所有客户端(Linux、Java、Windows 等)只需导入 rootCA.crt 即可建立信任关系。
  4. 如果服务端证书续期或重新签发,只要仍由该 Root CA 签发,客户端无需重新导入 Root CA。
  5. 如果业务使用的是 Java + Chromium(JVPuppeteer),建议同时导入 Linux 系统证书JVM cacerts,避免 Java 网络请求与 Chromium 页面访问出现不同的证书信任行为。
编撰人:zhenxy