SSH非root用户IP分级访问可通过Match Address+AllowUsers、AuthorizedKeysCommand、PAM access.conf及ProxyJump四层机制实现,无需重启服务、不依赖root权限、支持动态策略生效。

关键核心资产的 SSH 访问不能只靠“用户是谁”,更要看“从哪来”——尤其当登录者是非 root 普通用户时,来源 IP 必须参与准入决策,且整个过程需在不重启服务、不硬编码白名单、不依赖 root 权限的前提下动态生效。
用 Match Address + AllowUsers 实现非 root 用户的 IP 分级放行
OpenSSH 原生支持按源 IP 动态限制可登录的非 root 用户,无需脚本或特权操作:
- 在 /etc/ssh/sshd_config 末尾添加带网段的 Match 块,例如:
Match Address 10.20.30.0/24
AllowUsers deploy@10.20.30.0/24 audit@10.20.30.0/24
表示仅允许该网段内以 deploy 或 audit 身份、且来源 IP 匹配该子网的连接;其他用户(包括同名用户但来自其他 IP)直接拒绝 - 务必加兜底规则:DenyUsers *,防止未匹配规则的任意非 root 用户尝试接入
- 修改后执行 sshd -t 校验语法,再 systemctl reload sshd —— 不中断现有会话,也不需要 root 启动新进程
通过 AuthorizedKeysCommand 绑定 IP 与用户密钥(免改配置)
对已部署的非 root 用户,可让其公钥是否生效取决于实时 IP 上下文,完全绕过静态配置更新:
- 在 Match 块中启用:
Match Address 172.16.0.0/12
AuthorizedKeysCommand /usr/local/bin/ssh-allow-if-trusted %u %i
AuthorizedKeysCommandUser nobody
其中 %i 是客户端真实源 IP,脚本可查 Redis 缓存的跳板机授权记录、或调用内部 API 判断该 IP 是否刚通过 MFA 登录堡垒机 - 脚本返回对应用户的公钥内容则放行;无输出即拒绝——整个过程不触碰 ~/.ssh/authorized_keys 文件,也不需要用户重传密钥
- 普通运维人员只需申请临时访问权限,系统自动完成 IP 绑定与密钥激活,无需管理员手动改配置
用 PAM access.conf 在会话启动前做最后一道 IP 校验
作为补充防线,在用户通过密钥认证后、shell 启动前再次校验来源 IP 合法性,支持细粒度策略:
- 编辑 /etc/security/access.conf,添加类似规则:
- : deploy : ALL EXCEPT 10.20.30.0/24 172.16.100.50
表示 deploy 用户只允许从指定两个 IP 范围登录,其余全部拒绝 - 确保 /etc/pam.d/sshd 中有这一行(通常默认存在):
account required pam_access.so - 该机制不依赖 root 执行命令,也不修改 SSH 配置,所有策略变更写入 access.conf 即实时生效
收敛出口 + 强制 ProxyJump 隐式绑定可信 IP
最稳妥的方式是不让核心资产直接暴露 SSH 端口给任意来源,而是强制所有非 root 访问必须经由受控跳板节点:
- 在核心服务器的 sshd_config 中只保留:
AllowUsers deploy@10.10.20.50 audit@10.10.20.51
其中 10.10.20.50/51 是跳板集群固定内网 IP,意味着 deploy 只能从这台机器登录,且该跳板本身已做严格 IP 和硬件 ID 双因子控制 - 终端用户使用:
ssh -J jump-user@10.10.20.50 deploy@core-server
整个链路中,核心服务器看到的源 IP 永远是跳板机地址,天然实现 IP 动态收敛 - 跳板机自身可配置短时效令牌或临时 ACL,使“deploy 能否从某 IP 连跳板”也变成可动态开关的能力

















