使用 Vault 管理密钥

工程 | Mark Paluch | 2016年6月24日 | ...

密码、API 密钥和机密数据都属于密钥的范畴。以安全的方式存储密钥是一项挑战,需要限制访问权限并进行真正的安全存储。让我们看看 Hashicorp Vault 以及如何使用它来存储和访问密钥。

您如何存储密钥?

密码、API 密钥、安全令牌和机密数据都属于密钥的范畴。这些数据不应该随意放置。它不能以明文形式存储在容易猜测的位置。事实上,它不能以明文形式存储在任何位置。

可以使用 Spring Cloud Config ServerTomEE 对敏感数据进行加密。加密数据比未加密数据好一点。加密在另一端强加了用户端解密的需要,这需要分发解密密钥。现在,您将密钥放在哪里?密钥是否受密码保护?您将密码放在哪里?在多少个系统上分发密钥和密码?

如您所见,加密引入了“先有鸡还是先有蛋”的问题。存储解密密钥使应用程序能够解密数据。它也允许攻击向量。未经授权的人员可以通过访问机器来访问解密密钥。此人可以解密此密钥可解密的数据。密钥是静态的,因此泄露的密钥需要更改密钥。需要重新加密数据并更改凭据。无法通过在线措施发现此类泄漏,因为数据一旦获取即可离线解密。

一种方法是在应用程序启动之前将其密钥放在难以猜测的位置,并在将其读取到内存后擦除密钥。密钥可用的时间缩短了。攻击时间范围缩短了,但密钥仍然存在。擦除密钥仅适用于一次应用程序启动。众所周知,云中的容器和微服务在崩溃后会重新启动。应用程序不再可能重启,因为密钥已丢失。

等等,还有希望!

正确执行加密很困难,如果自己动手管理密钥则更加困难。Vault 正确解决了这些问题。它有助于解决“先有鸡还是先有蛋”的问题,并且附带加密功能。Vault 是一种管理密钥的服务。它提供了一个 API,该 API 基于策略授予对密钥的访问权限。API 的任何用户都需要进行身份验证,并且只能查看其有权访问的密钥。Vault 使用 256 位 AESGCM 对数据进行加密。它可以将数据存储在各种后端(文件、Amazon DynamoDB、Consul、etcd 等)。另一个关键方面是 Vault 从不将密钥存储在持久性位置。启动/重新启动 Vault 始终需要一个或多个操作员来解封 Vault。但是,让我们首先从基础知识开始。

Vault 并非所有安全问题的答案。值得查看 Vault 安全模型 文档以了解威胁模型。

要引导 Vault,您需要从 https://www.vaultproject.io/downloads.html 下载二进制文件。Vault 使用 Go 编写,并且为各种平台提供了二进制文件。解压缩下载的文件,您就可以使用 Vault 了。

接下来启动 Vault 服务器。您需要一个配置文件来指定一些选项。

vault.conf

backend "inmem" {
}

listener "tcp" {
  address = "0.0.0.0:8200"
  tls_disable = 1
}

disable_mlock = true

此配置适用于大多数平台,并且可以先尝试使用 Vault 进行一些操作。不要在生产环境中使用它。

使用以下命令启动 Vault:

$ vault server -config vault.conf

Vault 将作为前台进程启动。

恭喜,您已启动 Vault。

现在是打开第二个控制台以使用 Vault 执行管理任务的好时机。Vault 现在以明文模式运行,因为已禁用 TLS/SSL。您需要设置 VAULT_ADDR 环境变量以告知 Vault 客户端使用明文

$ export VAULT_ADDR=http://127.0.0.1:8200

Vault 已启动。在您实际开始使用 Vault 之前,还需要两个额外的步骤。Vault 需要初始化和解封。初始化是初始密钥生成的流程。解封是向 Vault 提供密钥,以便 Vault 可以解密加密数据并开始为客户端提供服务。

Vault 在初始化时会创建两件事

  1. 主密钥和密钥拆分
  2. 根令牌

Vault 允许使用 Shamir 秘密共享 算法共享密钥。数据通常使用一个密钥进行加密。拥有密钥访问权限的人员可以作为个人完全控制所有数据。有时您不希望这样。通常,您希望在多个人之间分发主密钥,以便没有人单独控制所有加密数据。Vault 允许在初始化期间指定密钥份额总数和解封 Vault 所需的密钥份额数。此设置在初始化 Vault 后无法更改。从控制台初始化 Vault 将显示完整密钥。使用 API 进行初始化可能是您希望与 DevOps 工具采用的方法,例如,通过将安全消息发送给应接收密钥份额的操作员。

