【数据安全】教程:使用 Azure Key Vault 证书保护 Spring Boot 应用程序

Chinese, Simplified

本教程向你展示如何使用 Azure Key Vault 和 Azure 资源的托管标识通过 TLS/SSL 证书保护你的 Spring Boot(包括 Azure Spring 应用程序)应用程序。

生产级 Spring Boot 应用程序,无论是在云端还是在本地,都需要使用标准 TLS 协议对网络流量进行端到端加密。您遇到的大多数 TLS/SSL 证书都可以从公共根证书颁发机构 (CA) 中发现。然而,有时候,这种发现是不可能的。当证书不可发现时,应用程序必须有某种方式来加载此类证书,将它们呈现给入站网络连接,并从出站网络连接中接受它们。

Spring Boot 应用程序通常通过安装证书来启用 TLS。证书安装到运行 Spring Boot 应用程序的 JVM 的本地密钥库中。使用 Azure 上的 Spring,不会在本地安装证书。相反,Microsoft Azure 的 Spring 集成提供了一种安全且无摩擦的方式来借助 Azure Key Vault 和 Azure 资源的托管身份来启用 TLS。

Diagram showing interaction of elements in this tutorial.

在本教程中,您将学习如何:

  • 使用系统分配的托管标识创建 GNU/Linux VM
  • 创建 Azure Key Vault
  • 创建自签名 TLS/SSL 证书
  • 将自签名 TLS/SSL 证书存储在 Azure Key Vault 中
  • 运行 Spring Boot 应用程序,其中入站连接的 TLS/SSL 证书来自 Azure Key Vault
  • 运行 Spring Boot 应用程序,其中用于出站连接的 TLS/SSL 证书来自 Azure Key Vault

 重要的

目前,Spring Cloud Azure Certificate starter 4.x 版本不支持 TLS/mTLS,它们仅自动配置 Key Vault 证书客户端。因此,如果要使用 TLS/mTLS,则无法迁移到版本 4.x。

先决条件

 

  • 如果您没有 Azure 订阅,请在开始之前创建一个免费帐户。
  • curl命令。大多数类 UNIX 操作系统都预装了此命令。特定于操作系统的客户端可在官方 curl 网站上获得。
  • jq 命令。大多数类 UNIX 操作系统都预装了此命令。官方 jq 网站上提供了特定于操作系统的客户端。
  • Azure CLI,版本 2.38 或更高版本
  • 受支持的 Java 开发工具包 (JDK),版本 8。有关详细信息,请参阅 Azure 和 Azure Stack 上的 Java 支持。
  • Apache Maven,版本 3.0。

 重要的

完成本文中的步骤需要 Spring Boot 2.5 或更高版本。

使用系统分配的托管标识创建 GNU/Linux VM



使用以下步骤创建具有系统分配的托管标识的 Azure VM,并准备运行 Spring Boot 应用程序。有关 Azure 资源的托管标识的概述,请参阅什么是 Azure 资源的托管标识?。

  • 打开 Bash 外壳。
  • 注销并删除一些身份验证文件以删除任何挥之不去的凭据。
az logout
rm ~/.azure/accessTokens.json
rm ~/.azure/azureProfile.json

 

  • 登录到 Azure CLI。

 

az login

 

  • 设置订阅 ID。请务必将占位符替换为适当的值。

 

az account set -s <your subscription ID>

 

  • 创建 Azure 资源组。记下资源组名称以备后用。

 

az group create \
    --name <your resource group name> \
    --location <your resource group region>

 

  • 设置默认资源组。
az configure --defaults group=<your resource group name>

 

  • 使用 UbuntuServer 提供的映像 UbuntuLTS 创建启用了系统分配的托管标识的 VM 实例。
az vm create \
    --name <your VM name> \
    --debug \
    --generate-ssh-keys \
    --assign-identity \
    --role contributor \
    --scope /subscriptions/<your subscription> \
    --image UbuntuLTS \
    --admin-username azureuser



在 JSON 输出中,记下 publicIpAddress 和 systemAssignedIdentity 属性的值。您将在本教程的后面部分使用这些值。

 笔记

UbuntuLTS 这个名字是统一资源名称 (URN) 的别名,它是为像 UbuntuLTS 这样的流行图像创建的缩写版本。运行以下命令以表格格式显示缓存的流行图像列表:

az vm image list --output table
 
  • 安装微软 OpenJDK。有关 OpenJDK 的完整信息,请参阅 Microsoft Build of OpenJDK。
