SSL
Spring Boot 提供了配置 SSL 信任材料的能力,这些材料可以应用于多种类型的连接,以支持安全通信。可以使用前缀为 spring.ssl.bundle 的配置属性来指定命名的信任材料集及其相关信息。
使用 Java KeyStore 文件配置 SSL
可以使用前缀为 spring.ssl.bundle.jks 的配置属性来配置通过 Java keytool 工具创建并以 JKS 或 PKCS12 格式存储在 Java KeyStore 文件中的信任材料包。每个包都有一个用户提供的名称,可用于引用该包。
当用于保护嵌入式 Web 服务器时,keystore 通常会配置一个包含证书和私钥的 Java KeyStore,如下例所示:
- Properties
- YAML
spring.ssl.bundle.jks.mybundle.key.alias=application
spring.ssl.bundle.jks.mybundle.keystore.location=classpath:application.p12
spring.ssl.bundle.jks.mybundle.keystore.password=secret
spring.ssl.bundle.jks.mybundle.keystore.type=PKCS12
spring:
ssl:
bundle:
jks:
mybundle:
key:
alias: "application"
keystore:
location: "classpath:application.p12"
password: "secret"
type: "PKCS12"
当用于保护客户端连接时,truststore 通常会配置一个包含服务器证书的 Java KeyStore,如下例所示:
- Properties
- YAML
spring.ssl.bundle.jks.mybundle.truststore.location=classpath:server.p12
spring.ssl.bundle.jks.mybundle.truststore.password=secret
spring:
ssl:
bundle:
jks:
mybundle:
truststore:
location: "classpath:server.p12"
password: "secret"
可以提供文件的 Base64 编码内容,而非文件的位置。如果选择此选项,则属性值应以 base64: 开头。
完整的支持属性集请参见 JksSslBundleProperties。
如果你使用环境变量来配置 bundle,bundle 的名称会始终转换为小写。
使用 PEM 编码的证书配置 SSL
可以使用前缀为 spring.ssl.bundle.pem 的配置属性来配置以 PEM 编码文本形式表示的信任材料包。每个包都有一个用户提供的名称,可用于引用该包。
当用于保护嵌入式 Web 服务器时,keystore 通常会配置一个证书和私钥,如下例所示:
- Properties
- YAML
spring.ssl.bundle.pem.mybundle.keystore.certificate=classpath:application.crt
spring.ssl.bundle.pem.mybundle.keystore.private-key=classpath:application.key
spring:
ssl:
bundle:
pem:
mybundle:
keystore:
certificate: "classpath:application.crt"
private-key: "classpath:application.key"
当用于保护客户端连接时,truststore 通常会配置服务器证书,如下例所示:
- Properties
- YAML
spring.ssl.bundle.pem.mybundle.truststore.certificate=classpath:server.crt
spring:
ssl:
bundle:
pem:
mybundle:
truststore:
certificate: "classpath:server.crt"
可以提供文件的 Base64 编码内容,而不是文件的位置。如果选择此选项,属性值应以 base64: 开头。
certificate 和 private-key 属性也可以直接使用 PEM 格式的内容。如果属性值中包含 BEGIN 和 END 标记,则会被视为 PEM 内容,而非资源位置。
以下示例展示了如何定义一个 truststore 证书:
- Properties
- YAML
spring.ssl.bundle.pem.mybundle.truststore.certificate=\
-----BEGIN CERTIFICATE-----\n\
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL\n\
BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI\n\
...\n\
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds\n\
HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb\n\
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8\n\
-----END CERTIFICATE-----\n
spring:
ssl:
bundle:
pem:
mybundle:
truststore:
certificate: |
-----BEGIN CERTIFICATE-----
MIID1zCCAr+gAwIBAgIUNM5QQv8IzVQsgSmmdPQNaqyzWs4wDQYJKoZIhvcNAQEL
BQAwezELMAkGA1UEBhMCWFgxEjAQBgNVBAgMCVN0YXRlTmFtZTERMA8GA1UEBwwI
...
V0IJjcmYjEZbTvpjFKznvaFiOUv+8L7jHQ1/Yf+9c3C8gSjdUfv88m17pqYXd+Ds
HEmfmNNjht130UyjNCITmLVXyy5p35vWmdf95U3uEbJSnNVtXH8qRmN9oK9mUpDb
ngX6JBJI7fw7tXoqWSLHNiBODM88fUlQSho8
-----END CERTIFICATE-----
完整的支持属性集请参见 PemSslBundleProperties。
如果你使用环境变量来配置 bundle,bundle 的名称始终会被转换为小写。
应用 SSL 证书包
一旦通过属性配置完成,SSL bundles 就可以在 Spring Boot 自动配置的各种连接类型的配置属性中通过名称进行引用。更多信息请参见 嵌入式 Web 服务器、数据技术 和 REST 客户端 相关章节。
使用 SSL Bundles
Spring Boot 会自动配置一个类型为 SslBundles 的 Bean,该 Bean 提供对通过 spring.ssl.bundle 属性配置的各个命名 bundle 的访问。
可以从自动配置的 SslBundles Bean 中获取 SslBundle,并用于创建对象,以配置客户端库中的 SSL 连接。SslBundle 提供了一种分层的方式来获取这些 SSL 对象:
-
getStores()提供对密钥库(key store)和信任库(trust store)的 KeyStore 实例以及所需的密钥库密码的访问。 -
getManagers()提供对 KeyManagerFactory 和 TrustManagerFactory 实例的访问,以及它们所创建的 KeyManager 和 TrustManager 数组。 -
createSslContext()提供了一种便捷的方式来获取一个新的 SSLContext 实例。
此外,SslBundle 提供了有关所使用密钥的详细信息、要使用的协议以及应应用于 SSL 引擎的任何选项。
以下示例展示了如何检索一个 SslBundle 并使用它来创建一个 SSLContext:
- Java
- Kotlin
import javax.net.ssl.SSLContext;
import org.springframework.boot.ssl.SslBundle;
import org.springframework.boot.ssl.SslBundles;
import org.springframework.stereotype.Component;
@Component
public class MyComponent {
public MyComponent(SslBundles sslBundles) {
SslBundle sslBundle = sslBundles.getBundle("mybundle");
SSLContext sslContext = sslBundle.createSslContext();
// do something with the created sslContext
}
}
import org.springframework.boot.ssl.SslBundles
import org.springframework.stereotype.Component
@Component
class MyComponent(sslBundles: SslBundles) {
init {
val sslBundle = sslBundles.getBundle("mybundle")
val sslContext = sslBundle.createSslContext()
// do something with the created sslContext
}
}
重新加载 SSL 证书包
当密钥材料发生变化时,SSL bundle 可以被重新加载。使用该 bundle 的组件必须兼容可重载的 SSL bundle。目前以下组件是兼容的:
-
Tomcat Web 服务器
-
Netty Web 服务器
要启用重载,你需要通过一个配置属性进行选择加入,如以下示例所示:
- Properties
- YAML
spring.ssl.bundle.pem.mybundle.reload-on-update=true
spring.ssl.bundle.pem.mybundle.keystore.certificate=file:/some/directory/application.crt
spring.ssl.bundle.pem.mybundle.keystore.private-key=file:/some/directory/application.key
spring:
ssl:
bundle:
pem:
mybundle:
reload-on-update: true
keystore:
certificate: "file:/some/directory/application.crt"
private-key: "file:/some/directory/application.key"
随后,一个文件监视器会监控这些文件,如果文件发生变化,SSL 证书包将被重新加载。这反过来会触发使用该证书包的组件进行重载,例如 Tomcat 会在启用 SSL 的连接器中轮换证书。
你可以通过 spring.ssl.bundle.watch.file.quiet-period 属性来配置文件监视器的静默期(以确保没有更多变更)。