ssl properties spring-boot truststore

ssl - Especificación de la información de la tienda de confianza en spring boot application.properties



spring-boot truststore (10)

Aquí mi versión extendida de la respuesta de Oleksandr Shpota , incluidas las importaciones. El paquete org.apache.http.* Se puede encontrar en org.apache.httpcomponents:httpclient . He comentado los cambios:

import org.apache.http.client.HttpClient; import org.apache.http.conn.ssl.NoopHostnameVerifier; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.core.io.Resource; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.client.RestTemplate; @Value("${http.client.ssl.key-store}") private Resource keyStore; @Value("${http.client.ssl.trust-store}") private Resource trustStore; // I use the same pw for both keystores: @Value("${http.client.ssl.trust-store-password}") private String keyStorePassword; // wasn''t able to provide this as a @Bean...: private RestTemplate getRestTemplate() { try { SSLContext sslContext = SSLContexts.custom() // keystore wasn''t within the question''s scope, yet it might be handy: .loadKeyMaterial( keyStore.getFile(), keyStorePassword.toCharArray(), keyStorePassword.toCharArray()) .loadTrustMaterial( trustStore.getURL(), keyStorePassword.toCharArray(), // use this for self-signed certificates only: new TrustSelfSignedStrategy()) .build(); HttpClient httpClient = HttpClients.custom() // use NoopHostnameVerifier with caution, see https://stackoverflow.com/a/22901289/3890673 .setSSLSocketFactory(new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier())) .build(); return new RestTemplate(new HttpComponentsClientHttpRequestFactory(httpClient)); } catch (IOException | GeneralSecurityException e) { throw new RuntimeException(e); } }

Estoy usando springBootVersion 1.2.0.RELEASE. Estoy tratando de configurar mi keystore y truststore a través de application.properties.

Cuando agrego las siguientes configuraciones, puedo hacer funcionar el keystore, pero no el truststore.

server.ssl.key-store=classpath:foo.jks server.ssl.key-store-password=password server.ssl.key-password=password server.ssl.trust-store=classpath:foo.jks server.ssl.trust-store-password=password

Sin embargo, si agrego el truststore,

bootRun { jvmArgs = [ "-Djavax.net.ssl.trustStore=c://foo.jks", "-Djavax.net.ssl.trustStorePassword=password"] }

funciona bien

¿Alguien ha usado la aplicación.propiedades para tiendas de confianza?


En caso de que necesite realizar una llamada REST, puede utilizarla de la siguiente manera.

Esto funcionará para las llamadas salientes a través de RestTemplate .

Declare RestTemplate Bean así.

@Configuration public class SslConfiguration { @Value("${http.client.ssl.trust-store}") private Resource keyStore; @Value("${http.client.ssl.trust-store-password}") private String keyStorePassword; @Bean RestTemplate restTemplate() throws Exception { SSLContext sslContext = new SSLContextBuilder() .loadTrustMaterial( keyStore.getURL(), keyStorePassword.toCharArray() ).build(); SSLConnectionSocketFactory socketFactory = new SSLConnectionSocketFactory(sslContext); HttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(socketFactory).build(); HttpComponentsClientHttpRequestFactory factory = new HttpComponentsClientHttpRequestFactory(httpClient); return new RestTemplate(factory); } }

Donde http.client.ssl.trust-store y http.client.ssl.trust-store-password apuntan a truststore en formato JKS y la contraseña para el truststore especificado.

Esto anulará el bean RestTemplate proporcionado con Spring Boot y hará que use el almacén de confianza que necesita.


En una infraestructura de microservicio (no se ajusta al problema, lo sé;)) no debe usar:

server: ssl: trust-store: path-to-truststore... trust-store-password: my-secret-password...

En cambio, el equilibrador de carga de cinta se puede configurar:

ribbon: TrustStore: keystore.jks TrustStorePassword : example ReadTimeout: 60000 IsSecure: true MaxAutoRetries: 1

Aquí https://github.com/rajaramkushwaha/https-zuul-proxy-spring-boot-app puede encontrar una muestra de trabajo. También hubo una discusión github sobre eso, pero ya no lo encontré.


Hizo esta pregunta en la página de Gitter de Spring-boot:


Las propiedades de Java "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" no se corresponden con "server.ssl.trust-store" y "server.ssl.trust-store-password" desde Spring boot " application.properties "(" application.yml ")

por lo que no puede establecer "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" simplemente configurando "server.ssl.trust-store" y "server.ssl.trust-store-password" en " application.properties "(" application.yml ")

una alternativa para configurar "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword" es mediante Spring Externalized Configuration

a continuación se encuentran extractos de mi implementación:

