在 Spring Boot 应用程序中从 Azure Key Vault 加载机密

本教程介绍如何在 Spring Boot 应用程序中使用 Key Vault 来保护敏感配置数据并从 Key Vault 检索配置属性。 Key Vault 提供了安全的通用存储机密,例如密码和数据库连接字符串。

先决条件

重要

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

为 Azure Key Vault 设置机密

本教程介绍如何从 Spring Boot 应用程序中的 Key Vault 读取数据库凭据。 若要从 Key Vault 读取凭据,应首先将数据库凭据存储在 Key Vault 中。

若要将 H2 数据库的 URL 作为新机密存储在 Key Vault 中,请参阅快速入门:使用 Azure 门户在 Azure Key Vault 中设置和检索机密。 在本教程中,你将设置一个名为 h2url、值为 jdbc:h2:~/testdb;user=sa;password=password 的机密。

注意

设置机密后,按照分配 Key Vault 访问策略中的说明授予应用对 Key Vault 的访问权限。

从 Azure Key Vault 读取机密

现在,数据库凭据已存储在 Key Vault 中,可以使用 Spring Cloud Azure 检索它们。

要安装 Spring Cloud Azure Key Vault Starter 模块,请将以下依赖项添加到 pom.xml 文件:

  • Spring Cloud Azure 物料清单 (BOM):

    <dependencyManagement>
      <dependencies>
        <dependency>
          <groupId>com.azure.spring</groupId>
          <artifactId>spring-cloud-azure-dependencies</artifactId>
          <version>5.19.0</version>
          <type>pom</type>
          <scope>import</scope>
        </dependency>
      </dependencies>
    </dependencyManagement>
    

    注意

    如果使用 Spring Boot 2.x,请确保将 spring-cloud-azure-dependencies 版本设置为 4.19.0。 此物料清单 (BOM) 应在 pom.xml 文件的 <dependencyManagement> 部分进行配置。 这可确保所有 Spring Cloud Azure 依赖项都使用相同的版本。 有关用于此 BOM 的版本的详细信息,请参阅应使用哪个版本的 Spring Cloud Azure

  • Spring Cloud Azure Key Vault Starter 项目:

    <dependency>
      <groupId>com.azure.spring</groupId>
      <artifactId>spring-cloud-azure-starter-keyvault</artifactId>
    </dependency>
    

Spring Cloud Azure 有多种从 Key Vault 读取机密的方法。 可以单独使用以下方法,也可以将它们组合用于不同的用例:

  • 使用 Azure SDK for Key Vault。
  • 使用 Spring KeyVault PropertySource

使用 Azure SDK for Key Vault

Azure SDK for Key Vault 提供 SecretClient 用于管理 Key Vault 中的机密。

以下代码示例演示如何使用 SecretClient 从 Azure Key Vault 检索 H2 数据库凭据。

若要使用 Azure SDK 从 Key Vault 读取机密,请按照以下步骤配置应用程序:

  1. application.properties 配置文件中配置 Key Vault 终结点。

    spring.cloud.azure.keyvault.secret.endpoint=https://<your-keyvault-name>.vault.azure.net/
    
  2. 在 Spring 应用程序中注入 SecretClient bean,并使用 getSecret 方法检索机密,如以下示例所示:

    import com.azure.security.keyvault.secrets.SecretClient;
    import org.springframework.boot.CommandLineRunner;
    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    
    @SpringBootApplication
    public class SecretClientApplication implements CommandLineRunner {
    
        // Spring Cloud Azure will automatically inject SecretClient in your ApplicationContext.
        private final SecretClient secretClient;
    
        public SecretClientApplication(SecretClient secretClient) {
            this.secretClient = secretClient;
        }
    
        public static void main(String[] args) {
            SpringApplication.run(SecretClientApplication.class, args);
        }
    
        @Override
        public void run(String... args) {
            System.out.println("h2url: " + secretClient.getSecret("h2url").getValue());
        }
    }
    

    提示

    在本教程中,配置或代码中没有身份验证操作。 但连接到 Azure 服务需要进行身份验证。 要完成身份验证,需要使用 Azure 标识。 Spring Cloud Azure 使用 Azure 标识库提供的 DefaultAzureCredential 来帮助获取凭据,而无需更改任何代码。

    DefaultAzureCredential 支持多种身份验证方法,并确定应在运行时使用哪种方法。 通过这种方法,你的应用可在不同环境(例如本地与生产环境)中使用不同的身份验证方法,而无需实现特定于环境的代码。 有关详细信息,请参阅 DefaultAzureCredential

    若要在本地开发环境中完成身份验证,可以使用 Azure CLI、Visual Studio Code、PowerShell 或其他方法。 有关详细信息,请参阅 Java 开发环境中的 Azure 身份验证。 若要在 Azure 托管环境中完成身份验证,建议使用用户分配的托管标识。 有关详细信息,请参阅什么是 Azure 资源的托管标识?

  3. 启动应用程序。 将会看到类似于以下示例的日志:

    h2url: jdbc:h2:~/testdb;user=sa;password=password
    

你可以自己构建 SecretClient bean,但这个过程很复杂。 在 Spring Boot 应用程序中,必须管理属性、了解生成器模式,并将客户端注册到 Spring 应用程序上下文。 以下代码示例演示如何生成 SecretClient bean:

import com.azure.identity.DefaultAzureCredentialBuilder;
import com.azure.security.keyvault.secrets.SecretClient;
import com.azure.security.keyvault.secrets.SecretClientBuilder;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class SecretClientConfiguration {

    @Bean
    public SecretClient createSecretClient() {
        return new SecretClientBuilder()
            .vaultUrl("https://<your-key-vault-url>.vault.azure.net/")
            .credential(new DefaultAzureCredentialBuilder().build())
            .buildClient();
    }

}

