欢迎关注微信公众号 singless
1 介绍
https://www.vaultproject.io/
https://lonegunmanb.github.io/essential-vault/
简单来说,在我们日常的工作中,免不了要和许多的机密信息打交道,可以是云服务的 Access Key 和 Secret Key,也可以是生产服务器的证书、SSH 口令、证书,或者数据库的用户名密码。以往在工作中我们经常面临着这样的问题:
- 执行密码轮换策略很痛苦
- 掌握机密的员工离职后可能泄密或是恶意报复
- 开发者不小心把机密信息随着代码上传到公网的源码仓库造成泄密
- 管理多个系统的机密非常麻烦
- 需要将机密信息安全地加密后存储,但又不想将密钥暴露给应用程序,以防止应用程序被入侵后连带密钥一起泄漏
Vault 就是用来解决这些问题的利器。
生产环境推荐的Vault架构如下
HashiCorp 推荐使用 Consul 作为 Vault 的数据存储 Backend(推荐但并不强制,Vault 支持丰富的数据存储 Backend)。本文使用consul作为vault的后端存储。
2 安装vault
笔者服务器为Ubuntu,其他系统请参考以下链接进行安装
https://developer.hashicorp.com/vault/downloads?product_intent=vault
root@ceph-4:~# wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg
root@ceph-4:~# echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list
root@ceph-4:~# sudo apt update && sudo apt install vault
root@ceph-4:~# vault version
Vault v1.15.0 (b4d07277a6c5318bb50d3b94bbd6135dccb4c601), built 2023-09-22T16:53:10Z
3 启动consul
以dev方式启动一个consul
root@ceph-4:~# sudo apt update && sudo apt install consul
root@ceph-4:~# consul agent -dev
4 vault操作
4.1 启动vault
创建vault的配置文件,指定后端存储为consul,数据存储路径为vault/,同时指定vault的端口为8200,并禁用tls
root@ceph-4:~# cat /root/config.hcl
storage "consul"{
address = "127.0.0.1:8500"
path = "vault/"
}
listener "tcp"{
address = "127.0.0.1:8200"
tls_disable = 1
}
root@ceph-4:~# vault server -config=/root/config.hcl ##启动vault服务
vault保存在Backend中的数据都是加密的。需要用密钥进行解密,这个密钥在vault中称为master key,master key需要手动创建。vault会使用shamir算法将master key切分成M份shared key,管理员需要至少提供其中N份shared key才能还原出master key(M和N都可配置,M≥N)。
Vault 刚启动时由于无法解密主密钥,所以处于 Seal 封印状态,这时 Vault 是无法进行任何操作的。解密主密钥的过程称为 Unseal 解封。在未解封(unseal)时,Vault 几乎无法执行任何操作。比方身份认证、管理挂载表等等,都无法执行。唯一可以执行的操作就是解封并检查封印状态。
4.2 生成key
root@ceph-4:~# vault operator init -address='http://127.0.0.1:8200'
执行上面的命令可以生成master key,默认master key会被分成5份,其中的任意3份可以组合成master key。root token是用来登录vault的账户,拥有最高的权限。这些key都需要自己保存好,vault并不会保存这些信息。
4.3 查看vault的状态
root@ceph-4:~# vault status -address='http://127.0.0.1:8200'
从图中我们可以看到,vault处于seal状态,且seal使用的是shamir算法,总共的shared key(unseal key)数量是5,threshold表示当有3把shared key时,可以解封vault,"unseal progress"代表我们当前提供了多少把shared key。
4.4 解封和封印vault
我们提供之前生成的三个shared key用于解封
root@ceph-4:~# vault operator unseal -address='http://127.0.0.1:8200' /glIbUIEG7/5IBc+OVVczoBiKocYBCb44F0cmz9mH8/E
root@ceph-4:~# vault operator unseal -address='http://127.0.0.1:8200' VIWROv3z+yLn/jbURZ/EhKMLYoEI7hvR9Rvvv2lP+udy
root@ceph-4:~# vault operator unseal -address='http://127.0.0.1:8200' 71DTfw9gZUAVSTlY6i3V9k1SYtyJQ6dNfZwox0NHc8SF
可以看到,在提供key时,unseal progress的数量一直在增加,当我们提供3个key 后,vault的sealed变为false状态,解封成功。
如果觉得系统存在风险,可以使用root token登录vault,执行以下命令将vault重新封印
root@ceph-4:~# vault operator seal -address='http://127.0.0.1:8200'
4.5 登录vault
root@ceph-4:~# vault login -address='http://127.0.0.1:8200' hvs.EjKzWarVoX2yQOQkNTrO3RCd
4.6 重建root token
如果root token泄露或root token不甚丢失,可以使用本节的方法重建root token。重建 Root 令牌有两种办法,分别是一次性密码(one time password)简称OPT,以及 pgp。本次使用OPT方式重建。
root@ceph-4:~# export VAULT_ADDR=http://127.0.0.1:8200 ##为了不用每次都输入一个-address参数,我们定义一个VAULT_ADDR的变量
root@ceph-4:~# vault operator generate-root -init ##生成OPT密码,这个密码我们需要记住,后面需要用到
下面来重新生成root token,会提示我们输入shared key,因为我们默认是需要三个shared key来生成master key,所以命令需要执行三次。最后一次命令执行时,会生成一个encoded token,我们使用otp可以将它解码为root token
root@ceph-4:~# vault operator generate-root
解码root token
root@ceph-4:~# vault operator generate-root -decode=MDtATTsEGC4ZDzQPORIYVzIHIz8wCGYLGjkODA -otp=XM3cMjJcIjSzxWo6CFuMGk0CjhbY ##使用这个就可以重新生成root token了
hvs.vnRMPeguAEwaqAVrwcVHpQlU
5 配置使用一次性密码登录SSH
5.1 原理介绍
实现原理图如下
我们需要在被登录的服务器上配置 vault-ssh-helper 程序,它可以取代 Linux 默认的登录验证程序,在用户传递了登录用户名密码后,转而向 Vault 服务器请求验证用户名密码的正确性。用户首先登录 Vault,通过 Vault 创建一个属于目标服务器的 otp,随后远程连接目标服务器,给出这组 otp,在 vault-ssh-helper 验证通过后成功登录,同时 Vault 服务器会在成功验证后删除这个 otp,确保密码的确是一次性的。
5.2 安装vault-ssh-helper
https://github.com/hashicorp/vault-ssh-helper
root@ceph-4:~# wget https://releases.hashicorp.com/vault-ssh-helper/0.2.1/vault-ssh-helper_0.2.1_linux_amd64.zip
root@ceph-4:~# unzip vault-ssh-helper_0.2.1_linux_amd64.zip
root@ceph-4:~# mv vault-ssh-helper /usr/bin/
root@ceph-4:~# vault-ssh-helper -version
vault-ssh-helper v0.2.1
创建配置文件
root@ceph-4:~# mkdir /etc/vault-ssh-helper.d/
root@ceph-4:~# cat /etc/vault-ssh-helper.d/config.hcl
vault_addr = "<VAULT_ADDRESS>"
ssh_mount_point = "ssh"
tls_skip_verify = true
allowed_roles = "*"
5.3 sshd配置
编辑/etc/pam.d/sshd文件
root@ceph-4:~# vim /etc/pam.d/sshd
注释@include common-account一行并加上两行auth
auth requisite pam_exec.so quiet expose_authtok log=/tmp/vaultssh.log /usr/local/bin/vault-ssh-helper -dev -config=/etc/vault-ssh-helper.d/config.hcl
auth optional pam_unix.so not_set_pass use_first_pass nodelay
检查ssh配置中以下三个值的配置是否正确
root@ceph-4:~# grep -E "ChallengeResponseAuthentication|PasswordAuthentication|UsePAM" /etc/ssh/sshd_config |grep -v "^#"
PasswordAuthentication no
ChallengeResponseAuthentication yes
UsePAM yes
重启ssh服务
root@ceph-4:~# systemctl restart sshd
5.4 vault服务配置
启动vault服务
root@ceph-4:~# cat /root/config.hcl
storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
}
listener "tcp" {
address = "192.168.85.151:8200" ##填写本机ip地址
tls_disable = 1
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = 1
}
root@ceph-4:~#
root@ceph-4:~# vault server -config=/root/config.hcl
参考第四节解封vault并用root token登录vault,shared key和root token可以使用之前的
登录后启用ssh模块
root@ceph-4:~# vault secrets enable ssh
Success! Enabled the ssh secrets engine at: ssh/
然后我们写入一条角色,允许使用 otp 登录 ssh
root@ceph-4:~# vault write ssh/roles/otp_key_role key_type=otp default_user=singless cidr_list=0.0.0.0/0
Success! Data written to: ssh/roles/otp_key_role
这里我们指定了生成的 otp 的默认用户名是 singless
,生成 otp 时要确保对应的用户名在要登录的服务器上已经存在,否则即使 Vault 验证通过,也是无法正常登录的。这里的 cidr_list
可以限制试图登录的来访 ip 范围。
生成一个otp
root@ceph-4:~# vault write ssh/creds/otp_key_role ip=192.168.85.151
ip为运行vault-ssh-helper的服务器ip,key为生成的otp密码,通过username一行可以知道,otp是为singless用户生成的。
我们在使用singless用户通过ssh连接到服务器上,通过otp密码可以正常连接到服务器。且OTP密码只可使用一次。