使用以下命令初始化 Vault:

$ vault init -key-shares=5 -key-threshold=2

Vault 将显示密钥份额和根密钥。请注意,这些值是随机的,并且在每次初始化时都会发生变化。请小心处理该输出,因为您只会看到一次。无法在之后检索密钥和令牌。使用真实数据使用 Vault 时,请仔细阅读说明,否则您将丢失数据。

Key 1: 99eb89735688ad7a29bb1ff27383bd1005a22a62c97f14357ea4f5f98c1d2c8c01
Key 2: 0c5605b16905794a302603bbeb8f6c8ad5ecf7e877f0e29084f838eba931b86902
Key 3: 7f3d88067c7e355acea4fe756a8b23fc6cd6bc671d7cb0f3d2cc8ae543dc3dc303
Key 4: 3d37062e1704ca2a02073b29c097d5a56e7056e710f515c16b40b9cfe3698bb804
Key 5: 4e5c8b99027f863afc85c6e741939ad3d74a1d687a7947a23d740bc109840e1205
Initial Root Token: 9a63de21-8af7-311a-9a5a-151b6a0d4795

Vault initialized with 5 keys and a key threshold of 2. Please
securely distribute the above keys. When the Vault is re-sealed,
restarted, or stopped, you must provide at least 2 of these keys
to unseal it again.

Vault does not store the master key. Without at least 2 keys,
your Vault will remain permanently sealed.

然后,您需要解封 Vault。Vault 不会将密钥存储在磁盘上。它始终存储在内存中。初始化和(重新)启动 Vault 后,您需要使用所需数量的密钥份额来解封 Vault,以便 Vault 可以提供密钥。在本例中,为两个密钥份额。注意:还有一个 seal 命令可以让 Vault 停止提供密钥。

$ vault unseal 99eb89735688ad7a29bb1ff27383bd1005a22a62c97f14357ea4f5f98c1d2c8c01
Sealed: true
Key Shares: 5
Key Threshold: 2
Unseal Progress: 1

$ vault unseal 7f3d88067c7e355acea4fe756a8b23fc6cd6bc671d7cb0f3d2cc8ae543dc3dc303
Sealed: false
Key Shares: 5
Key Threshold: 2
Unseal Progress: 0

解封 Vault 后,您可以开始在 Vault 中存储秘密数据。

从这里开始,Vault 需要经过身份验证的访问权限才能继续。Vault 在其传输层上使用令牌作为通用身份验证。

还记得初始化的输出吗?密钥份额之后的最后一项是根令牌。目前最简单的方法是使用根令牌。在控制台上使用令牌的最简单方法是将其存储在环境变量中

$ export VAULT_TOKEN=9a63de21-8af7-311a-9a5a-151b6a0d4795
$ vault write secret/my-application password=H@rdT0Gu3ss

通用密钥后端允许将任意值作为键值存储进行存储。单个上下文可以存储一个或多个键值元组。上下文可以分层组织,并且使用的数据格式为 JSON。

除了通用密钥后端之外,Vault 还提供其他后端,这些后端允许为 MySQL、SQL Server、PostgreSQL、Consul 和 更多 生成凭据。

身份验证

Vault 主要使用令牌。每个令牌都分配给一个策略,该策略可能会约束操作和路径。策略使用基于路径的匹配来应用规则。令牌可以获取元数据(键值)和分配显示名称,这使得管理更加易于操作。

您可以手动创建令牌并将它们分配给应用程序和用户。除此之外,还有几个 身份验证机制(LDAP、用户名/密码、GitHub 令牌等),允许用户登录并获取令牌。可以撤消令牌和身份验证机制,这使得锁定特定用户变得很容易。

Spring Cloud Vault

Pivotal 团队认为 Vault 是一款很有前景的工具。因此,我们开发了 Spring Cloud Vault。Spring Cloud Vault 是一款类似于 Spring Cloud Config 的配置扩展。Spring Cloud Config 旨在通过存储在各种存储库(如 GitHub、SVN 甚至 Vault)中的数据来实现外部配置管理。

使用 Spring Cloud Vault,您可以在 Vault 中访问您的密钥。密钥会在应用程序启动时获取。Spring Cloud Vault 使用应用程序中的数据(应用程序名称、活动上下文)来确定您存储密钥的上下文路径。

