什么是 Vault

用 Thoughtworks 技术雷达的描述:

在企业级应用开发过程中,团队每时每刻都需要管理各种各样的私密信息,从个人的登陆密码、到生产环境的 SSH Key 以及数据库登录信息、API 认证信息等。通常的做法是将这些机密信息保存在某个文件中,并且放置到 git 之类的源代码管理工具中。个人和应用可以通过拉取仓库来访问这些信息。但这种方式弊端很多,比如跨团队分享存在安全隐患、文件格式难以维护、私密信息难以回收等。 尤其是在微服务如此风靡的今天,如何让开发者添加私密信息、应用程序能轻松的获取私密信息、采用不同策略更新私密信息、适时回收私密信息等变得越来越关键。所以企业需要一套统一的接口来处理私密信息的方方面面,而 HashiCorp Vault 就是这样的一款工具。

简单来说,在我们日常的工作中,免不了要和许多的机密信息打交道,可以是云服务的 Access Key 和 Secret Key,也可以是生产服务器的证书、SSH 口令、证书,或者数据库的用户名密码。以往在工作中我们经常面临着这样的问题:

  • 执行密码轮换策略很痛苦
  • 掌握机密的员工离职后可能泄密或是恶意报复
  • 开发者不小心把机密信息随着代码上传到公网的源码仓库造成泄密
  • 管理多个系统的机密非常麻烦
  • 需要将机密信息安全地加密后存储,但又不想将密钥暴露给应用程序,以防止应用程序被入侵后连带密钥一起泄漏

Vault 就是用来解决这些问题的利器。

一个AWS的例子

考虑一个最简单的 Terraform 脚本:

variable "access_key" {}
variable "secret_key" {}

provider "aws" {
  region = "us-east-1"
  access_key = var.access_key
  secret_key = var.secret_key
}

如果我们运行这段 Terraform 的话:

$ terraform apply
var.access_key
  Enter a value: AKIAZXN6JNH5KFERRZNM

var.secret_key
  Enter a value: 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


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc.example will be created
......

糟了!为了向读者们演示这个例子,我不小心把我的 AWS Access Key 和 Secret Key 暴露给了读者(请大家放过笔者,不要去用这些信息做坏事)。

如果使用 Vault 我们如何规避这个问题?

启动Vault

我们首先到 Vault 下载页面(如果是 Mac 用户,使用 brew 更快捷)下载对应版本的 Vault 可执行文件。为了给大家演示,我们使用最简单的 dev 模式启动,该模式绝对不可用在生产环境中。

$ export VAULT_ADDR=http://127.0.0.1:8200

$ vault server -dev
==> Vault server configuration:

             Api Address: http://127.0.0.1:8200
                     Cgo: disabled
         Cluster Address: https://127.0.0.1:8201
              Go Version: go1.17.5
              Listener 1: tcp (addr: "127.0.0.1:8200", cluster address: "127.0.0.1:8201", max_request_duration: "1m30s", max_request_size: "33554432", tls: "disabled")
               Log Level: info
                   Mlock: supported: false, enabled: false
           Recovery Mode: false
                 Storage: inmem
                 Version: Vault v1.9.2
             Version Sha: f4c6d873e2767c0d6853b5d9ffc77b0d297bfbdf+CHANGES

==> Vault server started! Log data will stream in below:
...
WARNING! dev mode is enabled! In this mode, Vault runs entirely in-memory
and starts unsealed with a single unseal key. The root token is already
authenticated to the CLI, so you can immediately begin using Vault.

You may need to set the following environment variable:

    $ export VAULT_ADDR='http://127.0.0.1:8200'

The unseal key and root token are displayed below in case you want to
seal/unseal the Vault or re-authenticate.

Unseal Key: gyxfaC82CzIMeSkhYvlQBbX25+X0uKKiBiH/b5CA8V4=
Root Token: s.XNTda9o6L4BEgQONQ6Xad9RY

Development mode should NOT be used in production installations!

在这里值得我们注意的是输出中的 Root 令牌,在这里是s.0hiFJxxBsQGNKHjsfmray9r0。这个 Token 就是我们登陆Vault进行配置所需要的凭证:

$ vault login s.0hiFJxxBsQGNKHjsfmray9r0
Success! You are now authenticated. The token information displayed below
is already stored in the token helper. You do NOT need to run "vault login"
again. Future Vault requests will automatically use this token.

Key                  Value
---                  -----
token                s.0hiFJxxBsQGNKHjsfmray9r0
token_accessor       aYkWkRyTEsaqbSn4duRp1dTy
token_duration       ∞
token_renewable      false
token_policies       ["root"]
identity_policies    []
policies             ["root"]

这样就是登陆成功,这时我们是 Vault 系统的 root 用户,拥有最高的权限。如果您看到的是这样的:

$ vault login s.XNTda9o6L4BEgQONQ6Xad9RY
Error authenticating: error looking up token: Get "https://127.0.0.1:8200/v1/auth/token/lookup-self": http: server gave HTTP response to HTTPS client

这是由于您当前的会话没有配置VAULT_ADDR这个环境变量,Vault 默认会访问 https://127.0.0.1:8200 这个地址,而我们的 Vault 服务是-dev模式,没有配置证书和 tls,所以无法访问。我们只需要配置VAULT_ADDR

$ export VAULT_ADDR='http://127.0.0.1:8200'

$ vault login s.XNTda9o6L4BEgQONQ6Xad9RY

就可以了。

Vault 是一个基于插件的开放式系统,它使用被称为机密引擎(Secrets Engine)的插件来操作不同系统的机密信息。在我们配置 AWS 信息之前,我们要首先启用AWS插件:

