Habilitación de HTTPS en Spring Boot con certificados de Azure Key Vault
En este tutorial se muestra cómo proteger las aplicaciones de Spring Boot (incluidas Azure Spring Apps) con certificados TLS/SSL mediante Azure Key Vault e identidades administradas para recursos de Azure.
Las aplicaciones de Spring Boot del nivel de producción, ya sea en la nube o en un entorno local, requieren cifrado de un extremo a otro para el tráfico de red mediante protocolos TLS estándar. La mayoría de los certificados TLS/SSL que se encuentra se pueden detectar desde una entidad de certificación raíz pública. Sin embargo, a veces no es posible esta detección. Si los certificados no son detectables, la aplicación debe tener alguna manera de cargarlos, presentarlos a las conexiones de red entrantes y aceptarlos de las conexiones de red salientes.
Las aplicaciones de Spring Boot habilitan normalmente TLS mediante la instalación de los certificados. Los certificados se instalan en el almacén de claves local de la máquina virtual Java que ejecuta la aplicación Spring Boot. Con Spring en Azure, los certificados no se instalan localmente. En su lugar, la integración de Spring para Microsoft Azure proporciona una manera segura y sin problemas de habilitar TLS con la ayuda de Azure Key Vault y la identidad administrada para recursos de Azure.
Importante
Actualmente, Spring Cloud Azure Certificate Starter versión 4.x o posterior no admite TLS/mTLS, solo configuran automáticamente el cliente de certificados de Key Vault. Por lo tanto, si desea usar TLS/mTLS, no puede migrar a la versión 4.x.
Requisitos previos
Una suscripción a Azure: cree una cuenta gratuita.
Un kit de desarrollo de Java (JDK) admitido, versión 11.
Apache Maven, versión 3.0 o posterior.
cURL o una utilidad HTTP similar para probar la funcionalidad.
Una instancia de máquina virtual (VM) de Azure. Si no tiene una, use el comando az vm create y la imagen de Ubuntu proporcionada por UbuntuServer para crear una instancia de máquina virtual con una identidad administrada asignada por el sistema habilitada. Conceda el
Contributor
rol a la identidad administrada asignada por el sistema y establezca el accesoscope
a la suscripción.Una instancia de Azure Key Vault. Si no tiene una, consulte Inicio rápido: Creación de un almacén de claves mediante Azure Portal.
Una aplicación de Spring Boot. Si no tiene ninguna, cree un proyecto de Maven con Spring Initializr. Asegúrese de seleccionar Proyecto de Maven y, en Dependencias, agregue la dependencia de Spring Web y, a continuación, seleccione Java versión 8 o posterior.
Importante
Se requiere Spring Boot versión 2.5 o posterior para completar los pasos descritos en este artículo.
Establecimiento de un certificado TLS/SSL autofirmado
Los pasos de este tutorial se aplican a cualquier certificado TLS/SSL (incluso los autofirmados) que esté almacenado directamente en Azure Key Vault. Los certificados autofirmados no son adecuados para su uso en producción, pero son útiles para las aplicaciones de desarrollo y pruebas.
Este tutorial usa un certificado autofirmado. Para establecer el certificado, consulte Inicio rápido: Establecimiento y recuperación de un certificado de Azure Key Vault mediante Azure Portal.
Nota:
Después de establecer el certificado, conceda acceso a la máquina virtual a Key Vault siguiendo las instrucciones de Asignación de una directiva de acceso de Key Vault.
Protección de la conexión a través del certificado TLS/SSL
Ahora tiene una máquina virtual y una instancia de Key Vault y ha concedido acceso a la máquina virtual a Key Vault. En las secciones siguientes se muestra cómo conectarse de forma segura a través de certificados TLS/SSL desde Azure Key Vault en la aplicación Spring Boot. En este tutorial se muestran los dos escenarios siguientes:
- Ejecución de una aplicación de Spring Boot con conexiones entrantes seguras
- Ejecución de una aplicación de Spring Boot con conexiones salientes seguras
Sugerencia
En los pasos siguientes, el código se empaquetará en un archivo ejecutable y se cargará en la máquina virtual. No olvide instalar OpenJDK en la máquina virtual.
Ejecución de una aplicación de Spring Boot con conexiones entrantes seguras
Cuando el certificado TLS/SSL para la conexión entrante procede de Azure Key Vault, configure la aplicación siguiendo estos pasos:
Agregue las siguientes dependencias al archivo pom.xml :
<dependency> <groupId>com.azure.spring</groupId> <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId> <version>3.14.0</version> </dependency>
Configure las credenciales de Key Vault en el archivo de configuración application.properties .
server.ssl.key-alias=<the name of the certificate in Azure Key Vault to use> server.ssl.key-store-type=AzureKeyVault server.ssl.trust-store-type=AzureKeyVault server.port=8443 azure.keyvault.uri=<the URI of the Azure Key Vault to use>
Estos valores permiten que la aplicación Spring Boot realice la acción load del certificado TLS/SSL, como se mencionó al principio del tutorial. En la tabla siguiente se describen los valores de propiedad.
Propiedad Descripción server.ssl.key-alias
El valor del argumento --name
que pasó aaz keyvault certificate create
.server.ssl.key-store-type
Debe ser AzureKeyVault
.server.ssl.trust-store-type
Debe ser AzureKeyVault
.server.port
El puerto TCP local en el que se van a escuchar las conexiones HTTPS. azure.keyvault.uri
La propiedad vaultUri
del JSON devuelto desdeaz keyvault create
. Ha guardado este valor en una variable de entorno.La única propiedad específica de Key Vault es
azure.keyvault.uri
. La aplicación se ejecuta en una máquina virtual a cuya identidad administrada asignada por el sistema se le ha concedido acceso a Key Vault. Por lo tanto, también se ha concedido acceso a la aplicación.Estos cambios permiten a la aplicación de Spring Boot cargar el certificado TLS/SSL. En el paso siguiente, habilitará la aplicación para realizar la acción de aceptación del certificado TLS/SSL, como se mencionó al principio del tutorial.
Edite el archivo de clase de inicio para que tenga el siguiente contenido.
import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
Llamar a
System.exit(0)
desde una llamada REST GET no autenticada se efectúa solo con fines de demostración. No useSystem.exit(0)
en una aplicación real.Este código muestra la acción present mencionada al principio de este tutorial. En la lista siguiente se resaltan algunos detalles sobre este código:
- Ahora hay una anotación
@RestController
en la claseSsltestApplication
generada por Spring Initializr. - Hay un método anotado con
@GetMapping
, con unvalue
para la llamada HTTP que realice. - El método
inbound
simplemente devuelve un saludo cuando un explorador realiza una solicitud HTTPS a la ruta de acceso/ssl-test
. El métodoinbound
muestra cómo el servidor presenta el certificado TLS/SSL al explorador. - El
exit
método hace que la JVM salga cuando se invoque. Este método es conveniente para que el ejemplo sea fácil de ejecutar en el contexto de este tutorial.
- Ahora hay una anotación
Ejecute los siguientes comandos para compilar el código y empaquetarlo en un archivo JAR ejecutable.
mvn clean package
Compruebe que el grupo de seguridad de red creado en
<your-resource-group-name>
permite el tráfico entrante en los puertos 22 y 8443 desde su dirección IP. Para obtener información sobre cómo configurar las reglas del grupo de seguridad de red para permitir el tráfico entrante, consulte la sección Trabajar con reglas de seguridad del artículo Creación, modificación o eliminación de un grupo de seguridad de red.Coloque el archivo JAR ejecutable en la máquina virtual.
cd target sftp azureuser@<your VM public IP address> put *.jar
Ahora que ha compilado la aplicación Spring Boot y la ha cargado en la máquina virtual, siga estos pasos para ejecutarla en la máquina virtual y llamar al punto de conexión de REST con
curl
.Use SSH para conectarse a la máquina virtual y, a continuación, ejecute el archivo JAR ejecutable.
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
Abra un nuevo shell de Bash y ejecute el siguiente comando para comprobar que el servidor presenta el certificado TLS/SSL.
curl --insecure https://<your VM public IP address>:8443/ssl-test
Invoque la ruta de acceso
exit
para terminar los procesos del servidor y cerrar los sockets de red.curl --insecure https://<your VM public IP address>:8443/exit
Ahora que ha visto la carga y presenta acciones con un certificado TLS/SSL autofirmado, realice algunos cambios triviales en la aplicación para ver también la acción de aceptación.
Ejecución de una aplicación de Spring Boot con conexiones salientes seguras
En esta sección, modificará el código de la sección anterior para que el certificado TLS/SSL para las conexiones salientes provenga de Azure Key Vault. Por lo tanto, las acciones de load, present y accept se efectúan desde Azure Key Vault.
Agregue la dependencia del cliente HTTP de Apache al archivo pom.xml :
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency>
Incorporación de un nuevo punto de conexión de REST denominado
ssl-test-outbound
. Este punto de conexión abre un socket de TLS y comprueba que la conexión TLS acepta el certificado TLS/SSL. Reemplace la parte anterior de la clase de inicio por el código siguiente.import java.security.KeyStore; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; import com.azure.security.keyvault.jca.KeyVaultLoadStoreParameter; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.http.client.HttpComponentsClientHttpRequestFactory; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; import org.springframework.web.client.RestTemplate; import org.apache.http.conn.ssl.SSLConnectionSocketFactory; import org.apache.http.conn.ssl.TrustSelfSignedStrategy; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.ssl.SSLContexts; @SpringBootApplication @RestController public class SsltestApplication { public static void main(String[] args) { SpringApplication.run(SsltestApplication.class, args); } @GetMapping(value = "/ssl-test") public String inbound(){ return "Inbound TLS is working!!"; } @GetMapping(value = "/ssl-test-outbound") public String outbound() throws Exception { KeyStore azureKeyVaultKeyStore = KeyStore.getInstance("AzureKeyVault"); KeyVaultLoadStoreParameter parameter = new KeyVaultLoadStoreParameter( System.getProperty("azure.keyvault.uri")); azureKeyVaultKeyStore.load(parameter); SSLContext sslContext = SSLContexts.custom() .loadTrustMaterial(azureKeyVaultKeyStore, null) .build(); HostnameVerifier allowAll = (String hostName, SSLSession session) -> true; SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, allowAll); CloseableHttpClient httpClient = HttpClients.custom() .setSSLSocketFactory(csf) .build(); HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory(); requestFactory.setHttpClient(httpClient); RestTemplate restTemplate = new RestTemplate(requestFactory); String sslTest = "https://localhost:8443/ssl-test"; ResponseEntity<String> response = restTemplate.getForEntity(sslTest, String.class); return "Outbound TLS " + (response.getStatusCode() == HttpStatus.OK ? "is" : "is not") + " Working!!"; } @GetMapping(value = "/exit") public void exit() { System.exit(0); } }
Ejecute los siguientes comandos para compilar el código y empaquetarlo en un archivo JAR ejecutable.
mvn clean package
Vuelva a cargar la aplicación con el mismo comando
sftp
descrito anteriormente en este artículo.cd target sftp <your VM public IP address> put *.jar
Ejecute la aplicación en la máquina virtual.
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
Una vez que el servidor se esté ejecutando, compruebe que el servidor acepta el certificado TLS/SSL. En el mismo shell de Bash en el que emitió el comando
curl
anterior, ejecute el siguiente comando.curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
Verá el mensaje
Outbound TLS is working!!
.Invoque la ruta de acceso
exit
para terminar los procesos del servidor y cerrar los sockets de red.curl --insecure https://<your VM public IP address>:8443/exit
Ahora ha observado una ilustración sencilla de las acciones de load, present y accept con un certificado TLS/SSL autofirmado almacenado en Azure Key Vault.
Implementación en Azure Spring Apps
Ahora que tiene la aplicación Spring Boot que se ejecuta localmente, es el momento de moverla a producción. Azure Spring Apps facilita la implementación de aplicaciones de Spring Boot en Azure sin cambios en el código. El servicio administra la infraestructura de las aplicaciones de Spring, con el fin de que los desarrolladores puedan centrarse en el código. Azure Spring Apps proporciona administración del ciclo de vida mediante el uso de una supervisión y un diagnóstico completos, administración de la configuración, detección de servicios, integración de CI/CD e implementaciones azul-verde, entre otros. Para implementar la aplicación en Azure Spring Apps, consulte Implementación de la primera aplicación en Azure Spring Apps.
Pasos siguientes
Para más información acerca de Spring y Azure, vaya al centro de documentación de Azure.