/secret/{application}/{profile}
/secret/{application}
/secret/{defaultContext}/{profile}
/secret/{defaultContext}

Spring Cloud Vault 入门

首先,您需要一个 Spring Boot 项目。 start.spring.io 是一个很好的起点。任何空项目都足够。

在您的项目中包含 Spring Cloud Vault 启动器

将以下代码添加到您的构建配置文件中。这些行包含 Spring Cloud Vault 的启动器以及所有必需的依赖项。

Maven

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-vault-starter-config</artifactId>
    <version>1.0.0.BUILD-SNAPSHOT</version>
</dependency>

<repositories>
    <repository>
        <id>spring-snapshots</id>
        <name>Spring Snapshots</name>
        <url>https://repo.spring.io/libs-snapshot</url>
        <snapshots>
            <enabled>true</enabled>
        </snapshots>
    </repository>
</repositories>

Gradle

repositories {
    maven {
        url 'https://repo.spring.io/libs-snapshot'
    }
}

dependencies {
    compile("org.springframework.cloud:spring-cloud-vault-starter-config:1.0.0.BUILD-SNAPSHOT")
}

使用SNAPSHOT依赖项时,请确保包含快照存储库。

设置配置

Spring Cloud Vault 默认使用application作为默认上下文,并使用spring.application.name的值作为应用程序上下文。所有配置都需要在引导配置中指定。在此示例中,我们在src/main/resources中使用bootstrap.yml

spring:
    application:
        name: my-application
    cloud:
        vault:
            token: 9a63de21-8af7-311a-9a5a-151b6a0d4795
            scheme: http

spring.cloud.vault.scheme设置为http,因为我们已在纯文本 HTTP 模式下启动 Vault。不要在生产环境中这样做。纯文本会使整个密钥故事毫无用处,因为网络上的所有侦听器都可以看到您的密钥。spring.cloud.vault.scheme默认为https

请注意,此处的令牌取自根令牌。您可以使用以下命令创建新的令牌:

$ vault token-create
Key            	Value
---            	-----
token          	728d26ae-53a6-d8b6-d7a0-c5f62238ea55
token_accessor 	2fd7dcba-39d0-04d3-8d6b-096c3529cf14
token_duration 	0
token_renewable	true
token_policies 	[root]

将数据写入 Vault

将一些数据写入 Vault

$ vault write secret/my-application password=H@rdT0Gu3ss

更新您的 Spring Boot 应用程序

现在转到您的应用程序启动器类,并对其进行增强以注入密钥。使用与写入 Vault 时相同的属性名称。

package example;

import javax.annotation.PostConstruct;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;

@SpringBootApplication
public class SpringBootVaultHelloWorldApplication {

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

    @Value("${password}")
    String password;

    @PostConstruct
    private void postConstruct() {
        System.out.println("My password is: " + password);
    }
}

所有其他事项都由 Spring Cloud Vault 本身处理。现在运行您的应用程序。

恭喜,您成功了!

展望

Spring Cloud Vault 目前位于 Cloud Incubator 中。它支持令牌和 AppId 身份验证。Spring Cloud Vault 带有一个启动器和各种数据库集成以及 RabbitMQ/Consul 支持的依赖项。您可以在 https://github.com/spring-cloud-incubator/spring-cloud-vault-config 查看项目和 文档

我们准备了一些示例,让您了解如何将 Spring Cloud Vault 集成到您的应用程序中。您可以在 https://github.com/mp911de/spring-cloud-vault-config-samples 找到这些示例。

我们还没有关于何时发布 Spring Cloud Vault 的时间表。我们邀请您参加 Spencer GibbSpringOne Platform 2016 上关于 Spring Cloud 与 Consul 和 Vault 的演讲,或参加我的演讲,了解如何 大规模管理密钥。我们期待您的反馈。

感谢 Alex Soto 向我展示了 Vault。Vault 由 HashiCorp 开发,HashiCorp 还开发了 Vagrant、Consul 等其他优秀工具。

获取 Spring 新闻通讯

关注 Spring 新闻通讯

订阅

领先一步

VMware 提供培训和认证,帮助您快速提升技能。

了解更多

获取支持

Tanzu Spring 通过一个简单的订阅提供 OpenJDK™、Spring 和 Apache Tomcat® 的支持和二进制文件。

了解更多

即将举行的活动

查看 Spring 社区中所有即将举行的活动。

查看全部