La clase de Params contiene la configuración externa

@Component @ConfigurationProperties("params") public class Params{ //default values, can be override by external settings public static String trustStorePath = "config/client-truststore.jks"; public static String trustStorePassword = "wso2carbon"; public static String keyStorePath = "config/wso2carbon.jks"; public static String keyStorePassword = "wso2carbon"; public static String defaultType = "JKS"; public void setTrustStorePath(String trustStorePath){ Params.trustStorePath = trustStorePath; } public void settrustStorePassword(String trustStorePassword){ Params.trustStorePassword=trustStorePassword; } public void setKeyStorePath(String keyStorePath){ Params.keyStorePath = keyStorePath; } public void setkeyStorePassword(String keyStorePassword){ Params.keyStorePassword = keyStorePassword; } public void setDefaultType(String defaultType){ Params.defaultType = defaultType; }

La clase KeyStoreUtil asume la configuración de "javax.net.ssl.trustStore" y "javax.net.ssl.trustStorePassword"

public class KeyStoreUtil { public static void setTrustStoreParams() { File filePath = new File( Params.trustStorePath); String tsp = filePath.getAbsolutePath(); System.setProperty("javax.net.ssl.trustStore", tsp); System.setProperty("javax.net.ssl.trustStorePassword", Params.trustStorePassword); System.setProperty("javax.net.ssl.keyStoreType", Params.defaultType); } public static void setKeyStoreParams() { File filePath = new File(Params.keyStorePath); String ksp = filePath.getAbsolutePath(); System.setProperty("Security.KeyStore.Location", ksp); System.setProperty("Security.KeyStore.Password", Params.keyStorePassword); } }

obtienes los setters ejecutados dentro de la función de inicio

@SpringBootApplication @ComponentScan("com.myapp.profiles") public class ProfilesApplication { public static void main(String[] args) { KeyStoreUtil.setKeyStoreParams(); KeyStoreUtil.setTrustStoreParams(); SpringApplication.run(ProfilesApplication.class, args); } }

la aplicación.yml

--- params: trustStorePath: config/client-truststore.jks trustStorePassword: wso2carbon keyStorePath: config/wso2carbon.jks keyStorePassword: wso2carbon defaultType: JKS ---

finalmente, dentro del entorno en ejecución (servidor de implementación), crea una carpeta llamada "config" en la misma carpeta donde se almacena el archivo jar.

dentro de la carpeta "config", almacena "application.yml", "client-truststore.jks" y "wso2carbon.jks". ¡hecho!


Sé que esto es bastante viejo, pero si alguien se encuentra con esto, lo que hice fue agregar otra propiedad a mi archivo de propiedades.

server.ssl.trust-store=classpath:truststore.jks server.ssl.trust-store-password=${KEY_STORE_PASS} server.ssl.client-auth=need

Entonces primero crea el almacén de confianza y establece las propiedades en el archivo de propiedades. Luego, de acuerdo con this , agrega server.ssl.client-auth=need para forzar a Spring solo a aceptar solicitudes que lleven un certificado aceptado por aquellos en su tienda de confianza.

Este método resolvió mi problema.


Si ejecuta su aplicación Spring Boot como un servicio de Linux (por ejemplo, script init.d o similar), también tiene la siguiente opción: Cree un archivo llamado suAplicación.conf y póngalo junto a su archivo war / jar ejecutable. Su contenido debe ser algo similar:

JAVA_OPTS=" -Djavax.net.ssl.trustStore=path-to-your-trustStore-file -Djavax.net.ssl.trustStorePassword=yourCrazyPassword "


También estaba teniendo el mismo problema con Spring Boot y Tomcat integrado.

Por lo que entiendo, estas propiedades solo configuran los parámetros de configuración de Tomcat. Según la documentación de Tomcat, esto solo se usa para la autenticación de Cliente (es decir, para SSL bidireccional) y no para verificar certificados remotos:

truststoreFile - El archivo de almacenamiento de confianza que se utilizará para validar certificados de cliente .

https://tomcat.apache.org/tomcat-8.0-doc/config/http.html

Para configurar el almacén de confianza para HttpClient, depende en gran medida de la implementación de HttpClient que utilice. Por ejemplo, para RestTemplate de forma predeterminada Spring Boot utiliza un SimpleClientHttpRequestFactory basado en clases J2SE estándar como java.net.HttpURLConnection.

He encontrado una solución basada en los documentos de Apache HttpClient y estas publicaciones: http://vincentdevillers.blogspot.pt/2013/02/configure-best-spring-resttemplate.html http://literatejava.com/networks/ignore-ssl-certificate-errors-apache-httpclient-4-4/

Básicamente, esto permite un bean RestTemplate que solo confía en los certificados firmados por la CA raíz en el almacén de confianza configurado.

@Configuration public class RestClientConfig { // e.g. Add http.client.ssl.trust-store=classpath:ssl/truststore.jks to application.properties @Value("${http.client.ssl.trust-store}") private Resource trustStore; @Value("${http.client.ssl.trust-store-password}") private char[] trustStorePassword; @Value("${http.client.maxPoolSize}") private Integer maxPoolSize; @Bean public ClientHttpRequestFactory httpRequestFactory() { return new HttpComponentsClientHttpRequestFactory(httpClient()); } @Bean public HttpClient httpClient() { // Trust own CA and all child certs Registry<ConnectionSocketFactory> socketFactoryRegistry = null; try { SSLContext sslContext = SSLContexts .custom() .loadTrustMaterial(trustStore.getFile(), trustStorePassword) .build(); // Since only our own certs are trusted, hostname verification is probably safe to bypass SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext, new HostnameVerifier() { @Override public boolean verify(final String hostname, final SSLSession session) { return true; } }); socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create() .register("http", PlainConnectionSocketFactory.getSocketFactory()) .register("https", sslSocketFactory) .build(); } catch (Exception e) { //TODO: handle exceptions e.printStackTrace(); } PoolingHttpClientConnectionManager connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry); connectionManager.setMaxTotal(maxPoolSize); // This client is for internal connections so only one route is expected connectionManager.setDefaultMaxPerRoute(maxPoolSize); return HttpClientBuilder.create() .setConnectionManager(connectionManager) .disableCookieManagement() .disableAuthCaching() .build(); } @Bean public RestTemplate restTemplate() { RestTemplate restTemplate = new RestTemplate(); restTemplate.setRequestFactory(httpRequestFactory()); return restTemplate; } }

Y luego puede usar este cliente Rest personalizado siempre que lo necesite, por ejemplo:

@Autowired private RestTemplate restTemplate; restTemplate.getForEntity(...)

Esto supone que intenta conectarse a un punto final de resto, pero también puede usar el bean HttpClient anterior para lo que desee.


Tengo el mismo problema, trataré de explicarlo un poco más en detalle.

Estoy usando spring-boot 1.2.2-RELEASE y lo probé en Tomcat y Undertow con el mismo resultado.

Definir el trust-store en application.yml como:

server: ssl: trust-store: path-to-truststore... trust-store-password: my-secret-password...

No funciona, mientras:

$ java -Djavax.net.debug=ssl -Djavax.net.ssl.trustStore=path-to-truststore... -Djavax.net.ssl.trustStorePassword=my-secret-password... -jar build/libs/*.jar

funciona perfectamente bien

La forma más sencilla de ver la diferencia en el momento es habilitar ssl-debug en el cliente. Cuando se trabaja (es decir, usando -D flags) algo similar a lo siguiente se escribe en la consola (durante el procesamiento de la primera solicitud):

trustStore is: path-to-truststore... trustStore type is : jks trustStore provider is : init truststore adding as trusted cert: Subject: C=..., ST=..., O=..., OU=..., CN=... Issuer: C=..., ST=..., O=..., OU=..., CN=... Algorithm: RSA; Serial number: 0x4d2 Valid from Wed Oct 16 17:58:35 CEST 2013 until Tue Oct 11 17:58:35 CEST 2033

Sin las banderas -D consigo:

trustStore is: /Library/Java/JavaVirtualMachines/jdk1.8.0_11.jdk/Contents/Home/jre/lib/security/cacerts trustStore type is : jks trustStore provider is : init truststore adding as trusted cert: ... (one for each CA-cert in the defult truststore)

... y al realizar una solicitud obtengo la excepción:

sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

Espero que ayude a entender mejor el problema.


Tuve el mismo problema con Spring Boot, Spring Cloud (microservicios) y un certificado SSL autofirmado. Keystore funcionó de la caja de propiedades de la aplicación, y Truststore no.

Terminé manteniendo la configuración de almacén de claves y trustore en application.properties y agregando un bean de configuración separado para configurar las propiedades de truststore con el sistema.

@Configuration public class SSLConfig { @Autowired private Environment env; @PostConstruct private void configureSSL() { //set to TLSv1.1 or TLSv1.2 System.setProperty("https.protocols", "TLSv1.1"); //load the ''javax.net.ssl.trustStore'' and //''javax.net.ssl.trustStorePassword'' from application.properties System.setProperty("javax.net.ssl.trustStore", env.getProperty("server.ssl.trust-store")); System.setProperty("javax.net.ssl.trustStorePassword",env.getProperty("server.ssl.trust-store-password")); } }