[原创]企业SSH服务治理-SSH证书验证 #23

open
Sep0lkit opened this issue · 1 comments

标签: 解决方案; 安全架构

  • 个人主页(可选):
  • 原文链接(可选):

注: 请务必确保文章著作权或已获得转载授权; 著作权均归原作者所有.

目录

  • 证书!, NOT 密钥
  • 证书验证实践
    • 创建CA
    • 签发主机证书
    • 签发用户证书
  • SSH证书验证原理
  • SSH证书验证应用
    • 为什么证书验证?
    • 案例

证书! NOT密钥

证书? 密钥

首先, 先要严格阐明一下:"证书" 和 "密钥".

我们通常SSH登陆主机主要通过:

  1. 密码登陆
  2. 密钥登陆(也叫公钥登陆), 即我们通过ssh-keygen生成的公钥 + 私钥 密钥对.
#密钥登陆过程
ssh-kegen -t rsa -b 4096 -C "PublicKey Demo"
ssh-copy-id -i id_rsa.pub [email protected]
ssh -i id_rsa [email protected]

公钥认证, 是针对服务端而言, 对于客户端其实是私钥认证

SecureCRT/Putty/Xshell 的PublicKey也是上面的密钥登陆

麻烦请记住, 上面这种方式严格意义上叫 密钥/公钥登陆 !!!

那么什么是证书登陆验证呢? SSH证书也是基于密钥认证的, ssh证书是经过CA(证书颁发架构)签名后的公钥, 可以先看一下ssh公钥和ssh证书.

image-20200403204330497

证书 = 公钥 + 元数据(公钥指纹/签发CA/序列号/有效日期/Principals等)

结构图示: image-20200403205618164

Ok, 现在你只需要知道证书登陆 != 密钥登陆.

证书验证实践

SSH证书签发CA, 与我们所熟知的HTTPS的签发不同, 它不支持 证书链 和 可信商业CA. 可以理解为SSH签发CA只可以支持自签CA, 下面我们通过实例来说一下SSH证书验证.

创建CA

这里我们创建两个CA:

  • Host-CA: 用于给主机公钥
  • User-CA: 用于签发用户公钥
# 创建Host-CA
CA> ssh-keygen -t rsa -b 4096 -f Host-CA -C "host ca"
	
# 创建User-CA
CA> ssh-keygen -t rsa -b 4096 -f User-CA -C "user ca"

签发主机证书

# 在需要签名的主机上生成主机密钥对
exs-c7-2> ssh-keygen -f ssh_host_exs-c7-2 -t rsa -b 4096 -N ''

# 传输ssh_host_exs-c7-2.pub至CA服务器(exs-c7-1)

# 使用Host-CA签发主机公钥
cA> ssh-keygen -s Host-CA -I host-exs-c7-2 -h -n 192.168.11.212,exs-c7-2 -V +52w ssh_host_exs-c7-2.pub

#签发后我们得到cert文件
# ssh_host_exs-c7-2.pub
# ssh_host_exs-c7-2-cert.pub

参数说明: -s: 指定签名的私钥文件名 -I: 证书标识 -h: 表示需要生成的是主机证书, 而不是用户证书 -n: 使用逗号分隔, 证书主要校验字段[user|host], 可以验证此证书仅能验证那些主机IP或者主机域名 -V +52w: 表示证书有效期, 52周(一年)

-应用证书到服务器

  1. 私钥(ssh_host_exs-c7-2)拷贝至/etc/ssh

  2. 公钥证书(ssh_host_exs-c7-2-cert.pub)拷贝至/etc/ssh

  3. /etc/ssh/sshd_config 添加如下配置, 并重启sshd

HostKey /etc/ssh/ssh_host_exs-c7-2
HostCertificate /etc/ssh/ssh_host_exs-c7-2-cert.pub

-客户端导入Host-CA

client> cat ~/.ssh/known_hosts
@cert-authority 192.168.11.212 #替换为Host-CA.pub的内容" 

我们登陆主机, 可以看到服务器的证书校验通过, 如下:

image-20200403222146941

这里我们是通过重新生成主机密钥, 然后通过Host-CA进行签发, 其实可以将/etc/ssh下现有的公钥签发即可. 我们还可以将Host-CA添加至/etc/ssh/ssh_known_hosts

这一步其实是解决,使用公钥认证中"Trust on first use(TOFU)"的问题, 即 image-20200403223339517

签发用户证书

# 用户密钥生成
client-root> ssh-keygen -f ssh_user_root -t rsa -b 4096 -C "ssh-user:root"
# 用户将公钥传给CA服务器, 使用User-Ca签发
CA> ssh-keygen -s User-CA -I ssh-user-root -n root,t1,b2 -V +3d ssh_user_root.pub

-n: 使用逗号分隔, 证书主要校验字段[user|host], 通过此字段可以限制证书只可以用于登陆root/t1/b2用户.

-服务器信任User-CA

  1. 拷贝User-CA.pub至服务器/etc/ssh/
  2. 添加如下配置至/etc/ssh/sshd_config, 并重启sshd
# 信任User-CA签发的证书
TrustedUserCAKeys /etc/ssh/User-CA.pub

-登陆验证

ssh -vv -i ssh_user_root [email protected] 登陆成功, 即表示ssh证书验证配置Ok.

ssh证书验证其实是密钥认证的扩展, 嵌套了一层证书校验的逻辑, 核心还是密钥认证

SSH证书验证原理

SSH证书的其实就是PKI体系, 简单说一下, 不敢深入.

