1. 概述

应用和设备使用 SSL 证书来保障连接安全,它们能加密服务器与客户端之间的通信。这些证书都有有效期,到期后必须更换。

手动更换证书既耗时又容易导致服务中断或影响用户体验。本文将介绍如何实现证书的热重载,在 Spring Boot 应用中通过 HashiCorp Vault 动态更新证书。

2. 核心概念

本节将介绍后续内容需要掌握的基础知识。

2.1. SSL 证书

SSL(安全套接层)是一种在 Web 服务器和浏览器间建立加密连接的安全协议。

SSL 证书是用于验证网站或服务器身份的数字证书,能创建加密连接。证书包含颁发机构名称、接收方、公钥、有效期等信息,用于验证网站或服务器的真实性。

后文提到的“证书”均指 SSL 证书。

2.2. X.509 证书

X.509 是定义数字证书的标准之一,也是互联网上最常用的标准。它包含网站/服务器的身份信息和公钥,由证书颁发机构(CA)签名或自签名。

2.3. 根 CA

在 SSL 领域,存在少数被广泛信任的证书颁发机构,称为根 CA(如 GeoTrust、DigiCert)。它们颁发的证书称为根证书。操作系统和浏览器默认信任这些根 CA,用于验证其他证书。这套机制确保用户能安全连接网站并验证其身份。

2.4. 中级 CA

直接暴露根 CA 存在安全风险。为此我们创建中级 CA作为根 CA 与终端证书之间的桥梁。可创建多个中级 CA,每个中级 CA 代表其父级 CA 颁发证书,形成信任链而不暴露根 CA 的私钥。

这种设计通过保护根 CA 的同时,让中级 CA 负责验证和颁发证书,增强了安全性。浏览器和设备依赖此信任链确保安全连接。

2.5. HashiCorp Vault

Vault 是用于安全存储和访问敏感信息(如令牌、密码、密钥、数字证书等)的工具。HashiCorp 公司开发的 Vault 支持密钥存储、轮换、数据加密和证书颁发。

2.6. PKI 密钥引擎

在 HashiCorp Vault 中,我们使用 PKI 密钥引擎生成动态 X.509 证书。通过该引擎,服务无需手动生成私钥和 CSR、提交给 CA 并等待验证签名流程,即可直接获取证书。

2.7. Vault Agent

Vault Agent 是与 Vault 服务器通信的客户端守护进程,负责请求证书颁发。可配置其定期将证书写入指定目录。借助 Vault Agent,我们将实现证书的热重载功能。

至此,我们已掌握 SSL 和 HashiCorp Vault 的基础概念。接下来看这些组件如何协同工作,使 Spring Boot 应用能热重载 Vault 颁发的证书。

简单来说:我们将让应用在证书过期时从配置目录自动重载证书。Vault Agent 作为独立进程,定期请求 Vault 服务器颁发证书并写入目录。

3. 配置 Vault 服务器

使用中级 CA 比根 CA 更安全。本节将设置 Vault 服务器,配置根 CA 和中级 CA。

3.1. 在 Vault 服务器中配置根 CA

vault secrets enable pki
vault secrets tune -max-lease-ttl=87600h pki
vault write -field=certificate pki/root/generate/internal common_name="Root CA" ttl=87600h > root_ca.crt
vault write pki/config/urls issuing_certificates="http://127.0.0.1:8200/v1/pki/ca" crl_distribution_points="http://127.0.0.1:8200/v1/pki/crl"

✅ 以上命令:

  • 启用 PKI 密钥引擎
  • 设置根 CA 有效期为 10 年
  • 生成根证书并保存到 root_ca.crt
  • 配置证书颁发和吊销列表的 URL

3.2. 配置中级 CA

vault secrets enable -path=pki-int pki
vault secrets tune -max-lease-ttl=43800h pki-int
vault write -field=csr pki-int/intermediate/generate/internal common_name="Intermediate CA" ttl=43800h > pki_intermediate.csr
vault write pki/root/sign-intermediate csr=@pki_intermediate.csr format=pem_bundle ttl=43800h > intermediate_bundle.pem
vault write pki-int/intermediate/set-signed certificate=@intermediate_bundle.pem
vault write pki-int/roles/localhost-3 allowed_domains=localhost allow_subdomains=true max_ttl=3h

⚠️ 关键步骤说明:

  1. /pki-int 路径启用 PKI 引擎,设置最大有效期 5 年
  2. 生成中级 CSR 并保存到 pki_intermediate.csr
  3. 用根 CA 签名中级证书
  4. 将签名后的中级证书配置到 Vault
  5. 创建角色 localhost-3,颁发有效期 3 小时的证书

测试中级 CA:

