【问题标题】:ssh via python subprocess: how to bail if fingerprint absent (Are you sure you want to continue connecting?)通过 python 子进程 ssh:如果没有指纹,如何保释(您确定要继续连接吗?)
【发布时间】:2018-07-06 05:18:39
【问题描述】:

在重新映像工作站后,我正在使用 python 脚本来管理 ssh 指纹问题。

我尝试连接,如果我收到“远程主机标识已更改!”错误,然后脚本删除旧指纹,扫描新指纹并添加它。

这一切都很好,直到我收到这样的消息:

 Warning: the ECDSA host key for 'workstation-1-s' differs from the key for the IP address '192.168.1.132'
Offending key for IP in /home/me/.ssh/known_hosts:16
Matching host key in /home/me/.ssh/known_hosts:60
Are you sure you want to continue connecting (yes/no)?

脚本在继续并删除有问题的键之前等待用户输入。

我怎样才能让脚本通过,或者输入“否”以便脚本可以继续其指纹修复工作?

下面是相关方法:

def ssh_fingerprint_changed(node):
    """
    Checks if a node's ssh fingerprint has changed or an old key is found, which can occur when a node is reimaged.
    It does this by attempting to connect via ssh and inspecting stdout for an error message.
    :param node: the ip or hostname of the node
    :return: True if the node's fingerprint doesn't match the client's records. Else False.
    """
    cmd = ["ssh", "-q", ADMIN_USER + "@" + node, "exit"]
    completed = subprocess.run(cmd, stdout=subprocess.PIPE, universal_newlines=True)
    if completed.stdout.find("REMOTE HOST IDENTIFICATION HAS CHANGED!") == -1:
        print("REMOTE HOST IDENTIFICATION HAS CHANGED!")
        return True
    elif completed.stdout.find("Offending key") == -1:
        print("Offending key found.") # need to type "no" before this prints
        return True
    return False

【问题讨论】:

  • 您需要Popen 重定向标准输入并在遇到消息时提供no。请注意,我已经破解了我的plink 版本以摆脱一些互动内容。但这并不安全。
  • 你能举一个Popen的例子吗?

标签: python ssh subprocess


【解决方案1】:

run(或旧版call)不允许您以交互方式控制进程的输入/输出。当你得到输出时,这个过程已经结束了。所以你来晚了。

有些人会将您定向到pexpectparamiko(不需要调用ssh 命令)。

这是Popen 的解决方法。我放弃了你的 return 逻辑。如果你想保留它,请记住此时进程仍在运行,所以你必须杀死它(或等待它完成):

cmd = ["ssh", "-q", ADMIN_USER + "@" + node, "exit"]
p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stdin=subprocess.PIPE, universal_newlines=True)
# loop on lines
for l in p.stdout:
    if b"Offending key" in l:
        print("Offending key found.")
        p.stdin.write(b"no\n")   # provide no + newline as the answer
rc = p.wait()  # wait for process to end, get return code

如果您确定唯一的答案是“否”,并且在给定次数下,循环的替代方案将是

out,err = p.communicate(b"no\n"*10)  # send 10 times no+linefeed

在扫描字符串/写入数据时注意“b”前缀,因为标准输入/输出/错误是二进制的。在 python 2 中没关系,但在 python 3 中,省略 b 会将字符串与字节进行比较,你永远不会得到匹配。

除此之外,我已经在 Windows 上使用 plink 完成了该操作,但过了一段时间,我厌倦了并重建了一个 plink 版本,所有安全消息都被禁用/默认为“乐观”值。如果网络是防火墙后的公司网络,并且您要回答任何问题以通过这些提示,最好从一开始就创建一个非交互式工具。

【讨论】:

  • 查看Popen 文档,它建议使用Popen.communicate。那会更好吗? docs.python.org/3/library/…
  • 否,因为通信不允许您逐行过滤输出并决定回复什么。如果你知道你会在给定的次数内回答“不”,那么使用 comunicate 是可能的。
  • 为什么b"Offending key 中的 b 是字符串? universal_newlines=True 不会导致 stdout 成为字符串吗?
  • 不一样。它是 CR+LF / LF 转换。如果使用 python 3,输出仍然是bytes
  • 最后一个问题!如果您愿意,可以提出一个新问题。现在我被密码请求抓住了(如果没有找到“违规密钥”)但我不能在循环之后proc.terminate(),因为它永远不会超过循环?
猜你喜欢
  • 2020-12-19
  • 1970-01-01
  • 1970-01-01
  • 2012-08-18
  • 2016-09-04
  • 2016-10-23
  • 1970-01-01
  • 2020-10-10
  • 2019-08-28
相关资源
最近更新 更多