Jenkins SSH主机/用户证书工作流

Jenkins SSH主机/用户证书工作流,jenkins,ssh,ansible,Jenkins,Ssh,Ansible,如何在每次Ansible阶段运行时设置SSH证书签名过程? 我有一个管道,它用Terraform创建VM,然后运行Ansible。在cloudinit阶段,创建并签名主机密钥,并配置公共用户CA密钥。 客户端/主机CA权限在HashiCorp Vault中配置。 因此,在这一点上,无论配置了什么VM,我都可以通过SSH连接到每个VM,因为我拥有@cert authority*.example.com ecdsa-sha2-nistp521 aaaaaab3nzac1yc2eaaa…在/etc/S

如何在每次Ansible阶段运行时设置SSH证书签名过程? 我有一个管道,它用Terraform创建VM,然后运行Ansible。在cloudinit阶段,创建并签名主机密钥,并配置公共用户CA密钥。 客户端/主机CA权限在HashiCorp Vault中配置。 因此,在这一点上,无论配置了什么VM,我都可以通过SSH连接到每个VM,因为我拥有
@cert authority*.example.com ecdsa-sha2-nistp521 aaaaaab3nzac1yc2eaaa…
/etc/SSH/SSH\u known\u hosts
中全局设置。我所需要做的就是创建新密钥并对其签名,因为我的TTL很短。 但这在詹金斯不起作用。 Jenkins将所有SSH密钥存储在
/var/lib/Jenkins/.SSH
下,默认情况下没有任何内容。 如果出于测试原因,我确实将我的个人用户密钥和证书+ssh配置文件复制到
/var/lib/jenkins/.ssh
,那么jenkins可以愉快地运行Ansible。 但是,我不能每次在infra repo中进行提交时生成、签名和复制jenkins密钥。创建长寿证书也不好闻

SSH证书签名和轮换的惯用工作流程是什么?

我将自己列出“糟糕”的解决方案。不好,因为关键点旋转是手动的,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 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
检查它的有效期、主体等

因为基础架构中很可能会出现漂移,所以在
/var/lib/jenkins/.SSH/config
中静态存储SSH config将是一件痛苦的事情

相反,您可以创建内容如下的
ansible ssh.cfg
文件

主机堡垒
主机名bastion.example.com
唯一相同的是
IdentityFile~/.ssh/id_ecdsa
CertificateFile~/.ssh/id_ecdsa-cert.pub
端口22
议定书2
用户软呢帽
日志级别信息
此文件可以(应该)与Ansible代码的其余部分一起放置

然后,在
ansible.cfg
文件中包括SSH节

[ssh\u连接]
ssh_args=-F./ansible-ssh.cfg
这样Ansible将获取始终最新的SSH配置

如果您使用Terraform,则可以动态更新SSH配置文件,以包括新主机以及其他内容


此解决方案不绑定到Vault。使用
ssh-keygen
本身就可以很容易地完成这项工作。

我想到了其他解决方案

创建bash脚本
/etc/vault/sign-jenkins-cert.sh

#cat/etc/vault/sign-jenkins-cert.sh
#!/bin/bash
set-eu-o管道故障
保险库地址:https://vault.example.com'
SSH\u PUB\u KEY\u PATH='/var/lib/jenkins/.SSH/id\u ecdsa.PUB'
SSH_CERT_PATH='/var/lib/jenkins/.SSH/id_ecdsa-CERT.pub'
角色_ID=''#在cloudinit/kickstart阶段,应该将其烘焙
SECRET_ID=''#在cloud init/kickstart阶段,应该在
主要(){
本地保险库\u令牌=$(保险库\u签名“${ROLE\u ID}”“${SECRET\u ID}”)
本地SSH_PUB_KEY=$(cat“${SSH_PUB_KEY_PATH}”)
签署${ssh\u证书“${VAULT\u令牌}”${ssh\u发布密钥}”${ssh\u证书路径}”
chmod 0640“${SSH\u CERT\u PATH}”
}
保险库登记(){
本地角色\u ID=$1
本地机密ID=$2
本地RES=$(curl-s——请求POST)\
--数据“{role_id}”:“${role_id}”,“secret_id”:“${secret_id}”“}”\
${VAULT_ADDR}/v1/auth/approle/login | jq-r.auth.client_令牌)
本地RT=$?
如果[“$RT”==“0”];则
回声$RES
其他的
echo“使用角色$role\u ID登录失败。RT:$RT$RES”
回声“”
fi
}
签署ssh证书(){
本地保险库令牌=“$1”;
本地发布密钥=“$2”;
本地证书路径=“$3”;
curl-s\
--标题“X-Vault-Token:${Vault_Token}”\
--请帖\
--数据“{”public_key:“${PUB_key}”,“cert_type:“user”}”\
${VAULT_ADDR}/v1/ssh客户端签名者/sign/clientrole | jq-r.data.signed_key>“${CERT_PATH}”
}
主“$@”;出口
#EOT
然后将权限设置为
0644
和根所有者

sudo chown root/etc/vault/sign-jenkins-cert.sh和sudo chmod 0644/etc/vault/sign-jenkins-cert.sh
然后创建Systemd单元
/etc/Systemd/system/sign jenkins certificate.service

#cat/etc/systemd/system/sign-jenkins-certificate.service
[单位]
Description=在启动时签署新的主机证书,然后每天
[服务]
ExecStart=/bin/sh/etc/vault/sign-jenkins-cert.sh
重新启动=故障时
RestartSec=20
类型=分叉
#EOT
还将权限设置为
0644
和根所有者

然后创建计时器单元
/etc/systemd/system/sign jenkins certificate.timer

#cat/etc/systemd/system/sign-jenkins-certificate.timer
[单位]
Description=在启动时签署新的主机证书,然后每天
[计时器]
OnCalendar=每日
持久=真
单位=sign-jenkins-certificate.service
[安装]
WantedBy=timers.target
#EOT

核实

systemd分析验证/etc/systemd/system/sign-jenkins-certificate.timer
启用和启动计时器

systemctl启用sign-jenkins-certificate.timer&&\
systemctl启动sign-jenkins-certificate.timer&&\
systemctl状态sign-jenkins-certificate.timer
为那些坐在后面的人