ssh azureuser@<your VM public IP address>

 

  • 添加存储库。替换以下命令中的版本占位符并执行:
wget https://packages.microsoft.com/config/ubuntu/{version}/packages-microsoft-prod.deb -O packages-microsoft-prod.deb
sudo dpkg -i packages-microsoft-prod.deb



通过运行以下命令安装 Microsoft Build of OpenJDK:

sudo apt install apt-transport-https
sudo apt update
sudo apt install msopenjdk-11

 

创建和配置 Azure Key Vault



使用以下步骤创建 Azure Key Vault,并授予 VM 的系统分配托管标识访问 Key Vault 以获取证书的权限。

在资源组中创建 Azure Key Vault。

az keyvault create \
    --name <your Key Vault name> \
    --location <your resource group region>
export KEY_VAULT_URI=$(az keyvault show --name <your Key Vault name> 
| jq -r '.properties.vaultUri')



记下 KEY_VAULT_URI 值。你稍后会用到它。

  • 授予 VM 使用证书密钥保管库的权限。
az keyvault set-policy \
    --name <your Key Vault name> \
    --object-id <your system-assigned identity> \
    --secret-permissions get list \
    --certificate-permissions get list import



创建并存储自签名 TLS/SSL 证书



本教程中的步骤适用于直接存储在 Azure Key Vault 中的任何 TLS/SSL 证书(包括自签名)。自签名证书不适合在生产中使用,但对开发和测试应用程序很有用。本教程使用自签名证书。要创建证书,请使用以下命令。

az keyvault certificate create \
    --vault-name <your Key Vault name> \
    --name mycert \
    --policy "$(az keyvault certificate get-default-policy)"



使用安全入站连接运行 Spring Boot 应用程序



在本部分中,你将创建一个 Spring Boot 入门应用程序,其中用于入站连接的 TLS/SSL 证书来自 Azure Key Vault。

要创建应用程序,请使用以下步骤:

Project: Maven Project

Language: Java

Spring Boot: 2.7.4

Group: com.contoso (You can put any valid Java package name here.)

Artifact: ssltest (You can put any valid Java class name here.)

Packaging: Jar

Java: 11

 

  • 选择添加依赖项....
  • 在文本字段中,键入 Spring Web 并按 Ctrl+Enter。
  • 在文本字段中键入 Azure Support,然后按 Enter。您的屏幕应如下所示。
  • 带有基本选项的 Spring Initializr 的屏幕截图。

Screenshot of Spring Initializr with basic options.

  • 在页面底部,选择“生成”。
  • 出现提示时,将项目下载到本地计算机上的某个路径。本教程使用当前用户主目录中的 ssltest 目录。上面的值将为您提供该目录中的 ssltest.zip 文件。

启用 Spring Boot 应用程序以加载 TLS/SSL 证书



要使应用程序能够加载证书,请使用以下步骤:

  • 解压缩 ssltest.zip 文件。
  • 删除测试目录及其子目录。本教程忽略测试,因此您可以放心删除该目录。
  • 将 src/main/resources 中的 application.properties 重命名为 application.yml。
  • 文件布局如下所示。



├── HELP.md

├── mvnw

├── mvnw.cmd

├── pom.xml

└── src

    └── main

        ├── java

        │   └── com

        │       └── contoso

        │           └── ssltest

        │               └── SsltestApplication.java

        └── resources

            ├── application.yml

            ├── static

            └── templates

  • 修改 POM 以添加对 azure-spring-boot-starter-keyvault-certificates 的依赖。将以下代码添加到 pom.xml 文件的 <dependencies> 部分。
<dependency>
   <groupId>com.azure.spring</groupId>
   <artifactId>azure-spring-boot-starter-keyvault-certificates</artifactId>
</dependency>

 

  • 编辑 src/main/resources/application.yml 文件,使其具有以下内容。
server:
  ssl:
    key-alias: <the name of the certificate in Azure Key Vault to use>
    key-store-type: AzureKeyVault
    trust-store-type: AzureKeyVault
  port: 8443
azure:
  keyvault:
    uri: <the URI of the Azure Key Vault to use>
  • 这些值使 Spring Boot 应用程序能够执行 TLS/SSL 证书的加载操作,如本教程开头所述。下表描述了属性值。
Property Name Explanation
server.port The local TCP port on which to listen for HTTPS connections.
server.ssl.key-alias The value of the --name argument you passed to az keyvault certificate create.
server.ssl.key-store-type Must be AzureKeyVault.
server.ssl.trust-store-type Must be AzureKeyVault.
azure.keyvault.uri The vaultUri property in the return JSON from az keyvault create. You saved this value in an environment variable.



