使用 Azure 密钥库 证书在 Spring Boot 中启用 HTTPS
本教程介绍如何使用 Azure 密钥库和 Azure 资源的托管标识通过 TLS/SSL 证书保护 Spring Boot(包括 Azure Spring Apps)应用。
无论是在云中还是在本地,生产级 Spring Boot 应用程序都需要使用标准 TLS 协议对网络流量进行端到端加密。 可以在公共根证书颁发机构 (CA) 中发现大多数常见 TLS/SSL 证书。 但有时这种发现无法实现。 当证书不可发现时,应用必须具备某种方法来加载此类证书、将其提供给入站网络连接以及接受来自出站网络连接的证书。
Spring Boot 应用通常通过安装证书来启用 TLS。 证书将安装到运行 Spring Boot 应用的 JVM 的本地密钥存储中。 使用 Azure 上的 Spring 时,不会在本地安装证书。 在这种情况下,Microsoft Azure 的 Spring 集成提供了一种安全且流程的方式,可以借助 Azure Key Vault 和 Azure 资源的托管标识来启用 TLS。
重要
目前,Spring Cloud Azure 证书初学者版本 4.x 或更高版本不支持 TLS/mTLS,它们仅自动配置密钥库证书客户端。 因此,如果要使用 TLS/mTLS,则无法迁移到版本 4.x。
先决条件
Azure 订阅 - 免费创建订阅。
受支持的 Java 开发工具包 (JDK) 版本 11。
Apache Maven 3.0 或更高版本。
用来测试功能的 cURL 或类似的 HTTP 实用工具。
Azure 虚拟机(VM)实例。 如果没有,请使用 az vm create 命令和 UbuntuServer 提供的 Ubuntu 映像创建启用了系统分配的托管标识的 VM 实例。 将
Contributor
角色授予系统分配的托管标识,然后设置对订阅的访问权限scope
。Azure Key Vault 实例。 如果没有密钥保管库,请参阅快速入门:使用Azure 门户创建密钥保管库。
Spring Boot 应用程序。 如果没有,请使用 Spring Initializr 创建一个 Maven 项目。 请务必选择 Maven 项目,并在“依赖项”下添加 Spring Web 依赖项,然后选择 Java 版本 8 或更高版本。
重要
完成本文中的步骤需要 Spring Boot 2.5 或更高版本。
设置自签名 TLS/SSL 证书
本教程中的步骤适用于任何直接存储在 Azure Key Vault 中的 TLS/SSL 证书(包括自签名的)。 自签名证书不适合用于生产,但对于开发和测试应用程序很有用。
本教程使用自签名证书。 若要设置证书,请参阅快速入门:使用Azure 门户从 Azure 密钥库设置和检索证书。
注意
设置证书后,按照分配密钥库访问策略中的说明授予 VM 对密钥库的访问权限。
通过 TLS/SSL 证书保护连接
现在已有一个 VM 和一个密钥库实例,并已授予 VM 对密钥库的访问权限。 以下部分演示如何在 Spring Boot 应用程序中通过 Azure 密钥库的 TLS/SSL 证书安全地连接。 本教程演示了以下两种方案:
- 使用安全的入站连接来运行 Spring Boot 应用程序
- 使用安全的出站连接来运行 Spring Boot 应用程序
提示
在以下步骤中,代码将打包到可执行文件中,并上传到 VM。 不要忘记在 VM 中安装 OpenJDK 。
使用安全的入站连接来运行 Spring Boot 应用程序
当入站连接的 TLS/SSL 证书来自 Azure 密钥库时,请按照以下步骤配置应用程序:
将以下依赖项添加到 pom.xml 文件:
<dependency> <groupId>com.azure.spring</groupId> <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId> <version>3.14.0</version> </dependency>
在 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>
如本教程开头所述,这些值使 Spring Boot 应用能够对 TLS/SSL 证书执行加载操作。 下表对这些属性值进行了说明。
properties 说明 server.ssl.key-alias
传递给 az keyvault certificate create
的--name
参数的值。server.ssl.key-store-type
必须是 AzureKeyVault
。server.ssl.trust-store-type
必须是 AzureKeyVault
。server.port
要用于侦听 HTTPS 连接的本地 TCP 端口。 azure.keyvault.uri
从 az keyvault create
返回的 JSON 中的vaultUri
属性。 已将此值保存在环境变量中。特定于 Key Vault 的唯一属性是
azure.keyvault.uri
。 运行该应用的 VM 的系统分配的托管标识已被授予 Key Vault 的访问权限。 因此,该应用也获得了该访问权限。这些更改使 Spring Boot 应用能够加载 TLS/SSL 证书。 在下一步中,你将使应用能够执行 TLS/SSL 证书的接受操作,如本教程开头提及。
编辑启动类文件,使其包含以下内容。
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); } }
从未经身份验证的 REST GET 调用中调用
System.exit(0)
仅用于演示目的。 请勿在实际应用程序中使用System.exit(0)
。此代码演示了本教程开头提到的“呈现”操作。 下面的列表侧重说明了有关此代码的一些详细信息:
- 现在由 Spring initializer 生成的
SsltestApplication
类上有一个@RestController
注释。 - 有一个用 进行
@GetMapping
value
的 HTTP 调用注释的方法。 inbound
方法在浏览器向/ssl-test
路径发出 HTTPS 请求时,只返回一个问候语。inbound
方法说明服务器如何向浏览器呈现 TLS/SSL 证书。- 该方法
exit
会导致 JVM 在调用时退出。 此方法可便于使示例在本教程上下文中易于运行。
- 现在由 Spring initializer 生成的
运行以下命令以编译代码并将其打包到可执行的 JAR 文件中。
mvn clean package
验证
<your-resource-group-name>
中创建的网络安全组是否允许来自你的 IP 地址的入站流量通过端口 22 和 8443。 若要了解如何配置网络安全组规则以允许入站流量,请参阅创建、更改或删除网络安全组中的使用安全规则一节。将可执行 JAR 文件放在 VM 上。
cd target sftp azureuser@<your VM public IP address> put *.jar
现在,你已生成 Spring Boot 应用并将其上传到 VM,请使用以下步骤在 VM 上运行它,并使用 调用 REST 终结点
curl
。使用 SSH 连接到 VM,然后运行可执行的 JAR。
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
打开新的 Bash shell,然后执行以下命令,验证服务器是否显示了 TLS/SSL 证书。
curl --insecure https://<your VM public IP address>:8443/ssl-test
调用
exit
路径,终止服务器并关闭网络套接字。curl --insecure https://<your VM public IP address>:8443/exit
现在,你已看到具有自签名 TLS/SSL 证书的加载和演示操作,同时对应用进行一些微不足道的更改,以查看接受操作。
使用安全的出站连接来运行 Spring Boot 应用程序
在本部分中,将修改上一部分中的代码,以便出站连接的 TLS/SSL 证书来自 Azure 密钥库。 这样便可以通过 Azure Key Vault 来满足加载、呈现和接受操作的需要。
将 Apache HTTP 客户端依赖项添加到 pom.xml 文件:
<dependency> <groupId>org.apache.httpcomponents</groupId> <artifactId>httpclient</artifactId> <version>4.5.13</version> </dependency>
添加一个名为
ssl-test-outbound
的新 rest 终结点。 此终结点向自身打开一个 TLS 套接字,并验证 TLS 连接是否接受 TLS/SSL 证书。 将启动类的上一部分替换为以下代码。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); } }
运行以下命令以编译代码并将其打包到可执行的 JAR 文件中。
mvn clean package
使用本文前面所述的
sftp
命令再次上传应用。cd target sftp <your VM public IP address> put *.jar
在 VM 上运行应用。
set -o noglob ssh azureuser@<your VM public IP address> "java -jar *.jar"
服务器运行后,验证服务器是否接受 TLS/SSL 证书。 在发出前面的
curl
命令的同一 Bash shell 中运行以下命令。curl --insecure https://<your VM public IP address>:8443/ssl-test-outbound
应该看到消息
Outbound TLS is working!!
。调用
exit
路径,终止服务器并关闭网络套接字。curl --insecure https://<your VM public IP address>:8443/exit
现在你已通过一个简单示例了解了如何使用存储在 Azure Key Vault 中的自签名 TLS/SSL 证书执行加载、呈现和接受操作。
部署到 Azure Spring Apps
现在,你已在本地运行 Spring Boot 应用程序,现在可以将其移动到生产环境。 使用 Azure Spring Apps 可以轻松地将 Spring Boot 应用程序部署到 Azure,而无需进行任何代码更改。 该服务管理 Spring 应用程序的基础结构,让开发人员可以专注于代码。 Azure Spring Apps 可以通过以下方法提供生命周期管理:综合性监视和诊断、配置管理、服务发现、CI/CD 集成、蓝绿部署等。 若要将应用程序部署到 Azure Spring Apps,请参阅将 第一个应用程序部署到 Azure Spring Apps。
后续步骤
若要了解有关 Spring 和 Azure 的详细信息,请继续访问“Azure 上的 Spring”文档中心。