$ vault secrets enable aws
Success! Enabled the aws secrets engine at: aws/

Vault 的数据结构是一个虚拟的树形文件系统,在不指定-path参数时启用一个 Secrets Engine,默认就是赋予这个 Engine 在同名路径下拥有操作权限,在这里 aws 插件对应的路径就是aws/,当然我们也可以指定一个路径。这个路径用处很大,比如我们可以是 aws/事业线/团队/项目 这样,就可以把不同部门不同团队不同产品的机密分开管理。

下面我们要配置 AWS 插件:

$ vault write aws/config/root \
    access_key=AKIAZXN6JNH5D6ZSHS5V \
    secret_key=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 \
    region=us-east-1
Success! Data written to: aws/config/root

笔者把刚才用的 AWS Access Key 和 Secret Key 配置到了 aws/config/root 下,这样在 aws/ 路径下执行的 AWS 操作,都会使用这组 Key 来执行。

下面我们要创建一个角色,让它可以操作 VPC:

$ vault write aws/roles/vpc \
    credential_type=iam_user \
    policy_document=-<<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Action": "ec2:*",
      "Resource": "*"
    }
  ]
}
EOF

Success! Data written to: aws/roles/vpc

这时假设我们重新用刚才的 Terraform 脚本创建基础设施,在创建前我们先用 Vault 读一个具有刚才创建的 VPC 角色的 AWS Access Key 和 Secret Key:

$ vault read aws/creds/vpc
Key                Value
---                -----
lease_id           aws/creds/vpc/w8OTDxIri80TCkGtoZPkc6Qc
lease_duration     768h
lease_renewable    true
access_key         AKIAZXN6JNH5CKXB2JPO
secret_key         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
security_token     <nil>

我们会看到 Vault 返回了一组 access_keysecret_key,而且和我们刚才配置到 root 里的 key 是不同的。另外我们可以看到两个信息:

lease_id           aws/creds/vpc/w8OTDxIri80TCkGtoZPkc6Qc
lease_duration     768h

Vault 中把动态生成的机密信息关联了一个 lease 租约,每个租约都有对应的 id 以及有效时间,当租约过期后 Vault 会调用插件,删除租约所对应的凭证。目前我们生成的这组 Key 在 768 小时内是可用的。

让我们试试看使用它们:

$ terraform destroy -force
var.access_key
  Enter a value: AKIAZXN6JNH5CKXB2JPO

var.secret_key
  Enter a value: w6lEdAzhhdtbIQyfTGXLiHYltYBaKP9OkyZJ/X1S

aws_vpc.example: Refreshing state... [id=vpc-078628cc3ea3d053a]
aws_vpc.example: Destroying... [id=vpc-078628cc3ea3d053a]
aws_vpc.example: Destruction complete after 2s

Destroy complete! Resources: 1 destroyed.
ByersdeMacBook-Pro:aws_vpc_sample byers$ terraform apply
var.access_key
  Enter a value: AKIAZXN6JNH5FHUGY2DF

var.secret_key
  Enter a value: MOheb/FOzR1HZFBhVXJ1jMpRkbRzb1vxOlMt4Xk3


An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_vpc.example will be created
  + resource "aws_vpc" "example" {
      + arn                              = (known after apply)
      + assign_generated_ipv6_cidr_block = false
      + cidr_block                       = "10.0.0.0/16"
      + default_network_acl_id           = (known after apply)
      + default_route_table_id           = (known after apply)
      + default_security_group_id        = (known after apply)
      + dhcp_options_id                  = (known after apply)
      + enable_classiclink               = (known after apply)
      + enable_classiclink_dns_support   = (known after apply)
      + enable_dns_hostnames             = (known after apply)
      + enable_dns_support               = true
      + id                               = (known after apply)
      + instance_tenancy                 = "default"
      + ipv6_association_id              = (known after apply)
      + ipv6_cidr_block                  = (known after apply)
      + main_route_table_id              = (known after apply)
      + owner_id                         = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_vpc.example: Creating...
aws_vpc.example: Still creating... [10s elapsed]
aws_vpc.example: Creation complete after 19s [id=vpc-048217f069fc891d1]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

是成功的。如果我们登陆 AWS 的 Web 控制台,去 IAM 看一下,我们可以看到刚才创建的用户:

Vault 新建的用户
图 1.2.2/1 - Vault 新建的用户

需要注意的是,这组 key 的有效时间是 768 小时,如果您是在笔者撰写本文的 32 天之内读到这篇文章的话,您仍然可以使用这组 Key,这可不妙。我们可以吊销这个租约:

$ vault lease revoke aws/creds/vpc/w8OTDxIri80TCkGtoZPkc6Qc
All revocation operations queued successfully!

然后,对应的 iam 用户就被删除了:

iam 用户被删除了
图 1.2.2/2 - iam 用户被删除了

当然我们也可以设置生成的 Key 的有效时间:

$ vault secrets tune -default-lease-ttl=2m aws/

$ vault read aws/creds/vpc
Key                Value
---                -----
lease_id           aws/creds/vpc/6HULqs5ESLcjRZ6cxO1vrlYY
lease_duration     2m
lease_renewable    true
access_key         AKIAZXN6JNH5FSRANNAB
secret_key         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
security_token     <nil>

我们设置 aws/ 路径下的机密信息默认的有效期是 2 分钟,这样这组 Key 在 2 分钟以后就会被 Vault 删除(所以你们别试了)

通过这种方式,管理员可以把高权限的机密保存在 Vault 里,然后根据实际需求配置各团队所需要的目录、账号、权限以及策略,团队根据自己的身份可以动态获取机密,并且不用担心泄密问题。

results matching ""

    No results matching ""