SpringBoot 2 使用 SpringVault 配置来访问 HashiCorp Vault

开篇词

该指南将引导你使用 Spring Vault 构建可从密钥管理工具 HashiCorp Vault 加载加密数据的应用。
 

你将创建的应用

我们将加载存储在 Vault 中的加密数据,并使用传输加密后端。
 

你将需要的工具

如何完成这个指南

像大多数的 Spring 入门指南一样,你可以从头开始并完成每个步骤,也可以绕过你已经熟悉的基本设置步骤。如论哪种方式,你最终都有可以工作的代码。

  • 要从头开始,移步至用 Gradle 来构建
  • 要跳过基础,执行以下操作:
    • 下载并解压缩该指南将用到的源代码,或借助 Git 来对其进行克隆操作:git clone https://github.com/spring-guides/gs-accessing-vault.git
    • 切换至 gs-accessing-vault/initial 目录;
    • 跳转至该指南的安装并启动 HashiCorp Vault

待一切就绪后,可以检查一下 gs-accessing-vault/complete 目录中的代码。
 

用 Gradle 来构建

首先,我们设置一个基本的构建脚本。在使用 Spring 构建应用时可以使用任何喜欢的构建系统,但此处包含使用 GradleMaven 所需的代码。如果你都不熟悉,请参阅使用 Gradle 构建 Java 项目使用 Maven 构建 Java 项目

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

创建 Gradle 构建文件

以下是初始 Gradle 构建文件。
build.gradle

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.2.1.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'gs-accessing-vault'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

ext {
    springCloudVersion = 'Greenwich.SR2'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile('org.springframework.cloud:spring-cloud-starter-vault-config')
    testCompile("org.springframework.boot:spring-boot-starter-test")
}

dependencyManagement {
    imports {
        mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
    }
}

Spring Boot gradle 插件提供了许多方便的功能:

  • 它收集类路径上的所有 jar,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法并将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用于设置版本号以及匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。
     

用 Maven 来构建

首先,我们搭建一个基本的构建脚本。使用 Spring 构建应用时,可以使用任何喜欢的构建系统,但是此处包含了使用 Maven 所需的代码。如果你不熟悉 Maven,请参阅使用 Maven 构建 Java 项目

创建目录结构

在我们选择的项目目录中,创建以下自目录结构;例如,在 *nix 系统上使用 mkdir -p src/main/java/hello

└── src
    └── main
        └── java
            └── hello

创建 Maven 构建文件

