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 de nivel de producción, ya sea en la nube o en el 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 puedes encontrar son accesibles a través de una autoridad de certificación raíz pública. A veces, sin embargo, esta detección no es posible. Cuando los certificados no se pueden detectar, la aplicación debe tener alguna manera de cargar dichos certificados, presentarlos a las conexiones de red entrantes y aceptarlos de las conexiones de red salientes.
Las aplicaciones de Spring Boot suelen habilitar TLS mediante la instalación de los certificados. Los certificados se instalan en el almacén de claves local de la JVM 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 fricción de habilitar TLS con ayuda de Azure Key Vault e identidad administrada para los 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.
Prerrequisitos
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 rol
Contributor
a la identidad administrada asignada por el sistema y luego configure el accesoscope
en su suscripción.Una instancia de Azure Key Vault. Si no la tiene, consulte Inicio rápido: Creación de una instancia de Key Vault mediante Azure Portal.
Una aplicación de Spring Boot. Si no tiene uno, cree un proyecto Maven con Spring Initializr. Asegúrese de seleccionar del proyecto de Maven y, en Dependencias, agregue la dependencia Spring Web y, después, seleccione Versión de Java 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 (incluido el autofirmado) almacenado directamente en Azure Key Vault. Los certificados autofirmados no son adecuados para su uso en producción, pero son útiles para aplicaciones de desarrollo y pruebas.
En este tutorial se 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 a la máquina virtual acceso 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 de la máquina virtual al 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 carga acción para el 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
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
. Tú guardaste 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 cuya identidad administrada asignada por el sistema se ha concedido acceso a Key Vault. Por lo tanto, también se ha concedido acceso a la aplicación.Estos cambios permiten que la aplicación Spring Boot cargue el certificado TLS/SSL. En el paso siguiente, habilitará la aplicación para que realice la acción accept en el certificado TLS/SSL, como se indicó 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 dentro de una llamada REST GET no autenticada solo es para 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 método
exit
hace que la JVM salga cuando se invoque. Este método es una comodidad para facilitar la ejecución del ejemplo 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 reglas de grupo de seguridad de red para permitir el tráfico entrante, consulte la sección Trabajar con reglas de seguridad de Crear, cambiar o eliminar 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 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 eliminar el servidor y cerrar los sockets de red.curl --insecure https://<your VM public IP address>:8443/exit
Ahora que ha visto las acciones load y present con un certificado TLS/SSL autofirmado, realizará algunos cambios triviales en la aplicación para ver también la acción accept.
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 TLS a sí mismo 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 utilizando de nuevo el mismo comando
sftp
mencionado 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"
Después de ejecutar el servidor, compruebe que el servidor acepta el certificado TLS/SSL. En el mismo shell de Bash donde emitió el comando
curl
anterior, ejecute el siguiente comando.curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
Debería ver el mensaje
Outbound TLS is working!!
.Invoque la ruta de acceso
exit
para eliminar el 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 para que los desarrolladores puedan centrarse en su código. Azure Spring Apps proporciona administración del ciclo de vida mediante supervisión y diagnósticos completos, administración de configuración, detección de servicios, integración de CI/CD, implementaciones azul-verde, etc. 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 sobre Spring y Azure, continúe con el Centro de documentación de Spring en Azure.