领先一步
VMware 提供培训和认证,助你加速进步。
了解更多密码、API 密钥和机密数据属于 secrets(机密数据)的范畴。以安全的方式存储 secrets 是一项挑战,需要限制访问并实现真正的安全存储。让我们看看 Hashicorp 的 Vault,以及如何使用它来存储和访问 secrets。
密码、API 密钥、安全令牌和机密数据属于 secrets 的范畴。这些数据不应随意存放。它们绝不能以明文形式存在于容易猜测的位置。事实上,它们绝不能以明文形式存储在任何位置。
敏感数据可以使用 Spring Cloud Config Server 或 TomEE 进行加密。加密数据比未加密数据更好一步。加密的另一面是用户端需要解密,这需要分发解密密钥。那么,你把密钥放在哪里?密钥是否由密码保护?你把密码放在哪里?你将密钥和密码分发到多少系统上?
正如你所见,加密引入了一个先有鸡还是先有蛋的问题。存储解密密钥使得应用程序能够解密数据。这也提供了一个攻击向量。未经授权的人员可以通过访问机器来获取解密密钥。该人员可以解密此密钥可解密的数据。密钥是静态的,因此密钥泄露需要更改密钥。数据需要重新加密,凭据需要更改。无法通过在线措施发现此类泄露,因为一旦数据被获取,就可以离线解密。
一种方法是在应用程序启动前将密钥放在难以猜测的位置,并在将密钥读入内存后立即擦除。密钥可用的时间被缩短。攻击时间范围也随之缩短,但密钥仍然存在过。擦除密钥仅适用于一次应用程序启动。云中的容器和微服务在崩溃后已知会重新启动。由于密钥已丢失,应用程序无法再重新启动。
正确地进行加密很困难,如果自己管理 secrets 则更难。Vault 正是解决了这些问题。它有助于解决先有鸡还是先有蛋的问题,并且自带加密功能。Vault 是一个管理 secrets 的服务。它提供了一个基于策略访问 secrets 的 API。任何使用 API 的用户都需要认证,并且只能看到其被授权访问的 secrets。Vault 使用带有 GCM 的 256 位 AES 对数据进行加密。它可以将数据存储在各种后端(文件、Amazon DynamoDB、Consul、etcd 等等)。另一个关键方面是 Vault 绝不将密钥存储在持久位置。启动/重启 Vault 始终需要一个或多个操作员来解封 (unseal) Vault。不过,我们先从基础知识开始。
Vault 并非所有安全问题的答案。值得查看 Vault 安全模型文档,以了解其威胁模型。
要启动 Vault,你需要从 https://www.vaultproject.io/downloads.html 下载二进制文件。Vault 用 Go 语言编写,并为各种平台提供了二进制文件。解压下载的文件即可开始使用 Vault。
接下来启动 Vault Server。你需要一个配置文件来指定一些选项。
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 需要被初始化 (initialized) 并解封 (unsealed)。初始化是初始密钥生成的过程。解封是向 Vault 提供密钥,以便 Vault 可以解密加密数据并开始为客户端提供服务。
Vault 在初始化时创建两样东西
Vault 允许使用 Shamir Secret Sharing 算法进行密钥共享。数据通常用一个密钥加密。拥有密钥的人作为单个人拥有对所有数据的完全控制。有时你不希望这样。通常你希望将主密钥分发给多个人,这样任何单个人都无法控制你所有加密的数据。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.
然后你需要解封 (unseal) Vault。Vault 不会将密钥存储在磁盘上。它始终存储在内存中。在初始化后以及(重新)启动 Vault 后,你需要使用所需数量的密钥分片来解封 Vault,以便 Vault 可以提供 secrets 服务。在这种情况下是两个密钥分片。注意:还有一个 seal 命令可以使 Vault 停止提供 secrets 服务。
$ 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
通用 secret 后端允许将任意值存储为键值存储。单个上下文可以存储一个或多个键值对。上下文可以分层组织,使用的数据格式为 JSON。
除了通用 secret 后端,Vault 还提供了其他后端,可以为 MySQL、SQL Server、PostgreSQL、Consul 和 更多生成凭据。
Vault 主要通过令牌工作。每个令牌都分配给一个策略,该策略可以约束操作和路径。策略使用基于路径的匹配来应用规则。令牌可以被分配元数据(键值对)和显示名称,这使得管理更加运维友好。
你可以手动创建令牌并将其分配给应用程序和用户。除此之外,还有一些 认证机制(LDAP、用户名/密码、GitHub 令牌等),允许用户登录并获取令牌。令牌和认证机制可以被撤销,这使得锁定特定用户变得容易。
我们 Pivotal 的团队对 Vault 进行了研究,并认为它是一个很有前景的工具。因此,我们构建了 Spring Cloud Vault。Spring Cloud Vault 是一个类似于 Spring Cloud Config 的配置扩展。Spring Cloud Config 目标是外部配置管理,数据存储在各种仓库中,如 GitHub、SVN 甚至 Vault。
使用 Spring Cloud Vault,你可以访问 Vault 中的 secrets。secrets 在应用程序启动时被获取。Spring Cloud Vault 使用你的应用程序数据(应用程序名称、活动上下文)来确定存储 secrets 的上下文路径。
/secret/{application}/{profile}
/secret/{application}
/secret/{defaultContext}/{profile}
/secret/{defaultContext}
首先,你需要一个 Spring Boot 项目。start.spring.io 是一个不错的起点。任何空白项目都可以。
将以下代码添加到你的构建配置文件中。这些行包含了 Spring Cloud Vault 的 starter 以及所有必需的依赖项。
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
依赖项时,请确保包含 Snapshots 仓库。
Spring Cloud Vault 默认使用 application
作为默认上下文,并使用 spring.application.name
的值作为应用程序上下文。所有配置都需要在 bootstrap 配置中指定。对于本示例,我们在 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。生产环境中请勿这样做。明文会使整个 secret 管理失去意义,因为网络上的所有监听者都可以看到你的 secrets。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 write secret/my-application password=H@rdT0Gu3ss
现在转到你的应用程序启动类,并对其进行增强以注入 secret。使用与写入 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 中。它支持 Token 和 AppId 认证。Spring Cloud Vault 附带了一个 starter 以及用于各种数据库集成和 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 的发布时间表。欢迎你参加 SpringOne Platform 2016 上 Spencer Gibb 关于 结合 Consul 和 Vault 使用 Spring Cloud 的演讲,或我的演讲,了解如何大规模管理 Secrets。我们期待你的反馈。
感谢 Alex Soto 向我展示了 Vault。Vault 是由 Hashicorp 开发的,他们是创建了 Vagrant、Consul 和其他优秀工具的公司。