如何为相互 SSL 覆盖 Spring 引导 keystore/truststore
How to override Spring boot keystore/truststore for mutual SSL
我有一个 Spring 启动应用程序。它的 application.yml 是从在线资源中获取的。它包含以下相互 SSL 的配置:
server:
ssl:
enabled: true
client-auth: need
key-store-type: PKCS12
key-store: http://{config server url}/keystore.p12
key-store-password: {keystore password}
trust-store-type: JKS
trust-store: http://{config server url}/truststore.jks
trust-store-password: {truststore password}
port: 8443
当运行申请时,我有这个错误:
java.io.IOException: DerInputStream.getLength(): lengthTag=111, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)
at sun.security.util.DerValue.init(DerValue.java:391)
at sun.security.util.DerValue.<init>(DerValue.java:332)
at sun.security.util.DerValue.<init>(DerValue.java:345)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1938)
at java.security.KeyStore.load(KeyStore.java:1445)
at org.apache.tomcat.util.security.KeyStoreUtil.load(KeyStoreUtil.java:69)
at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:209)
at org.apache.tomcat.util.net.SSLHostConfigCertificate.getCertificateKeystore(SSLHostConfigCertificate.java:206)
at org.apache.tomcat.util.net.SSLUtilBase.getKeyManagers(SSLUtilBase.java:272)
at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:239)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:97)
... 23 common frames omitted
但我可以通过编程方式打开密钥库和信任库。 (如下图)
private KeyStore getKeyStore() {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (InputStream is = readCertificateFromURL(new URI(keyStoreURL))) {
keyStore.load(is, keyStorePassword.toCharArray());
}
return keyStore();
}
private InputStream readCertificateFromURL(URI uri) throws IOException {
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.accept(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM)
.build();
Resource resource = new RestTemplate().exchange(requestEntity,Resource.class).getBody();
return resource.getInputStream();
}
如何让 Spring 引导选择这些 key/truststores 而不是 application.yml 中定义的那些?
我在网上找到的唯一内容是覆盖 keystore/truststore 路径,而不是 KeyStore 对象本身。
javax.net.ssl.trustStore
和 javax.net.ssl.keyStore
的值以及它们在 Spring 属性中的相应值需要是文件系统路径。如果您将它们复制到本地文件系统并改为引用它们,您的方法是否有效?
正如@Toby 所问,它确实适用于本地文件。问题是商店是从配置服务器下载的,而不是以二进制形式下载的。我最终实现了自定义 SslStoreProvider:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer() {
return tomcat -> tomcat.setSslStoreProvider(new SslStoreProvider() {
@Override
public KeyStore getKeyStore() throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
try (InputStream is = readStoreFromURL(new URI(keyStoreURL))) {
keyStore.load(is, keyStorePassword.toCharArray());
}
return keyStore;
}
@Override
public KeyStore getTrustStore() throws Exception {
KeyStore truststore = KeyStore.getInstance(trustStoreType);
try (InputStream is = readStoreFromURL(new URI(trustStoreURL))) {
truststore.load(is, trustStorePassword.toCharArray());
}
return truststore;
}
private InputStream readStoreFromURL(URI uri) {
// Download the stores as binary from the config server
}
});
}
我有一个 Spring 启动应用程序。它的 application.yml 是从在线资源中获取的。它包含以下相互 SSL 的配置:
server:
ssl:
enabled: true
client-auth: need
key-store-type: PKCS12
key-store: http://{config server url}/keystore.p12
key-store-password: {keystore password}
trust-store-type: JKS
trust-store: http://{config server url}/truststore.jks
trust-store-password: {truststore password}
port: 8443
当运行申请时,我有这个错误:
java.io.IOException: DerInputStream.getLength(): lengthTag=111, too big.
at sun.security.util.DerInputStream.getLength(DerInputStream.java:599)
at sun.security.util.DerValue.init(DerValue.java:391)
at sun.security.util.DerValue.<init>(DerValue.java:332)
at sun.security.util.DerValue.<init>(DerValue.java:345)
at sun.security.pkcs12.PKCS12KeyStore.engineLoad(PKCS12KeyStore.java:1938)
at java.security.KeyStore.load(KeyStore.java:1445)
at org.apache.tomcat.util.security.KeyStoreUtil.load(KeyStoreUtil.java:69)
at org.apache.tomcat.util.net.SSLUtilBase.getStore(SSLUtilBase.java:209)
at org.apache.tomcat.util.net.SSLHostConfigCertificate.getCertificateKeystore(SSLHostConfigCertificate.java:206)
at org.apache.tomcat.util.net.SSLUtilBase.getKeyManagers(SSLUtilBase.java:272)
at org.apache.tomcat.util.net.SSLUtilBase.createSSLContext(SSLUtilBase.java:239)
at org.apache.tomcat.util.net.AbstractJsseEndpoint.createSSLContext(AbstractJsseEndpoint.java:97)
... 23 common frames omitted
但我可以通过编程方式打开密钥库和信任库。 (如下图)
private KeyStore getKeyStore() {
KeyStore keyStore = KeyStore.getInstance("PKCS12");
try (InputStream is = readCertificateFromURL(new URI(keyStoreURL))) {
keyStore.load(is, keyStorePassword.toCharArray());
}
return keyStore();
}
private InputStream readCertificateFromURL(URI uri) throws IOException {
RequestEntity<Void> requestEntity = RequestEntity.get(uri)
.accept(org.springframework.http.MediaType.APPLICATION_OCTET_STREAM)
.build();
Resource resource = new RestTemplate().exchange(requestEntity,Resource.class).getBody();
return resource.getInputStream();
}
如何让 Spring 引导选择这些 key/truststores 而不是 application.yml 中定义的那些?
我在网上找到的唯一内容是覆盖 keystore/truststore 路径,而不是 KeyStore 对象本身。
javax.net.ssl.trustStore
和 javax.net.ssl.keyStore
的值以及它们在 Spring 属性中的相应值需要是文件系统路径。如果您将它们复制到本地文件系统并改为引用它们,您的方法是否有效?
正如@Toby 所问,它确实适用于本地文件。问题是商店是从配置服务器下载的,而不是以二进制形式下载的。我最终实现了自定义 SslStoreProvider:
@Bean
public WebServerFactoryCustomizer<TomcatServletWebServerFactory> tomcatSslCustomizer() {
return tomcat -> tomcat.setSslStoreProvider(new SslStoreProvider() {
@Override
public KeyStore getKeyStore() throws Exception {
KeyStore keyStore = KeyStore.getInstance(keyStoreType);
try (InputStream is = readStoreFromURL(new URI(keyStoreURL))) {
keyStore.load(is, keyStorePassword.toCharArray());
}
return keyStore;
}
@Override
public KeyStore getTrustStore() throws Exception {
KeyStore truststore = KeyStore.getInstance(trustStoreType);
try (InputStream is = readStoreFromURL(new URI(trustStoreURL))) {
truststore.load(is, trustStorePassword.toCharArray());
}
return truststore;
}
private InputStream readStoreFromURL(URI uri) {
// Download the stores as binary from the config server
}
});
}