以下列表显示了此代码不灵活或正常的原因:

  • Key Vault 终结点已硬编码。
  • 如果使用 @Value 从 Spring 环境获取配置,则 application.properties 文件中不能有 IDE 提示。
  • 如果有微服务方案,则必须复制每个项目中的代码,这很容易出错,也很难保持一致。

幸运的是,使用 Spring Cloud Azure 不需要自行构建 SecretClient bean。 相反,可以直接注入 SecretClient,并使用已熟悉的配置属性来配置 Key Vault。 有关详细信息,请参阅配置示例

Spring Cloud Azure 还为不同方案提供以下全局配置。 有关详细信息,请参阅 Spring Cloud Azure 开发人员指南Azure 服务 SDK 的全局配置部分。

  • 代理选项。
  • 重试选项。
  • HTTP 传输客户端选项。

还可以连接到不同的 Azure 云。 有关详细信息,请参阅连接到不同的 Azure 云

使用 Spring Key Vault PropertySource

前面的部分介绍了如何在应用程序启动后使用 CommandLineRunner 中的 SecretClient 读取机密。 但是,在 Spring Boot 应用程序中,在应用程序启动之前需要读取机密。 例如,在应用程序启动之前,数据源密码属性是必需的。 如果想要将数据源密码存储在 Key Vault 中,并且仍使用 Spring 自动配置来获取数据源,则前面的方案将不起作用。

在这种情况下,Spring Cloud Azure 提供 Spring 环境集成,用于在生成应用程序上下文之前从 Key Vault 加载机密。 可以在 Spring 应用程序上下文初始化期间使用机密来构造和配置 bean。 此方法是从 Key Vault 访问机密的透明方式,不需要更改代码。

以下代码示例演示如何使用 PropertySource 检索 H2 数据库凭据,以从 Azure Key Vault 生成数据源。

若要从 Key Vault 检索 H2 数据库的 URL,并使用 Spring Data JPA 存储 H2 数据库中的数据,请执行以下步骤配置应用程序:

  1. 将以下 Key Vault 终结点和数据源属性添加到 application.properties 配置文件。

    logging.level.org.hibernate.SQL=DEBUG
    
    spring.cloud.azure.keyvault.secret.property-sources[0].endpoint=https://<your-keyvault-name>.vault.azure.net/
    spring.datasource.url=${h2url}
    
    spring.jpa.hibernate.ddl-auto=create-drop
    spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
    

    提示

    有关 Spring Cloud Azure 属性配置的示例,请参阅 Spring Cloud Azure 开发人员指南配置示例部分。

    提示

    此示例是使用 H2 数据库的简单数据库方案。 建议在生产环境中使用 Azure Database for MySQL 或 Azure Database for PostgreSQL,并将数据库 URL、用户名和密码存储在 Azure Key Vault 中。 如果想要避免密码,则无密码连接是一个不错的选择。 有关详细信息,请参阅 Azure 服务的无密码连接

  2. 新建一个新 Todo Java 类。 此类是映射到 JPA 自动创建的 todo 表上的域模型。 下面的代码忽略 getterssetters 方法。

    import javax.persistence.Entity;
    import javax.persistence.GeneratedValue;
    import javax.persistence.Id;
    
    @Entity
    public class Todo {
    
        public Todo() {
        }
    
        public Todo(String description, String details, boolean done) {
            this.description = description;
            this.details = details;
            this.done = done;
        }
    
        @Id
        @GeneratedValue
        private Long id;
    
        private String description;
    
        private String details;
    
        private boolean done;
    
    }
    
  3. 编辑启动类文件以显示以下内容。

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.boot.context.event.ApplicationReadyEvent;
    import org.springframework.context.ApplicationListener;
    import org.springframework.context.annotation.Bean;
    import org.springframework.data.jpa.repository.JpaRepository;
    
    import java.util.stream.Stream;
    
    @SpringBootApplication
    public class KeyvaultApplication {
    
        public static void main(String[] args) {
            SpringApplication.run(KeyvaultApplication.class, args);
        }
    
        @Bean
        ApplicationListener<ApplicationReadyEvent> basicsApplicationListener(TodoRepository repository) {
            return event->repository
                .saveAll(Stream.of("A", "B", "C").map(name->new Todo("configuration", "congratulations, you have set up "
                    + "correctly!", true)).toList())
                .forEach(System.out::println);
        }
    
    }
    
    interface TodoRepository extends JpaRepository<Todo, Long> {
    
    }
    
  4. 启动应用程序。 应用程序将从 Key Vault 检索 H2 数据库的 URL,然后连接到 H2 数据库,并将数据存储到数据库。 将会看到类似于以下示例的日志:

    2023-01-13 15:51:35.498 DEBUG 5616 --- [main] org.hibernate.SQL: insert into todo (description, details, done, id) values (?, ?, ?, ?)
    com.contoso.keyvault.Todo@1f
    

部署到 Azure Spring Apps

现在,你已在本地运行 Spring Boot 应用程序,是时候将其转移到生产环境了。 借助 Azure Spring Apps,可以轻松地将 Spring Boot 应用程序部署到 Azure,不需更改任何代码。 该服务管理 Spring 应用程序的基础结构,让开发人员可以专注于代码。 Azure Spring Apps 可以通过以下方法提供生命周期管理:综合性监视和诊断、配置管理、服务发现、CI/CD 集成、蓝绿部署等。 若要将应用程序部署到 Azure Spring Apps,请参阅在 Azure Spring Apps 中部署你的第一个应用程序

后续步骤