唯一特定于 Key Vault 的属性是 azure.keyvault.uri。该应用在其系统分配的托管标识已被授予访问 Key Vault 的 VM 上运行。因此,该应用程序也已被授予访问权限。

这些更改使 Spring Boot 应用程序能够加载 TLS/SSL 证书。在下一节中,您将允许应用程序执行 TLS/SSL 证书的接受操作,如本教程开头所述。

创建一个 Spring Boot REST 控制器



要创建 REST 控制器,请使用以下步骤:

  • 编辑 src/main/java/com/contoso/ssltest/SsltestApplication.java 文件,使其具有以下内容。
package com.contoso.ssltest;

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);
    }

}
  1. 从未经身份验证的 REST GET 调用中调用 System.exit(0) 仅用于演示目的。不要在实际应用程序中使用 System.exit(0)。

此代码说明了本教程开头提到的当前操作。以下列表突出显示了有关此代码的一些详细信息:

  • 现在在 Spring Initializr 生成的 SsltestApplication 类上有一个 @RestController 注释。
  • 有一个用@GetMapping 注释的方法,其中包含您将进行的HTTP 调用的值。
  • 当浏览器向 /ssl-test 路径发出 HTTPS 请求时,入站方法只返回一条问候语。 inbound 方法说明了服务器如何向浏览器提供 TLS/SSL 证书。
  • exit 方法将导致 JVM 在被调用时退出。此方法有助于使示例易于在本教程的上下文中运行。
  • 打开一个新的 Bash shell 并导航到 ssltest 目录。运行以下命令。

 

mvn clean package

 

  1. Maven 编译代码并将其打包成可执行的 JAR 文件

验证在 <您的资源组名称> 中创建的网络安全组是否允许来自您的 IP 地址的端口 22 和 8443 上的入站流量。要了解如何配置网络安全组规则以允许入站流量,请参阅创建、更改或删除网络安全组的使用安全规则部分。

  • 将可执行 JAR 文件放在 VM 上。
cd target
sftp azureuser@<your VM public IP address>
put *.jar



在服务器上运行应用程序



现在您已经构建了 Spring Boot 应用程序并将其上传到 VM,请使用以下步骤在 VM 上运行它并使用 curl 调用 REST 端点。

  1. 使用 SSH 连接到 VM,然后运行可执行 jar。
set -o noglob
ssh azureuser@<your VM public IP address> "java -jar *.jar"
  1. 打开一个新的 Bash shell 并执行以下命令以验证服务器是否提供 TLS/SSL 证书。
curl --insecure https://<your VM public IP address>:8443/ssl-test
  1. 调用退出路径以终止服务器并关闭网络套接字。
curl --insecure https://<your VM public IP address>:8443/exit

 

现在您已经看到使用自签名 TLS/SSL 证书加载和呈现操作,您将对应用程序进行一些微不足道的更改以查看接受操作。

使用安全出站连接运行 Spring Boot 应用程序

在本节中,你将修改上一节中的代码,以便出站连接的 TLS/SSL 证书来自 Azure Key Vault。因此,从 Azure Key Vault 中可以满足加载、呈现和接受操作。

修改 SsltestApplication 以说明出站 TLS 连接

 

使用以下步骤修改应用程序:

  • 通过将以下代码添加到 pom.xml 文件的 <dependencies> 部分来添加对 Apache HTTP 客户端的依赖。
<dependency>
   <groupId>org.apache.httpcomponents</groupId>
   <artifactId>httpclient</artifactId>
   <version>4.5.13</version>
</dependency>

 

  • 添加一个名为 ssl-test-outbound 的新 rest 端点。此端点为自身打开一个 TLS 套接字,并验证 TLS 连接是否接受 TLS/SSL 证书。

用以下代码替换 SsltestApplication.java 的内容。

package com.contoso.ssltest;

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);
    }

}
  • 构建应用程序。
cd ssltest
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



您应该会看到消息出站 TLS 正在工作!!。

  • 调用退出路径以终止服务器并关闭网络套接字。
curl --insecure https://<your VM public IP address>:8443/exit

 

你现在已经看到了一个简单的说明,说明了使用存储在 Azure Key Vault 中的自签名 TLS/SSL 证书进行加载、呈现和接受操作。

清理资源



使用完本教程中创建的 Azure 资源后,可以使用以下命令删除它们:

az group delete --name <your resource group name>
SEO Title
Tutorial: Secure Spring Boot apps using Azure Key Vault certificates