生成并使用 SSH OPT 密码
我们将在本节介绍使用 Vault 生成一次性的 Linux 登陆密码(One Time Password, OTP)的方案。
管理用户在生产服务器上的用户名、密码是一件很枯燥而又关键的事,Vault 提供了一种创建一次性登陆密码的方式,它的工作原理如图:
首先我们需要在被登陆的服务器上配置 vault-ssh-helper 程序,它可以取代 Linux 默认的登陆验证程序,在用户传递了登陆用户名密码后,转而向 Vault 服务器请求验证用户名密码的正确性。用户首先登陆 Vault,通过 Vault 创建一个属于目标服务器的 otp,随后远程连接目标服务器,给出这组 otp,在 vault-ssh-helper 验证通过后成功登陆,同时 Vault 服务器会在成功验证后删除这个 otp,确保密码的确是一次性的。
实验环境
实验环境为:
- 我个人的 Macbook,运行 Vault 以及 Consul 服务,IP 为
10.25.239.240
。 - 一台 Ubuntu Server 20.04.2 LTS,IP 为
10.25.81.248
。
安装配置 vault-ssh-helper
目前 vault-ssh-helper 官方支持 Ubuntu 操作系统,在 CentOS 上由于一些原因,官方的教程还无法直接工作。本文后续都是在 Ubuntu 上进行试验。
安装本身很简单,以 vault-ssh-helper 0.2.1 为例:
# Download the vault-ssh-helper
$ wget https://releases.hashicorp.com/vault-ssh-helper/0.2.1/vault-ssh-helper_0.2.1_linux_amd64.zip
# Unzip the vault-ssh-helper in /user/local/bin
$ sudo unzip -q vault-ssh-helper_0.2.1_linux_amd64.zip -d /usr/local/bin
$ sudo chmod 0755 /usr/local/bin/vault-ssh-helper
下面是创建配置文件 /etc/vault-ssh-helper.d/config.hcl
:
vault_addr = "<VAULT_ADDRESS>"
ssh_mount_point = "ssh"
tls_skip_verify = true
allowed_roles = "*"
我们为了演示,所以没有为 Vault 配置 tls
和证书,所以我们要设置 tls_skip_verify
为 true
,并且 vault_addr
要配置 http 而非 https 的地址。生产环境必须配置 tls
验证,使用 https 地址,因为 vault-ssh-helper 会将用户提供的 OTP 通过网络传递给 Vault,非加密链路存在被中间人拦截的可能性。
然后是修改 /etc/pam.d/sshd
:
# PAM configuration for the Secure Shell service
# Standard Un*x authentication.
#@include common-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
...
在这段配置里,我们把原有的 include common-auth
这一行注释了,common-auth
是 linux 提供标准的身份验证模块,我们必须将它注释,才能使用我们后面定义的 vault-ssh-helper 模块。
注意我们配置的模块 /usr/local/bin/vault-ssh-helper
后面跟了 -dev
参数。这是因为我们在前面的配置文件中将 tls_skip_verify
设置为 true
,并使用了 http 而非 https 地址,只有在开启 -dev
模式后 vault-ssh-helper
才可以使用 http 地址。生产环境的配置中绝对不要开启 -dev
模式。
然后我们修改 /etc/ssh/sshd_config
,确保其中的三项配置设置如下:
ChallengeResponseAuthentication yes
PasswordAuthentication no
UsePAM yes
最后,我们重启一下 sshd 服务:
$ sudo systemctl restart sshd
至此,在待登陆服务器上的配置已经完成,让我们继续配置 Vault 服务器。
配置Vault服务器
OTP SSH 需要 vault-ssh-helper 远程访问 Vault 进行密码的验证,所以我们不可以使用 -dev
模式启动 Vault 服务,因为 -dev
模式下的 Vault 仅接收来自 127.0.0.1
的访问。我们需要如上一篇文章介绍的那样,以常规模式启动 Vault 服务,使用 consul
作为存储,并且正确配置侦听的 IP,比如:
storage "consul" {
address = "127.0.0.1:8500"
path = "vault/"
}
listener "tcp" {
address = "10.25.239.240:8200"
tls_disable = 1
}
listener "tcp" {
address = "127.0.0.1:8200"
tls_disable = 1
}
在这里侦听的 ip 地址就是 Vault 服务器的地址 10.25.239.240
,由于是演示,我们设置 tls_disable
为 1
,生产环境中务必不要如此。
按照上一篇文章的步骤,我们成功启动 Vault,并且解封,用 Root Token 登陆后,首先启用 ssh
插件:
$ vault secrets enable ssh
Success! Enabled the ssh secrets engine at: ssh/
然后我们写入一条角色,允许使用 otp 登陆 ssh
:
$ vault write ssh/roles/otp_key_role key_type=otp default_user=ubuntu cidr_list=0.0.0.0/0
Success! Data written to: ssh/roles/otp_key_role
这里我们指定了生成的 otp 的默认用户名是 ubuntu
,生成 otp 时要确保对应的用户名在要登陆的服务器上已经存在,否则即使 Vault 验证通过,也是无法正常登陆的。这里的 cidr_list
可以限制试图登陆的来访 ip 范围,在这里我们姑且放开,任意来源都可以使用 otp 登陆。
随后我们生成一条 otp:
$ vault write ssh/creds/otp_key_role ip=10.25.81.248
Key Value
--- -----
lease_id ssh/creds/otp_key_role/Kxkvuy5IgRw0uKk3K8UzPMAH
lease_duration 768h
lease_renewable false
ip 10.25.81.248
key f4d7dbf5-cef2-efc1-3adb-62ffdfc666e2
key_type otp
port 22
username ubuntu
在这里 ip=10.25.81.248
中的这个 ip 就是我们想要登陆的服务器 ip(就是前文配置了 vault-ssh-helper 的服务器),返回的信息中标明 username
是 ubuntu
,而形如 uuid 的 key
则是对应的 otp。让我们尝试登陆 10.25.81.248
:
$ ssh ubuntu@10.25.81.248
ubuntu@10.25.81.248's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-96-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun 30 Jan 2022 12:55:01 PM UTC
System load: 0.0
Usage of /: 14.4% of 30.88GB
Memory usage: 13%
Swap usage: 0%
Processes: 133
Users logged in: 1
IPv4 address for enp0s5: 10.25.81.248
IPv6 address for enp0s5: fdb2:2c26:f4e4:0:21c:42ff:fe36:186f
97 updates can be installed immediately.
1 of these updates is a security update.
To see these additional updates run: apt list --upgradable
Last login: Sun Jan 30 10:38:42 2022 from 10.25.81.248
ubuntu@roger:~$
登陆的用户名是 ubuntu
,密码就是 f4d7dbf5-cef2-efc1-3adb-62ffdfc666e2
,我们看到的确可以成功登陆。如果我们退出后重复用同一个密码登陆会怎么样?
ssh ubuntu@10.25.81.248
Password:
Password:
我们会发现,该密码再次使用就无法正确登陆了。如果我们生成一个新的 otp,再次登陆到 10.25.81.248
,去看一下 vault-ssh-helper 的日志:
*** Sun Jan 30 12:55:01 2022
2022/01/30 12:55:01 ==> WARNING: Dev mode is enabled!
2022/01/30 12:55:01 [INFO] using SSH mount point: ssh
2022/01/30 12:55:01 [INFO] using namespace:
2022/01/30 12:55:01 [INFO] ubuntu@10.25.81.248 authenticated!
*** Sun Jan 30 12:55:08 2022
2022/01/30 12:55:08 ==> WARNING: Dev mode is enabled!
2022/01/30 12:55:08 [INFO] using SSH mount point: ssh
2022/01/30 12:55:08 [INFO] using namespace:
2022/01/30 12:55:08 [ERROR]: Error making API request.
URL: PUT http://10.25.239.240:8200/v1/ssh/verify
Code: 400. Errors:
* OTP not found
我们会看到两条记录,第一条是我们第一次成功的 otp 登陆,同样的密码第二次登陆引发了一个 400 错误,回复找不到 OTP,这是因为第一次成功登陆后 Vault 服务器就删除了这条 otp。
自动化申请 otp 并登陆
我们目前使用 otp 登陆,需要先用 vault write
生成一条 otp,然后再用 ssh 登陆。Vault 也提供了更简单的登陆方法:
$ vault ssh -role otp_key_role -mode otp -strict-host-key-checking=no ubuntu@10.25.81.248
Vault could not locate "sshpass". The OTP code for the session is displayed
below. Enter this code in the SSH password prompt. If you install sshpass,
Vault can automatically perform this step for you.
OTP for the session is: 930d8bdc-4d73-c450-d57d-8b27e9a84d36
ubuntu@10.25.81.248's password:
Welcome to Ubuntu 20.04.2 LTS (GNU/Linux 5.4.0-96-generic x86_64)
* Documentation: https://help.ubuntu.com
* Management: https://landscape.canonical.com
* Support: https://ubuntu.com/advantage
System information as of Sun 30 Jan 2022 01:08:04 PM UTC
System load: 0.0
Usage of /: 14.4% of 30.88GB
Memory usage: 13%
Swap usage: 0%
Processes: 125
Users logged in: 1
IPv4 address for enp0s5: 10.25.81.248
IPv6 address for enp0s5: fdb2:2c26:f4e4:0:21c:42ff:fe36:186f
97 updates can be installed immediately.
1 of these updates is a security update.
To see these additional updates run: apt list --upgradable
Last login: Sun Jan 30 12:55:02 2022 from 10.25.239.240
ubuntu@roger:~$
由于我的 Mac 没有安装 sshpass ,所以 Vault 会帮助我申请到 OTP,然后要求我自己复制粘贴该 OTP 执行登录,但即使这样也极大地简化了使用 OTP 登录服务器的工作。如果客户端安装了 sshpass,则 Vault 会替我们填写 OTP,直接实现登录。我们可以将该命令封装为脚本进行进一步简化,在此不再赘述。
小结
通过配置 vault-ssh-helper 和 Vault 服务器的 ssh 插件,我们可以实现强制用户使用自己的 Vault 账号生成对应服务器的一次性密码来登陆生产服务器。由于密码仅能使用一次,所以也就大大降低了泄密和管理的风险。值得注意的是,由于 vault-ssh-helper 的开发团队目前只给出了 Ubuntu 下 pam 的配置,所以目前 ssh otp 我只在 Ubuntu 下测试成功,vault-ssh-helper在其他发行版上的运行还在摸索中。