我们有一个用于 REST Web 服务的 Spring Boot 应用程序,该应用程序仍在开发中。 我们现在使用自签名证书。
现在,它将与另外 1 个已开发的应用程序一起部署到系统中。 这个预先存在的应用程序默认使用自签名证书,但为客户提供了上传 CA 证书的选项(如果需要)。现在,我们想为这个新应用程序使用相同的证书。
基本上,我们希望客户端对在 1 个系统中运行的 2 个应用程序使用 1 个证书。
现在,这个现有应用程序具有 .pem 和 .cer 等证书文件。
如何在使用 jks 格式证书的 Spring Boot 应用程序中使用此证书?
当然,如果有任何更新,证书应该可供两个应用程序使用。
从 Spring Boot 2.7 开始,可以使用 PEM 编码的证书和私钥文件。
请参阅下面的示例(PKCS8 格式的私钥)。
server:
port: 8443
ssl:
certificate: "classpath:my-cert.crt"
certificate-private-key: "classpath:my-cert.key"
trust-certificate: "classpath:ca-cert.crt"
PEM 是一种众所周知的证书文件格式。除了 Java 之外。由于 Java 仅使用 JKS(其仅限 Java 的二进制密钥库)或 PKCS12 作为密钥和证书。因此,我们必须将 PEM 编码的证书转换为 JKS 或 PKCS12,以便 Java 可以使用它。但在很多情况下这可能很丑陋。
您可以在 spring-boot 应用程序中使用以下依赖项。
<dependency>
<groupId>de.dentrassi.crypto</groupId>
<artifactId>pem-keystore</artifactId>
<version>2.0.0</version>
</dependency>
然后添加
KeyStore keyStore = KeyStore.getInstance("PEM");
了解更多信息
https://github.com/ctron/pem-keystore
application.properties
server.ssl.enabled=true
server.ssl.key-store=/path/to/keystore.properties
server.ssl.key-store-type=PEMCFG
server.ssl.key-store-password=dummy
server.ssl.key-alias=keycert
然后创建文件
keystore.properties
:
alias=keycert
source.cert=/etc/…/fullchain.pem
source.key=/etc/…/privkey.pem
我经常做的就是在 Spring 中用 Jetty 替换 Tomcat,它允许自定义 ssl 配置。通过这种设置,可以进行任何类型的自定义,例如处理 pem 文件,但也可以处理特别加密的 pem 文件。以下是我使用的设置:
下面将加载 pem 文件并创建 KeyManager TrustManager。这将用于创建 SSLFactory,而 SSLFactory 将用于转换为 Jetty 兼容的 ssl 配置。
import nl.altindag.ssl.SSLFactory;
import nl.altindag.ssl.util.JettySslUtils;
import nl.altindag.ssl.util.PemUtils;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import javax.net.ssl.X509ExtendedKeyManager;
import javax.net.ssl.X509ExtendedTrustManager;
@Configuration
public class SSLConfig {
@Bean
public SSLFactory sslFactory() {
X509ExtendedKeyManager keyManager = PemUtils.loadIdentityMaterial("chain.pem", "private-key.pem", "my-password".toCharArray());
X509ExtendedTrustManager trustManager = PemUtils.loadTrustMaterial("some-trusted-certificate.pem");
return SSLFactory.builder()
.withIdentityMaterial(keyManager)
.withTrustMaterial(trustManager)
.build();
}
@Bean
public SslContextFactory.Server sslContextFactory(SSLFactory sslFactory) {
return JettySslUtils.forServer(sslFactory);
}
}
Jetty SSL 配置需要传递到服务器配置:
import org.eclipse.jetty.server.Connector;
import org.eclipse.jetty.server.ServerConnector;
import org.eclipse.jetty.util.ssl.SslContextFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.embedded.jetty.JettyServerCustomizer;
import org.springframework.boot.web.embedded.jetty.JettyServletWebServerFactory;
import org.springframework.boot.web.servlet.server.ConfigurableServletWebServerFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.Collections;
@Configuration
public class ServerConfig {
@Bean
public ConfigurableServletWebServerFactory webServerFactory(SslContextFactory.Server sslContextFactory, @Value("${server.port}") int serverPort) {
JettyServletWebServerFactory factory = new JettyServletWebServerFactory();
JettyServerCustomizer jettyServerCustomizer = server -> {
ServerConnector serverConnector = new ServerConnector(server, sslContextFactory);
serverConnector.setPort(serverPort);
server.setConnectors(new Connector[]{serverConnector});
};
factory.setServerCustomizers(Collections.singletonList(jettyServerCustomizer));
return factory;
}
}
在这两个java配置之后,你还需要告诉Spring不要使用Tomcat,而应该使用Jetty。这可以通过以下 pom 配置来完成:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot</artifactId>
<version>2.7.5</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
<version>2.7.5</version>
<exclusions>
<exclusion>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-jetty</artifactId>
<version>2.7.5</version>
</dependency>
我使用自己的库来读取 pem 文件。请参阅下面的依赖项,并在此处了解有关其他用法的更多信息:SSLContext-Kickstart
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-jetty</artifactId>
<version>8.1.2</version>
</dependency>
<dependency>
<groupId>io.github.hakky54</groupId>
<artifactId>sslcontext-kickstart-for-pem</artifactId>
<version>8.1.2</version>
</dependency>
可以从证书和私钥创建 JKS 文件(pem 格式),如下
#Combine private key and certificate to create pkcs12 file
openssl pkcs12 -export -out keystore.p12 -inkey privatekey.pem -in certificate.crt -name your_alias
#Import the certificate and key into a JKS file for Java to use
keytool -importkeystore -srckeystore keystore.p12 -srcstoretype PKCS12 -destkeystore keystore.jks -deststoretype JKS
为了测试安全 API,您可以使用 Fiddler,这是一个绕过或伪造 SSL 的工具。
(或)
您可以像下面这样配置应用程序属性。
server.port: 8443
security.require-ssl=true
server.ssl.key-store:/etc/letsencrypt/live/seeld.eu/keystore.p12
server.ssl.key-store-password: <your-password>
server.ssl.keyStoreType: PKCS12
server.ssl.keyAlias: tomcat