vault write pki-int/issue/localhost-3 common_name="localhost" ttl=1h

此命令将生成 1 小时有效期的证书。手动生成证书太麻烦,接下来用 Vault Agent 自动化。

4. 配置 Vault Agent

4.1. 创建访问策略

创建 policy.hcl 文件:

path "pki-int/issue/localhost-3" {
  capabilities = ["update"]
}

执行命令创建策略:

vault policy write vault-agent-policy policy.hcl

4.2. 启用 AppRole 认证

vault auth enable approle
vault write auth/approle/role/localhost-3 \
  token_policies="vault-agent-policy" \
  secret_id_ttl="24h" \
  token_ttl="1h" \
  token_max_ttl="4h"

保存角色 ID 和密钥:

vault read auth/approle/role/localhost-3/role-id > role-id
vault write -f auth/approle/role/localhost-3/secret-id > secret-id

4.3. 配置证书模板

创建 template.tpl 文件:

{{- with pkiCert "pki-int/issue/localhost-3" "common_name=localhost" "alt_names=localhost" "ttl=5m" -}}
{{ .Cert }}{{ .CA }}{{ .Key }}
{{ .Key | trimSpace | writeToFile "/etc/vault/private_key.key" "" "" "0400" }}
{{ .CA | trimSpace | writeToFile "/etc/vault/ca.pem" "" "" "0644" }}
{{ .Cert | trimSpace | writeToFile "/etc/vault/certificate.crt" "" "" "0644" }}
{{- end -}}

⚠️ 模板功能:

  • 使用 localhost-3 角色生成 5 分钟有效期的证书
  • 将私钥、CA 证书和服务器证书分别写入文件
  • 设置文件权限(私钥仅所有者可读写)

4.4. 配置 Vault Agent

创建 vault_agent.hcl 文件:

pid_file = "/var/run/vault-agent/pidfile.pid"

vault {
  address = "http://127.0.0.1:8200"
}

auto_auth {
  method {
    type = "approle"
    config = {
      role_id_file_path                   = "/etc/vault/role-id"
      secret_id_file_path                 = "/etc/vault/secret-id"
      remove_secret_id_file_after_reading = false
    }
  }
}

template {
  source      = "/etc/vault/template.tpl"
  destination = "/etc/vault/all-certs"
}

启动 Vault Agent:

sudo mkdir -p /var/run/vault-agent
sudo vault agent -config=/etc/vault/vault_agent.hcl

✅ 验证证书生成:

ls -l /etc/vault/
# 应该看到 private_key.key, ca.pem, certificate.crt, all-certs

5. 配置 Spring Boot 应用

5.1. 添加依赖

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-web</artifactId>
    <version>3.4.0</version>
</dependency>
<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-vault-config</artifactId>
    <version>4.2.0</version>
</dependency>

5.2. 配置证书路径

application.properties 中:

server.ssl.key-store=file:/etc/vault/all-certs
server.ssl.key-store-password=
server.ssl.key-store-type=PEM
server.ssl.certificate-file=file:/etc/vault/certificate.crt
server.ssl.certificate-private-key=file:/etc/vault/private_key.key
server.ssl.trust-certificate=file:/etc/vault/ca.pem

⚠️ 关键配置:

  • 使用 PEM 格式证书
  • 指定证书、私钥和 CA 证书路径
  • Spring Boot 会自动检测文件变化并重载证书

5.3. 验证热重载

启动应用后观察日志,每隔 5 分钟应看到类似:

Connector [https-jsse-nio-8080], TLS virtual host [_default_], certificate type [UNDEFINED] configured from keystore [/etc/vault/all-certs] using alias [tomcat] with trust store [null]

✅ 成功标志:

  • 应用启动时自动加载证书
  • 证书更新后无需重启应用
  • 日志显示证书重新加载

6. 总结

本文完成了以下工作:

  1. 介绍了 SSL 和 HashiCorp Vault 的核心概念
  2. 阐述了根 CA 与中级 CA 的区别及重要性
  3. 演示了 Vault 服务器的配置流程:
    • 设置根 CA
    • 配置中级 CA
  4. 详解了 Vault Agent 的配置与使用:
    • 创建访问策略
    • 启用 AppRole 认证
    • 配置证书模板
    • 启动 Agent 进程
  5. 实现了 Spring Boot 应用的证书热重载:
    • 配置证书路径
    • 验证自动重载机制

通过这套方案,我们实现了证书的自动化管理,避免了手动更换的繁琐操作和潜在风险。Vault Agent 定期更新证书文件,Spring Boot 自动检测变化并重载,整个过程对业务透明。


原始标题:Reload SSL Certificates From HashiCorp Vault for Spring Boot | Baeldung