image-20200403231232331

"CA可以验证某个证书是否由其签发

  1. 客户端发起ssh链接, 服务器返回公钥证书
  2. 客户端CA验证服务器客户端证书是否是由其签发
  3. 服务器要求验证客户端身份, 客户端发送其公钥证书
  4. 服务器验证客户端证书是否由其TrustedUserCAKeys签发
  5. 进入密钥认证流程

SSH证书验证应用

为什么证书验证?

采用证书验证自然会继承PKI体系的优点:

  • 基于证书身份验证

  • 主机身份校验

  • 生命周期管理

  • SSH零信任方案

  • 客户端身份校验/权限管控

    如: 限制某个证书只可以登陆某个用户, 同时此证书禁止ssh端口/X11/agent转发等.

案例

Uber: uber的SSH治理正是基于SSH证书认证 + PAM的模式, 详细可以参考: Introducing the Uber SSH Certificate Authority

Netflix: https://github.com/Netflix/bless

个人见解:

SSH证书认证不是什么新技术, 自OpenSSH5.4都已经支持(2010/03/08), 但是有多少人知道又有多少企业在用呢?

个人在以下场景中, SSH证书体系绝对是最佳的安全选择.

  • 企业基础架构体系建设
  • SSH服务器治理与零信任结合

参考:

  1. How to SSH Properly
  2. How Uber, Facebook, and Netflix Do SSH
  3. 使用OpenSSH证书认证
  4. Introducing the Uber SSH Certificate Authority

来源:[email protected]

文章对你有帮助? 赞赏一元.

Sep0lkit commented at 4/10/2020

案例分享-Cloudflare

文章来源: Public keys are not enough for SSH security

原文介绍了Cloudflare Access的SSH安全防护方式: Short-Lived Certificates, 正是基于SSH证书验证. 作为商业性的安全解决方案, Cloudflare Access是如何实现的呢? 我们一起来看一下吧.

阅读笔记

仅记录个人学习笔记, 供参考.

  • 如果你的组织或者公司还在使用SSH公钥认证, 那么你可能已经走错了一步
    • 备份/离职资产中的密钥可能导致基础设施被攻陷
    • 密钥共享, 则加剧密钥泄露的风险
    • 密钥独立不共享, 则需要维护更多的密钥
  • 假设某一个设备已经被攻破
    • 通过known_hosts很可能链接到此网络中的更多设备
    • 如何快速响应撤销丢失的密钥?
    • 密钥是否会定期更换?
    • 如何在企业组织中毫不费力的采用安全性方案?
  • Cloudflare Access SSH in 零信任
    • 通过IdP集成, 可以在SSH链接中引入SSO的安全性
    • 但是, 并不能解决对SSH密钥的依赖
    • 引入" short-lived certificates" 解决方案

Cloudflare Access两个核心点

1. 接入Cloudflare Access网络, 摒弃传统的专用网路 2. 引入SSH证书, 摒弃SSH密钥

Cloudflare Access构建的三个工具

1.Cloudflare Access 2.Argo 3.Workers

Cloudflare Access 策略引擎服务器, 通过集成身份认证服务器 + 定义策略, 提供访问策略控制.

Argo Argo Tunnel, 你可以认为是一个OpenVPN, 其实就是将你的服务器与Cloudflare网络建立网络隧道. 服务器需要安装一个cloudflared守护程序.

Workers Workers又称为Web Workers或者Service Workers, Cloudflare提供的全球性无服务器的javascript运行环境, 你可以理解为一个全球性的Web服务. Wokers在此方案中就是作为一个Web服务的提供者.

图示

Cloudflare Access SSO 流程: 图一

关于SSO的流程这里不做过多的解释, 请注意这里的cert是没有CA签发的过程. 这里的最下面的两个流程 ③, 应该是⑤呀!

SSH证书签发 流程: image 当开启"short-lived certificates" 验证的情况下, 流程如下:

  • 1/2/3的过程即图一中的1/2/3的过程
  • 4过程, Cloudflare CA验证JWT并求请签发新的客户端证书
  • 5过程, Cloudflare CA签发新的客户端证书并返回给客户端
  • 6过程, 记录签发日志
  • 7过程, 用户通过签发的证书登陆服务器

The certificate, once issued, is valid for 2 minutes but the SSH connection can last longer once the session has started

用户体验

  • 用户客户端也需要安装cloudflared command-line tool
  • 通过cloudflared cli, ssh对用户完全透明, 不需要复杂的命令/参数等
  • 查看SSH配置
cloudflared access ssh-config --hostname vm.example.com --short-lived-cert

用户透明, 其实就是cloudflared已经给你封装好了ssh配置.

Host vm.example.com
    ProxyCommand bash -c '/usr/local/bin/cloudflared access ssh-gen \
    --hostname %h; ssh -tt %[email protected] >&2 <&1'
    
Host cfpipe-vm.example.com
    HostName vm.example.com
    ProxyCommand /usr/local/bin/cloudflared access ssh --hostname %h
    IdentityFile ~/.cloudflared/vm.example.com-cf_key
    CertificateFile ~/.cloudflared/vm.example.com-cf_key-cert.pup

原文中有一个演示视频, 感兴趣的可以去看一下.

总结

Git-News这篇文章介绍的技术点, Cloudflare这篇文章介绍的一套完整的商业方案, 都是用于SSH服务器安全治理. 实际过程中肯定还会存在各种问题, 希望这两篇文章对大家有所帮助.

^