以下是初始 Maven 构建文件。
pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>org.springframework</groupId>
    <artifactId>gs-accessing-vault</artifactId>
    <version>0.1.0</version>

    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>

    <properties>
        <java.version>1.8</java.version>
        <spring-cloud.version>Greenwich.SR2</spring-cloud.version>
    </properties>

    <dependencies>

        <!-- Vault Starter -->
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-vault-config</artifactId>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.cloud</groupId>
                <artifactId>spring-cloud-dependencies</artifactId>
                <version>${spring-cloud.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
            </plugin>
        </plugins>
    </build>

</project>

Spring Boot Maven 插件提供了许多方便的功能:

  • 它收集类路径上的所有 jar,并构建一个可运行的单个超级 jar,这使执行和传输服务更加方便;
  • 它搜索 public static void main() 方法并将其标记为可运行类;
  • 它提供了一个内置的依赖解析器,用于设置版本号以及匹配 Spring Boot 依赖。我们可以覆盖所需的任何版本,但默认为 Boot 选择的一组版本。
     

用 IDE 来构建

安装并启动 HashiCorp Vault

完成项目的搭建后,我们可以安装和启动 HashiCorp Vault。

如果我们使用的是带有 hombrew 的 Mac,则操作非常简单:

brew install vault

或者,从 https://www.vaultproject.io/downloads.html 下载适用于我们的操作系统的 Vault:

https://releases.hashicorp.com/vault/1.2.1/vault_1.2.1_darwin_amd64.zip
unzip vault_1.2.1_darwin_amd64.zip

对于其他具有软件包管理的系统,例如 Redhat、Ubuntu、Debian、CentOS 和 Windows,请参阅 https://www.vaultproject.io/docs/install/index.html 上的说明。

安装 Vault 之后,在控制台窗口中启动它。该命令还会启动服务器进程。

vault server --dev --dev-root-token-id="00000000-0000-0000-0000-000000000000"

我们应该在最后一行看到以下内容:

[INFO ] core: post-unseal setup complete

上面的命令在不使用传输加密的情况下使用内存存储以开发模式启动 Vault。这适合在本地评估 Vault。确保使用适当的 SSL 证书和可靠的存储后端共生产使用。有关更多详细信息,请查阅 Vault 的生产强化指南

存储密钥至 Vault

Vault 是一个加密数据管理系统,可让我们存储敏感的数据,这些数据在静态时被加密。理想的是存储敏感的配置详细信息,例如密码、加密密钥、API 密钥。

启动另一个控制台窗口,以使用 Vault 命令行将应用配置存储在 Vault 中。

首先,我们需要设置两个环境变量以将 Vault CLI 指向 Vault 端点并提供身份验证令牌。

export export VAULT_TOKEN="00000000-0000-0000-0000-000000000000"
export VAULT_ADDR="http://127.0.0.1:8200"

现在,我们可以在 Vault 中存储配置键值对:

vault kv put secret/github github.oauth2.key=foobar

配置应用

在这里,我们可以使用 bootstrap.properties 配置应用。Spring Cloud Vault 使用引导上下文配置。

src/main/resources/bootstrap.properties

spring.cloud.vault.token=00000000-0000-0000-0000-000000000000
spring.cloud.vault.scheme=http

创建应用类

在这里,我们将创建一个具有所有组件的 Application 类。

src/main/java/hello/Application.java

package hello;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.vault.core.VaultKeyValueOperationsSupport.KeyValueBackend;
import org.springframework.vault.core.VaultSysOperations;
import org.springframework.vault.core.VaultTemplate;
import org.springframework.vault.core.VaultTransitOperations;
import org.springframework.vault.support.VaultMount;
import org.springframework.vault.support.VaultResponse;

@SpringBootApplication
public class Application implements CommandLineRunner {

  @Autowired
  private VaultTemplate vaultTemplate;

  public static void main(String[] args) {
    SpringApplication.run(Application.class, args);
  }

  @Override
  public void run(String... strings) throws Exception {

    // You usually would not print a secret to stdout
    VaultResponse response = vaultTemplate
        .opsForKeyValue("secret", KeyValueBackend.KV_2).get("github");
    System.out.println("Value of github.oauth2.key");
    System.out.println("-------------------------------");
    System.out.println(response.getData().get("github.oauth2.key"));
    System.out.println("-------------------------------");
    System.out.println();

    // Let's encrypt some data using the Transit backend.
    VaultTransitOperations transitOperations = vaultTemplate.opsForTransit();

    // We need to setup transit first (assuming you didn't set up it yet).
    VaultSysOperations sysOperations = vaultTemplate.opsForSys();

    if (!sysOperations.getMounts().containsKey("transit/")) {

      sysOperations.mount("transit", VaultMount.create("transit"));

      transitOperations.createKey("foo-key");
    }

    // Encrypt a plain-text value
    String ciphertext = transitOperations.encrypt("foo-key", "Secure message");

    System.out.println("Encrypted value");
    System.out.println("-------------------------------");
    System.out.println(ciphertext);
    System.out.println("-------------------------------");
    System.out.println();

    // Decrypt

    String plaintext = transitOperations.decrypt("foo-key", ciphertext);

    System.out.println("Decrypted value");
    System.out.println("-------------------------------");
    System.out.println(plaintext);
    System.out.println("-------------------------------");
    System.out.println();
  }
}

Spring Cloud Vault 使用 VaultOperations 与 Vault 进行交互。Vault 中的属性被映射到 MyConfiguration 以进行类型安全的访问。@EnableConfigurationProperties(MyConfiguration.class) 启用配置属性映射并注册 MyConfiguration bean。

Application 包括 main() 方法,该方法自动装配 MyConfiguration 的实例。
 

构建可执行 JAR

我们可以结合 Gradle 或 Maven 来从命令行运行该应用。我们还可以构建一个包含所有必须依赖项、类以及资源的可执行 JAR 文件,然后运行该文件。在整个开发生命周期中,跨环境等等情况下,构建可执行 JAR 可以轻松地将服务作为应用进行发布、版本化以及部署。

如果使用 Gradle,则可以借助 ./gradlew bootRun 来运行应用。或通过借助 ./gradlew build 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar build/libs/gs-accessing-vault-0.1.0.jar

如果使用 Maven,则可以借助 ./mvnw spring-boot:run 来运行该用。或可以借助 ./mvnw clean package 来构建 JAR 文件,然后运行 JAR 文件,如下所示:

java -jar target/gs-accessing-vault-0.1.0.jar

由官网提供的以上这条命令的执行结果与我本地的不一样,我需要这样才能运行:java -jar target/accessing-vault-0.0.1-SNAPSHOT.jar

我们还可以将 JAR 应用转换成 WAR 应用

当我们的 Applictaion 实现 CommandLineRunner 时,启动时会自动调用 run 方法。我们应该会看到以下内容:

Value of github.oauth2.key
-------------------------------
foobar
-------------------------------

Encrypted value
-------------------------------
vault:v1:2wgVE2PXiR9o55xbyur5KHJl8IwyGDkDU4l1SZScUq6BuqZYgTopwvc4
-------------------------------

Decrypted value
-------------------------------
Secure message
-------------------------------

Vault 的加密后段与使用 URI 识别文档的文档存储相比非常好。文档基于 JSON,可方便地对 Vault 数据进行对象映射。

概述

恭喜你!我们搭建了一个 Vault 服务器,并编写了一个简单的应用,该应用使用 Spring Vault 读取密码并使用强大的暗号对数据进行加密 - 所有这些密钥管理、暗号模式及填充都无需去费心实现。
 

想看指南的其他内容?请访问该指南的所属专栏:《Spring 官方指南

发布了224 篇原创文章 · 获赞 13 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/stevenchen1989/article/details/104899816