每次运行某个 Ansible 阶段时如何设置 SSH 密钥签名过程?或者至少在某个间隔内设置。
我有使用 Terraform 创建虚拟机然后运行 Ansible 的管道。在 cloud-init 阶段,创建并签名主机密钥,并配置公共用户 CA 密钥。客户端/主机 CA 颁发机构在 HashiCorp Vault 中配置/运行。因此,此时,无论配置了哪些虚拟机,我都可以通过 SSH 进入每个虚拟机,因为我已在@cert-authority *.example.com ecdsa-sha2-nistp521 AAAAB3NzaC1yc2EAAA...
中全局设置了主机 CA 公钥/etc/ssh/ssh_known_hosts
。我需要做的就是创建新的个人密钥并对其进行签名,因为我的 TTL 很短。
但这在 Jenkins 中不起作用。Jenkins 将所有 SSH 密钥存储在 下/var/lib/jenkins/.ssh
,默认情况下什么都没有。如果只是为了测试,我将我的个人用户(或生成的)密钥和证书 + ssh 配置文件复制到 中/var/lib/jenkins/.ssh
,那么 Jenkins 可以愉快地运行 Ansible。但是,每次我在 infra repo 中执行某些提交时,我都无法生成、签名和复制 jenkins 密钥。创建长期有效的证书也不好。
SSH 密钥签名和轮换的惯用自动化工作流程是什么?
答案1
我将自己列出“不好”的解决方案。不好,因为密钥轮换是手动的,而且由于我们很懒,TTL 很可能会很长。
在 Vault 中,你需要创建一个新的“jenkins”SSH 角色,其 TTL 如下52w
然后,理想情况下,您需要在 Jenkins 主机上创建新的密钥。
ssh-keygen -t ecdsa -b 521 -f /var/lib/jenkins/.ssh/id_ecdsa -C "jenkins@jenkins-01"
然后通过 Vault 签名
vault write -field=signed_key ssh-client-signer/sign/jenkinsrole public_key=/var/lib/jenkins/.ssh/id_ecdsa.pub > /var/lib/jenkins/.ssh/id_ecdsa-cert.pub
这意味着 Vault 应该在系统上。...这是一个两难的问题 - 您是否想通过网络复制 ssh 密钥(包括私钥),这有点奇怪,或者您想在 Jenkins 机器上安装 Vault。这取决于你。
获得id_ecdsa-cert.pub
证书后,您可以检查它ssh-keygen -Lf /var/lib/jenkins/.ssh/id_ecdsa-cert.pub
并查看其有效期、原理等是否正确。
因为基础设施很可能会出现偏差,所以静态存储 SSH 配置/var/lib/jenkins/.ssh/config
将会很麻烦。
相反,你可以创建ansible-ssh.cfg
包含类似内容的文件
Host bastion
HostName bastion.example.com
IdentitiesOnly yes
IdentityFile ~/.ssh/id_ecdsa
CertificateFile ~/.ssh/id_ecdsa-cert.pub
Port 22
Protocol 2
User ansible
LogLevel INFO
该文件可以(应该)与 Ansible 代码的其余部分位于一起。
然后,在ansible.cfg
文件中包含 SSH 节
[ssh_connection]
ssh_args = -F ./ansible-ssh.cfg
这样,Ansible 将始终获取最新的 SSH 配置。
如果您使用 Terraform,那么可以动态更新 SSH 配置文件以包含新主机等。
此解决方案不仅限于 Vault。它ssh-keygen
本身也可以轻松实现。
更新:最终我得到了一个小型 shell 脚本,该脚本使用 approle 进行授权,然后签署证书。Systemd 服务和 Timer 单元执行该 shell 脚本,该脚本每天进行证书轮换。因此此时 Jenkins 使用它自己的新用户证书来运行 Terraform 和 Ansible。 https://stackoverflow.com/a/65875997/6651080