SSH 与提权
xops ssh 用于交互式登录主机、执行单条远程命令或建立端口转发隧道。
# 通过节点别名快速登录
xops ssh web-01
# 指定私钥与用户名登录
xops ssh -i ~/.ssh/id_ed25519 deploy@192.0.2.10
# 通过跳板机(ProxyJump)登录
xops ssh -J bastion.example.com deploy@192.0.2.10直连跳板支持 IP、FQDN 或 host:port;不带域名后缀的单标签跳板名称(如 -J jumphost)需预先保存为节点或别名。以显式用户名连接同一台主机时,凭据保持独立隔离。
连接诊断
xops ssh -v web-01
xops ssh -vv web-01 uptime
xops ssh -vvv -N -L 8080:127.0.0.1:80 web-01
xops ssh -v web-01 uptime >output.log 2>ssh.log-v显示连接、主机密钥验证、最终成功的认证方式、协商算法和会话结果;-vv增加请求确认、提权交互及转发连接信息;-vvv再增加终端交接与会话清理信息。诊断采用 OpenSSH 风格的debug1/2/3:前缀,写入 stderr,不改变远程 stdout。- 认证成功行中的
using "publickey"、using "password"或using "none"表示实际完成握手的方法;多阶段认证还显示成功链。MAC: <implicit>表示 AES-GCM 或 ChaCha20-Poly1305 自带完整性保护,无需独立 MAC,并非没有校验;非 AEAD 算法显示实际 HMAC 名称,无法确认的值显示<unknown>。 -q隐藏诊断及隧道就绪提示,不隐藏远程输出、失败报错或安全确认。与 OpenSSH 一样,顺序有影响:-qv启用诊断,-vq关闭诊断,-vqv不立即恢复 DEBUG1。--debug/--log-level控制另一套内部日志,不受-v/-q改写。远程命令自己的-v放在命令名称之后,例如xops ssh -v web-01 curl -v https://example.com。- 诊断不打印用户命令、脚本、密码或私钥正文;提权调用使用脱敏载荷,但包含主机、用户名、指纹、密码提示词及转发地址,分享日志前仍需检查。
-vvv不提供完整的 SSH 内部报文跟踪。 - 若某类管道不支持诊断输出,请将 stderr 重定向到普通日志文件。诊断输出失败会使本次操作报错,不代表远程命令未执行,请勿因此直接重试。
-f -N只显示前台验证阶段的诊断,不保留后台持续日志。
执行远程命令与管道脚本
除进入交互式终端外,xops ssh 也可以直接在远端执行命令或通过管道运行脚本:
# 原生执行单条远程命令(默认 server 模式,原样转发给远端默认 Shell)
xops ssh web-01 uptime
xops ssh --host web-01 --interpreter server uname -a
# 使用 Bash 执行命令,不加载登录环境
xops ssh --host linux-01 --interpreter bash --launch-dialect posix --login-shell=false id- 解释器选择:默认使用远端 Shell;需要指定时,可选择
server、bash、sh、zsh、fish、powershell、pwsh或cmd。参数搭配见命令执行。Windows、macOS 和 Linux 均可在终端中运行。 - 登录环境控制:使用
bash、zsh或fish时可通过--login-shell控制是否加载登录环境;--no-login为 Bash 兼容参数(等效于非登录bash -c);server模式不接受登录选项。 - 输入流与 Shell 路由:
- 终端无命令:标准输入为终端且未传命令时,打开交互式 PTY 登录 Shell。
- 管道脚本(如
cat script.sh | xops ssh web-01):默认由远端 Shell 读取并执行;若节点配置了bash、sh、zsh或fish,则使用该解释器和节点的登录设置。 - 空命令保护:显式传入空字符串(如
xops ssh web-01 "")会直接报错拒绝,不会误打开交互式 Shell。
- 中断与输出:可按
Ctrl+C中断操作。若通过管道输出时提示不支持,可改为直接在终端运行,或用xops exec执行非交互命令并将结果保存到文件。
首次连接自动保存节点
通过 ssh、sftp、scp 或 exec 首次连接新主机时,XOps 仅在连接和身份认证成功后才保存节点、主机和身份信息:
- 连接超时、拒绝连接、认证失败或认证前取消不会留下垃圾节点。
- 节点保存在打开 Shell 或执行命令之前完成,后续命令失败不会删除已认证节点;已有节点连接失败也不会被删除。
--remember never仅禁止保存密码/口令机密,认证成功的节点地址信息仍会保存。
例如,首次执行 xops ssh root@192.0.2.10(默认 22 端口)连接失败不会创建 :22 节点;随后执行 xops ssh root@192.0.2.10:2222 认证成功后仅保存 :2222 节点,下次省略端口即可直接匹配它(若同一主机保存了多个不同端口,仍需指定端口或使用别名)。
若保存节点失败,本次连接会报错。若提示配置可能已经保存,请先用 xops host list 检查,再决定是否重试。
SSH 认证方式与多因素认证 (MFA)
XOps 支持标准 SSHv2 的多种身份认证机制,以及由服务器端发起的任意多阶段多因素认证(MFA / 2FA)流程。
支持的认证方式
| 认证方式 | 协议方法名 | 说明与特性 |
|---|---|---|
| 公钥认证 | publickey | 支持 RSA、Ed25519、ECDSA、PKCS#8、PEM 等密钥格式;支持口令保护的私钥文件,支持交互式提示或 --passphrase-stdin 管道传入口令。 |
| 密码认证 | password | 传统静态口令认证;支持安全凭据库安全加密存储(zero-plaintext),支持交互式安全提示或 --password-stdin 管道传入。 |
| 键盘交互质询 | keyboard-interactive (RFC 4256) | 服务器发起的交互式问答(如 PAM 动态质询、静态安全问题等)。支持人工交互输入(自动根据提示属性开启/关闭回显)、正则自动化匹配规则(keyboard_interactive.rules),答案来源支持复用登录密码(login_password)、复用动态口令(otp)、凭据库托管机密(secret)以及外部命令提供者(command)。 |
| 一次性动态口令 | otp (RFC 6238 / RFC 4226) | 基于时间的动态口令(TOTP)。内置纯 Go 标准库实现的 RFC 6238 算法(支持标准 Base32 密钥及 otpauth:// URI 格式,支持 SHA1/SHA256/SHA512、6/8 位及自定义步长)。支持凭据库托管密钥(totp_secret_ref)、外部命令提供者(command)以及命令行单次会话覆盖参数(--otp / --otp-stdin)。 |
| 多阶段多因素认证 | PartialSuccessMethods 编排 | 自动识别服务器的多阶段认证要求(例如:公钥 + 密码、密码 + TOTP、公钥 + TOTP、密码 + 静态安全问题等),按阶段自动流转至全部认证通过。 |
配置与使用示例
1. 配置文件(~/.xops/xops_config.yaml)
XOps 严格遵守 Schema v2 架构规范与零明文安全策略:
hosts定义网络主机与端口;identities维护认证身份,私钥口令、登录密码、TOTP 密钥和质询答案一律由凭据库托管,配置文件中仅保存*_ref引用;nodes聚合host_ref与identity_ref,形成可直接连接的节点条目。
hosts:
bastion-host:
address: 198.51.100.1
port: 22
identities:
opsadmin-mfa:
user: opsadmin
auth_type: auto # 可选:auto、key、password、agent、otp、keyboard-interactive
key_path: ~/.ssh/id_ed25519 # 公钥认证密钥路径
# 方式 A:TOTP (OTP) 自动化配置
otp:
totp_secret_ref: # 凭据库托管的 TOTP 种子引用(通过 xops identity credential set 录入生成)
store_id: file
item_id: totp-seed
prompt_pattern: '(?i)verification code|otp' # 可选:当质询提示词匹配该正则时自动提供 OTP
# 也可通过外部命令动态获取 OTP(与 totp_secret_ref 二选一,禁止使用 Shell 特殊元字符):
# command: "/usr/local/bin/get-totp"
# args: ["--account", "opsadmin"]
# timeout: 5s
# 方式 B:键盘交互质询 (Keyboard-Interactive) 自动化规则
keyboard_interactive:
rules:
# 规则 1:静态安全问题,答案由安全凭据库托管(source: secret)
- name: security_question
prompt_pattern: '(?i)favorite city' # 正则匹配服务器 Prompt 文本(必填)
instruction_pattern: '(?i)answer carefully' # 可选:正则匹配服务器说明文本
source: secret # 来源类型:secret、command、login_password、otp
secret_ref: # 凭据引用(通过 xops identity credential set 录入生成)
store_id: file
item_id: city-answer
# 规则 2:外部命令提供者(source: command),从外部密码管理器动态读取答案
- name: corporate_sso_token
prompt_pattern: '(?i)one-time passcode'
source: command
command: "op"
args: ["read", "op://Employee/bastion/passcode"]
timeout: 5s
# 规则 3:服务器通过质询提问密码时,自动复用当前身份的登录密码
- name: pam_password
prompt_pattern: '(?i)password'
source: login_password
# 规则 4:服务器通过质询提问动态口令时,自动复用当前身份配置的 OTP
- name: pam_otp
prompt_pattern: '(?i)authenticator code'
source: otp
nodes:
bastion-mfa:
host_ref: bastion-host
identity_ref: opsadmin-mfa
sudo_mode: none2. 通过 CLI 安全录入凭据
机密无需(且不允许)在 YAML 文件中手写明文,使用 xops identity credential set 配合 --password-stdin 即可安全录入对应机密:
# 录入登录密码与私钥解密口令
xops identity credential set opsadmin-mfa --kind login_password --password-stdin
xops identity credential set opsadmin-mfa --kind passphrase --password-stdin
# 录入 TOTP 共享密钥(支持 Base32 密钥或 otpauth:// URI,自动在身份中配置 totp_secret_ref)
printf '%s\n' 'JBSWY3DPEHPK3PXP' | xops identity credential set opsadmin-mfa --kind totp_secret --password-stdin
# 录入特定质询规则的静态回答(需在 keyboard_interactive.rules 中已声明该规则 name)
printf '%s\n' 'Beijing' | xops identity credential set opsadmin-mfa --kind challenge_answer --rule security_question --password-stdin3. 命令行临时覆盖与人工交互回退
临时传入当前动态口令(会话单次覆盖): 在终端中临时连接开启了 2FA/OTP 的服务器时,可直接通过命令行参数传入当前的动态口令,单次优先使用,不改动身份的持久化配置:
bash# 通过 --otp 传入当前动态口令 xops ssh --otp 839201 bastion-mfa # 通过管道安全传入动态口令(避免暴露在进程列表) printf '%s\n' '839201' | xops ssh --otp-stdin bastion-mfa无配置时的交互式提示: 若服务器启用了
keyboard-interactive挑战,而当前配置中未指定匹配规则,XOps 不会凭关键字猜测问题类型,而是直接在终端安全展示服务器发起的原始挑战问题,由用户人工输入答案:- 若服务器标记该问题不需要回显(如密码/PIN),终端将关闭回显以保护隐私;
- 若服务器标记该问题允许回显(如确认信息/普通文本),终端将正常显示用户键入的字符。
Sudo / Su 提权
# 打开提权后的交互式 Shell
xops ssh --sudo web-01
# 排查提权:显示模式选择、密码交互与远端就绪阶段
xops ssh -vv --sudo web-01
# 在 PTY 下以提权身份执行单条命令
xops exec -x --sudo web-01 id提权诊断中,-v 显示模式选择、提权调用、尝试/重试、远端提权 Shell 就绪及结束结果;-vv 补充 root/免密探测、凭据查找、密码提示匹配规则及实际识别到的提示词/响应阶段;-vvv 还显示终端交接与恢复。sudo/su 的选项、目标用户和控制 Shell 可见;用户命令/脚本显示为 <privileged payload>,随机提示标记显示为 <password-prompt>(例如 [sudo: <password-prompt>] Password:)。密码等凭据响应内容及控制帧不会写入诊断。模式被选中不代表已提权成功;提权 Shell 就绪也不代表后续用户命令成功。root 或免密路径不会虚构密码交互。
提权方式由节点的 sudo_mode 配置决定(支持 auto、root、sudoer 免密、sudo 密码、su 密码):
- 禁止 root 直接登录的主机:可配置为
su模式,使用普通用户建立 SSH 连接后再通过su和 root 密码切换身份,无需开放PermitRootLogin。 - 传统
sudo与sudo-rs兼容:缺少凭据或密码被拒时,会提示重新输入。exec -x --sudo仅显示命令结果,不显示多余的 root 提示符。 - sudo/PAM 忽略
-p时:可在节点或全局配置中显式设置password_prompt_pattern,例如password_prompt_pattern: '(?m)^Password:[ \t]*$'。sudo 优先识别随机标记,未匹配时才使用该配置回退;节点配置优先于全局配置。未配置、正则无效或可匹配空字符串时不会自动启用内置默认正则作为 sudo 回退;sudoer免密模式不回退。-vv显示回退规则和命中情况。请按真实密码提示精确配置,避免匹配 banner 或其他输入;此功能不支持 OTP/多因素认证,也不会重新执行用户命令。 - 多 Shell 提权支持(
bash/sh/zsh/fish):- 节点配置
launch_dialect: fish+interpreter: fish(或bash/sh/zsh),或配置launch_dialect: posix+interpreter: zsh后,均可使用xops ssh --sudo、xops exec --sudo和 Playbooksudo: true。 - 目标系统需提供
/bin/sh;使用su时还需支持-s选项,见 su 手册。 - CLI 显式
--interpreter参数暂不支持与--sudo同时传入,请在节点或 Playbook 的execution中配置。
- 节点配置
端口转发与隧道
# 本地转发(-L):将本机 127.0.0.1:8080 转发至远端看到的 127.0.0.1:80
xops ssh -L 8080:127.0.0.1:80 -N web-01
# 动态 SOCKS5 代理(-D):在本机 127.0.0.1:1080 开启 SOCKS5 代理
xops ssh -D 1080 -N web-01
# 远程转发(-R):将远端 127.0.0.1:9000 转发至本机 127.0.0.1:3000
xops ssh -R 9000:127.0.0.1:3000 -N web-01- 绑定与校验时机:
-L和-D在本地端口收到连接时才按需打开 SSH 通道;-R在启动时立即向服务器申请远端监听(建立与关闭各有 10 秒超时上限),若被服务器拒绝则立即报错退出。 - 单连接故障隔离:单次转发连接失败(如
administratively prohibited或目标端口未监听)通过受控队列提示到stderr,但不会中断主 SSH 会话或转发监听器。-N就绪提示仍写 stdout。堵塞输出不会卡住转发回调,输出失败在结束时作为错误返回;不支持的管道可能略过辅助提示,可将对应输出流重定向到普通文件。 - 连接保活与断开退出:使用
-L、-R、-D或-N时自动启用连接监测——连续 15 秒无远端数据时发送 SSH 心跳,等待期间若连续 10 秒既无心跳回复也无数据进展则判定断线,自动关闭本地监听端口并以非零状态退出。后台运行可组合-f -N。