在 Spring Boot 应用程序中从Azure 密钥保管库加载机密

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

先决条件

重要

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

将机密存储到Azure 密钥保管库

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

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

注意

设置机密后,按照 Assign a 密钥保管库 访问策略中的说明授予应用对密钥保管库的访问权限。

从Azure 密钥保管库读取机密

现在,数据库凭据已存储在密钥保管库中,可以使用 Spring Cloud Azure检索它们。

若要安装 Spring Cloud Azure 密钥保管库 Starter 模块,请将以下依赖项添加到 pom.xml 文件中:

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

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

    注意

    如果使用 Spring Boot 4.0.x,请确保将 spring-cloud-azure-dependencies 版本设置为 7.2.0

    如果使用 Spring Boot 3.5.x,请确保将 spring-cloud-azure-dependencies 版本设置为 6.2.0

    如果使用 Spring Boot 3.1.x-3.5.x,请确保将 spring-cloud-azure-dependencies 版本设置为 5.25.0

    如果使用 Spring Boot 2.x,请确保将 spring-cloud-azure-dependencies 版本设置为 4.20.0

    应在 <dependencyManagement> 文件的 部分中配置此材料清单(BOM)。 这可确保所有 Spring Cloud Azure依赖项都使用相同的版本。

    有关用于此 BOM 的版本的详细信息,请参阅 我应该使用哪个 Spring Cloud Azure 版本

  • Spring Cloud Azure 密钥保管库 Starter 项目:

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

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

  • 将Azure SDK用于密钥保管库。
  • 使用 Spring KeyVault PropertySource

将Azure SDK用于密钥保管库

密钥保管库的Azure SDK提供 SecretClient 来管理密钥保管库中的机密。

下面的代码示例演示如何使用 SecretClient 从Azure 密钥保管库检索 H2 数据库凭据。

若要使用Azure SDK从密钥保管库读取机密,请执行以下步骤配置应用程序:

  1. application.properties 配置文件中配置密钥保管库终结点。

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

}

以下列表显示了此代码不够灵活或不够优雅的一些原因:

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

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

Spring Cloud Azure还为不同的方案提供以下全局配置。 欲了解更多信息,请参阅Azure 服务 SDK 的 Global 配置Spring Cloud Azure 开发人员指南部分。

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

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

使用 Spring 密钥保管库 PropertySource

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

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

下面的代码示例演示如何使用 PropertySource 检索 H2 数据库凭据,以便从Azure 密钥保管库生成数据源。

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

  1. 将以下密钥保管库终结点和数据源属性添加到 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 开发人员指南Configuration 示例部分。

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

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

    import jakarta.persistence.Entity;
    import jakarta.persistence.GeneratedValue;
    import jakarta.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. 启动应用程序。 应用程序将从密钥保管库检索 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

后续步骤

适用于 Spring 开发人员的 AzureSpring Cloud Azure KeyVault 示例