首页 > 解决方案 > Python SSH 通过不同路径迭代

问题描述

我有一个如下所示的 JSON 对象:

{UID_1:{
    jumpboxes:[jump_ip1, jump_ip2,...],
    hosts: [host_ip1, host_ip2,...],
    ...},
UID_2:{...

对 jumpboxes 的身份验证是通过 kerberos(无密码),对主机的身份验证是使用密码,并且主机只能通过跳转主机可见。我不知道 IP 列表中哪些有效,哪些被卡住或无响应等,所以我需要找到第一个可以让我打开 SSH 会话的路径。

我可以做的是在 ssh-ing 到跳转主机时检查退出代码,如下所示:

jumpip = ''
for i in json[uid][jumpboxes]:
    if os.system('ssh {}@{}'.format(username,i))>0:
        continue
    else:
        jumpip = i
        break

这为我提供了第一个正常工作的 jumpbox ip,但是拥有与第二台主机建立 ssh 连接的密码并不容易检查其退出代码。

有多种方法可以打开隧道 - 使用 os.system() 和使用 sshpass 和会话代理(类似于:( if os.system('sshpass -p {} ssh -o ProxyCommand="ssh {}@{} nc {} 22" {}@{} -t {}'.format(password, user, jumpip, hosts[j], user, hosts[j], remote_cmd))>0:....对于上下文,我们假设 sshpass 命令看起来像这样:sshpass -p Password123! -o ProxyCommand="ssh user@jumpbox nc hostip 22" user@hostip -t ll或者在子shell中使用一些东西做 pint喜欢os.system('ssh user@jumpbox -t ping {} -c 5'.format(hosts[j])),虽然 ping 会返回一个退出代码,但 ICMP 回显回复并不意味着我能够打开一个隧道(例如,守护进程可能被卡住或可能已经崩溃等),或者我可以做一个 try-except -else 块,它尝试通过带有 pexpect 或 subrpocess.popen 并通过管道传输 stdio 的跳转框打开与远程主机的 ssh 会话,从而允许我推送密码,如果未能引发自定义异常,但我可以不知道如何从 ssh 客户端获取退出代码,所以我可以检查状态...

这些对我来说都不够健壮,所以我宁愿正确地遍历 IP,我愿意接受建议。

一点背景知识 - 隧道将用于启动 nohup-ed 命令,然后将被关闭。该脚本使用多处理和池来处理一大堆这些,所以我将启动它们,然后有一个循环来检查它们的状态并检索在主机上执行的远程脚本的结果。我知道 os.system 已被弃用,我应该使用子进程,但这对于用例来说不是必需的,所以我并不真正关心这一点。我正在寻找一种聪明的方法来遍历可能的路径,这些路径将采用给定一个带有长度的跳转框n列表和一个带有长度m和超时x秒数的主机列表,最大n*m*x秒数以找出并缩短该时间。

一旦我找到了打开隧道所需的正确 IP,我还使用 pexpect(它本身使用 paramiko)与远程主机进行交互。

提前致谢!

标签: pythonsshparamikopexpectsshpass

解决方案


我想通了 - 如果有提示,pexpect 会提供退出代码,即我做了一些类似的事情

host = ''
for i in hosts:
    cmd = 'ssh {}@{} -t ssh {}'.format(user,jumpbox, i)
    try:
        p = pexpect.spawn(cmd)
        if p.expect('.*') == 0:
            host = i
            break
    except:
        someException()
if host != '':
    ...

感谢所有的投入。


推荐阅读