一种跳板机的实现思路
vivo 互联网运维团队- Yang Lei
本文介绍了一种跳板机实现思路,阐述了基本原理,并讲解了特点和相对优势。
一、 跳板机思路简介
本文所描述的跳板机(下文称为“jmp”)支持:
Linux 服务器
Windows 服务器
其他终端(MySQL 终端、Redis 终端、网络设备终端 等等)
有别于市面上常见的 jumpserver 方案,使用本文所搭建的跳板机将不会存储任何 Linux 服务器的账号、密码、密钥等信息,杜绝了信息泄露的可能。本文最大的特点是借助 Linux 的 PAM 机制,通过修改 Linux 服务器系统层配置,部分接管了 Linux 系统的身份认证能力,关于这一点,下文将详细描述。
二、背景知识
2.1 Linux 的 PAM 机制
PAM(Pluggable Authentication Modules)机制,是一种广泛应用于当代 Unix、Linux 发行版的系统层身份认证框架。通过提供一系列动态链接库和两套编程接口(Service Programming Interface 和 Application Programming Interface),将系统提供的服务与该服务的认证方式分离,从而使得可以根据需要灵活地给不同的服务配置不同的认证方式而无需更改服务程序。
2.2 PAM 的核心能力
2.3 PAM 模块类型
auth
用来对用户的身份进行识别,如:提示用户输入密码,或判断用户是否为 root 等。
account
对帐号的各项属性进行检查,如:是否允许登录,是否达到最大用户数,或是 root 用户是否允许在这个终端登录等。
session
这个模块用来定义用户登录前的,及用户退出后所要进行的操作,如:登录连接信息、用户数据的打开与关闭、挂载文件系统等。
password
使用用户信息来更新,如:修改用户密码。
2.4 常见 PAM 模块
pam_unix.so 模块
【auth】提示用户输入密码,并与/etc/shadow 文件相比对,匹配返回 0(PAM_SUCCESS)。【account】检查用户的账号信息(包括是否过期等),帐号可用时,返回 0。【password】修改用户的密码,将用户输入的密码,作为用户的新密码更新 shadow 文件。
pam_cracklib.so 模块
这个模块可以插入到一个程序的密码栈中,用于检查密码的强度。
pam_loginuid.so 模块
用来设置已通过认证的进程的 uid,以使程序通过正常的审核。
pam_securetty.so 模块
如果用户要以 root 登录时,则登录的 tty 必须在/etc/securetty 中之前。
pam_rootok.so 模块
pam_rootok 模块用来认证用户 id 是否为 0,为 0 返回 PAM_SUCCESS。
pam_console.so 模块
当用户登录到终端时,改变终端文件文件的权限.在用户登出后,再将它们修改回来。
pam_permit.so 模块
该模块任何时候都返回成功。
pam_env.so 模块
pam_env 允许设置环境变量;默认下若没有指定文件,将依据/etc/security/pam_env.conf 进行环境变量的设置
pam_xauth.so 模块
pam_xauth 用来在用户之间转发 xauth-key。
pam_stack.so 模块
pam_stack 可以调用另一个服务;即多个服务可以包含到一个设置中,当需要修改时只修改一个文件就可以了。
pam_warn.so 模块
pam_warn 用来记录服务、终端用户、远程用户和远程主机的信息到系统日志,模块总是返回 PAM_IGNORE、指不希望影响到认证处理。
三、跳板机系统架构
3.1 微服务和高可用设计
3.1.1 微服务设计
整个跳板机系统可拆分为 5 个服务,和 1 个组件。
① jmp-api 服务
监听 8080 端口,提供 http 接口能力
认证某个账号是否存在且正常
认证某个账号对某台服务器是否有登录权限
认证某个账号对某台服务器是否有 sudo 权限
数据拉取:账号、主机、危险命令库等
是 jmp 访问数据库的唯一入口
② jmp-ssh 服务
监听 2200 端口,提供 ssh 代理能力
可直接访问 Linux 服务器、其他终端
③ jmp-socket 服务
监听 8080 端口,提供 websocket/socket.io 连接能力
通过 ssh 协议转发 socket.io 的流量到 jmp-ssh
支持网页终端的连接和访问
④ jmp-rdp 服务
监听 8080 端口,提供 socket.io 连接能力
实现 rdp 代理,以便于操作 Windows 服务器
支持基于网页的远程桌面服务
⑤ jmp-sftp 服务
提供文件上传下载能力,支持在 jmp 中通过 sftp 命令,支持任意 sftp 客户端连接
访问 S3,以便存取文件
⑥ jmp-agent 组件
部署在每台 Linux 服务器中
jmp-agent 常驻进程
定时从 jmp-api 拉取服务和权限信息,缓存到本地文件
根据需要检测文件改动,确保配置文件不被恶意修改
jmp 专用 pam 模块
提供 jmp.so 动态库,为 pam 模块
安装脚本释放配置文件,修改/etc/pam.d/xxx 文件,生效 jmp 的 pam 模块
接管身份识别和权限认证,调用 jmp-api 接口以完成鉴权
3.1.2 高可用设计
jmp 中任何一个服务都是无状态的,因而支持异地多机房部署
http 协议的服务(jmp-api、jmp-socket、jmp-rdp),通过 Nginx 配置路由,且配置自动负载均衡策略。
非 http 的服务(jmp-ssh、jmp-sftp),通过 4 层负载均衡(lvs、vgw)实现高可用。
自动降级策略
危险命令识别能力存在耗时久的可能性,因此当发现识别危险命令的接口超时,则自动忽略危险命令识别。
身份认证接口超时的情况下,则使用 jmp-agent 本地缓存的身份信息,如获取不到本地缓存,则使用配置项的默认策略(全部通过或者全部拒绝)。
jmp-agent 组件的高可用
由于 jmp-agent 部署在业务服务器上,所处环境可能随时发生变化,因此必须具备较强的适应性(磁盘空间不足、inode 满、内存不足、网络不稳定、域名解析异常等等)。
针对磁盘空间或 inode 不足,jmp-agent 可能无法使用本地文件缓存,因此此时选择降级,忽略缓存。
针对网络不稳定问题,jmp-agent 选择增加同 jmp-api、jmp-ssh 的通信超时,同时可降级鉴权,确保操作不受影响。
针对解析异常问题,jmp-agent 无法通过域名同服务交互,此时使用内置的固定 ip 同服务交互。
3.2 跳板机各子服务交互图
从图中可见,作为核心服务的 jmp-ssh 承载了 ssh 流量的代理转发,将来自用户 ssh 客户端、jmp-socket 服务的 ssh 流量转发到目标服务器上,并将来自目标服务器的返回结果送达回 ssh 客户端、jmp-socket 服务。因此,可在 jmp-ssh 服务上识别来自用户的危险命令,在送达目标服务器之前就给出告警或者直接拦截,避免恶意操作或者误操作给业务造成影响。
图中的 jmp-api 作为同数据库和缓存直接交互的服务,在整个系统中承担数据接口和管理端的角色,接受来自全量服务器中 jmp-agent 组件的用户身份鉴别和权限校验请求,是整个系统中的控制中枢。
jmp-api 也同时提供的权限设置能力,通过与流程系统对接,可方便的为人员/部门申请机器/服务/项目的登录权限或 root 权限,此外,jmp-api 也对登录权限和 root 权限的可申请人做出限制,针对不同项目/服务,对权限有效时间做出限制,严格控制权限粒度。
由于同一个项目/服务往往由同一个组的人维护,因此 jmp-api 内置了默认的权限策略,可允许项目/服务的负责人对项目/服务直接拥有登录权限,而无需申请;仅支持对应项目/服务的运维负责人默认拥有 root 权限,其他所有人如果希望获取 root 权限,则必须经过申请,由对应服务的运维负责人审批。
图中的 jmp-agent 是部署在每一台 Linux 服务器上的,通过在 Linux 上修改/etc/pam.d/sshd、/etc/
pam.d/remote、/etc/pam.d/sudo 等等文件,让 jmp.so (属于 jmp-agent.rpm 或 jmp-agent.deb 的一部分)接管 ssh 服务、sudo 程序等关键系统程序的身份识别、权限认证。从而使得在不增加/etc/passwd、/etc/shadow 内容的前提下实现了在任意一台服务器上识别出所有人员身份的能力。
图中的 jmp-rdp 仅作为 Windows 服务器的 rdp 代理服务,并提供基于 web 的远程桌面能力。
图中的 jmp-socket 则提供基于 web 的 Linux 服务器操作终端,从而让用户不使用 ssh 客户端也能够方便地登录服务器。
四、核心设计思路
4.1 登录跳板机
用户使用 ssh 客户端登录到 jmp-ssh 服务,与 jmp-ssh 服务交互。
jmp-ssh 服务获得 ssh 会话建立过程中的账号、加密后密码、二次认证信息。
jmp-ssh 服务访问 jmp-api 服务,提交账号、加密后密码、二次认证信息,以便知晓该用户是否有登录 jmp 的权限。
4.2 登录目标服务器
仅当用户已经登录到 jmp-ssh 或者已经通过了 jmp-socket 的前端身份认证时方可登录目标服务器。
用户在 jmp-ssh 提供的伪终端下输入 ssh xxxx(xxxx 为目标服务器的主机名或者 IP 地址)。
jmp-ssh 通过 ssh 连接到目标服务器,自动携带用户名信息,尝试建立会话。
由于目标服务器上的 jmp-agent 接管了 sshd 的身份识别和权限认证,因此 jmp.so 获取 ssh 会话建立过程中的用户名,将用户名和本机 IP 地址信息加密,调用 jmp-api 接口进行权限认证。
jmp-api 根据内置的策略,以及查询授权表,断定该用户对该机器是否有登录权限。
jmp-agent 得到鉴权结果,对有权限的,则 ssh 会话建立成功,否则会话建立失败。
jmp-ssh 获得会话建立结果和原因,返回给用户 ssh 终端。
4.3 命令交互
仅当用户已经登录到某台机器时,才可命令交互。
当用户在 ssh 客户端上敲入字符,传递到 jmp-ssh,jmp-ssh 判断语句是否结束。
当语句结束,则 jmp-ssh 根据该机器的危险命令规则,匹配用户输入的语句,决定告警、拦截、通过。
jmp-ssh 将通过的语句或需要告警的语句传递到目标服务器,目标服务器执行并返回结果。
4.4 切换用户 / 特权账号
仅当用户已经登录到某台机器时,才可能触发切换用户的行为。
当用户在 ssh 客户端执行 sudo xxxx、su、id 等等命令时,jmp-ssh 透传命令到目标服务器上。
目标服务器上的 sshd 进程执行 sudo xxxx、su、id 等等命令,由于目标服务器上已经被 jmp-agent 接管了身份失败和权限认证,因此由 jmp.so 获取登录用户名、当前用户名、本机地址信息、目标用户名信息,调 jmp-api 的接口进行 sudo 权限认证。
jmp-api 判断该用户是否拥有对该机器切换到 xx 账号的权限(如是否有 root 权限)。
sudo、su、id 等进程通过 jmp.so 获得了鉴权结果,决定是否切换用户。
4.5 使用网页交互
仅针对用户已经通过网页完成了登录(如 sso)的情况。
用户通过网页访问 jmp-socket 服务。
jmp-socket 服务获取用户名信息、网页登录 sso 信息,提交给 jmp-api,生成一个临时登录凭证。
jmp-socket 访问 jmp-ssh,提交临时登录凭证。
jmp-ssh 发起登录的二次认证,等待用户完成二次认证。
jmp-socket 在用户完成二次认证后,承担了 ssh 客户端的角色,与 jmp-ssh 交互。
4.6 危险命令拦截
jmp-ssh 在用户已经登录到目标服务器后,在该会话内,加载目标机器对应服务的危险命令规则,初始化正则匹配逻辑。
jmp-ssh 在用户输入语句结束后,根据该机器的危险命令规则,匹配用户输入的语句。
jmp-ssh 根据危险命令规则匹配后策略,决定对该输入做如下处理:告警、拦截、通过。
对于通过的,jmp-ssh 传递命令到目标服务器。
对于告警的,jmp-ssh 传递命令到目标服务器,但是向用户、用户的直属领导、jmp 系统管理员发送危险命令告警。
对于拦截的,jmp-ssh 拒绝传递命令,同时向用户、用户的直属领导、jmp 系统管理员发送危险命令告警。
4.7 非 Linux 服务器的跳板机
Windows 服务器
对于 Windows 服务器,使用 jmp-rdp 服务,将 rdp 协议数据转成由 socket.io 承载的应用数据(依赖 Apache Guacamole),并通过 web 页面的 Canvas 展示实时图像并接受键盘鼠标事件。
MySQL 终端和 Redis 终端
仅支持部署在 Linux 服务器上的 MySQL 和 Redis。
在服务器上通过 mysql.sock,使 jmp-agent 连接到本地 MySQL 服务,jmp-agent 转发标准输入和标准输出到 jmp-ssh。
在服务器上通过 redis.sock,使 jmp-agent 连接到本地 Redis 服务,jmp-agent 转发标准输入和标准输出 jmp-ssh。
该方法理论上支持任意可通过 unixsocket 连接的服务。
网络设备管理终端
对于网络终端,则 jmp-ssh 读取 jmp-api 接口,获取对应网络设备的连接信息(协议类型、账号信息等),实现连接和操作。
五、权限规则和审批链路设计
5.1 默认拥有的权限
无需申请,即可拥有的权限。
5.2 权限申请的审批链路
如果没有默认权限,但是需要登录机器,或者需要使用 ROOT 权限,则需要申请。
如果为组织申请权限,则该组织(部门)下所有成员均有锁申请的权限。
这里明确了申请流程的审批链路:
六、这种实现思路的优点
6.1 操作方便,体验较好
通过该思路所建设的跳板机系统,操作上比较方便,即支持了 ssh、又兼容了 rdp,同时提供了网页端操作入口,体验较好。同时,由于采用微服务架构,服务间耦合较小,比较容易做到高可用,从而很少出现卡顿、延时等现象,整体稳定性可靠,体验上有保证。
6.2 安全可靠,容易审计
本文的最大特点就是在目标服务器上使用了 pam 机制,通过 jmp.so 接管多个服务的身份识别和权限认证,从而做到了在不修改标准命令的基础上,统一接管权限,统一管控。并且做到了在登录到目标机器上后,可以进一步 ssh 到其他服务器,所有的交互过程全程记录,所有的操作命令都会被记录下来。
由于通过该思路所实现的跳板机直接将用户名作为目标服务器 ssh 会话的登录名,所以在系统内部所记录的日志里也是直接的用户名,而不是如 jumpserver 等方案的统一账号,这种方式下,更容易定位到操作轨迹的真实执行人,一目了然。
危险命令拦截功能,更是可以很大程度上避免恶意操作或者破坏性强的误操作,为业务稳定性增加一层保障。
6.3 服务间职责明确
由于采用了微服务架构,可以做到每个服务的横向扩展,从而做到了通过扩容服务的方式管控更多的机器。服务间职责明确,可根据需要裁减 jmp-rdp、jmp-socket、jmp-sftp,也可以根据需要增加新的服务,适配性较好。
七、总结与展望
随着服务器规模的扩大,如何管理这些服务器成为一个越来越重要的问题。针对服务器的登录访问,本文介绍了跳板机的一种实现思路,并描述了该思路的优点和独特之处。通过该思路可以一定程度上构建简单、易用且高可用的跳板机,从而解决服务器登录问题。如果读者对这个实现思路感兴趣,或者有任何疑问,欢迎与我们沟通。我们也非常愿意与各位一起学习,研究技术。
版权声明: 本文为 InfoQ 作者【vivo互联网技术】的原创文章。
原文链接:【http://xie.infoq.cn/article/a83494b9df568e50424822eaf】。文章转载请联系作者。
评论