【问题标题】:Nested SSH using Python Paramiko使用 Python Paramiko 的嵌套 SSH
【发布时间】:2022-01-08 20:47:56
【问题描述】:

我有这种情况:

本地主机 --------- 跳转主机 ------- 目标机器

我正在尝试使用 Paramiko 在 Python 中编写代码,首先 SSH 从本地主机到跳转主机,然后 SSH 从跳转主机到目标机器。 从目标机器,我想捕获一些输出并将它们作为变量或文件存储在本地(还没有到那个点)。 我从 Stack Overflow 中找到了一个示例,他们在其中谈论将嵌套 SSH 与 Paramiko 一起使用,我遵循了它,但我被困在这里:

我的代码:

enter code here

#!/usr/bin/python
#
# Paramiko
#
import paramiko
import sys
import subprocess
#
# we instantiate a new object referencing paramiko's SSHClient class
#
vm=paramiko.SSHClient()
vm.set_missing_host_key_policy(paramiko.AutoAddPolicy())
vm.connect('192.168.115.103',username='osmanl',password='xxxxxx')
#
vmtransport = vm.get_transport()
dest_addr = ('192.168.115.103', 22)
local_addr = ('127.0.0.1', 22)
vmchannel = vmtransport.open_channel("direct-tcpip", dest_addr, local_addr)
#
jhost=paramiko.SSHClient()
jhost.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jhost.load_host_keys('/home/osmanl/.ssh/known_hosts')
jhost.connect('10.103.53.26', username='latiu', password='xxxx', sock=vmchannel)
#
stdin, stdout, stderr = rtr.exec_command("show version | no-more")
#
print stdout.readline()
#
jhost.close()
vm.close()
# End

当我运行上面的,我得到这个错误:

$ python sshvm.py
Traceback (most recent call last):
  File "sshvm.py", line 28, in <module>
    jhost.load_host_keys('/home/osmanl/.ssh/known_hosts')
  File "/usr/lib/python2.7/site-packages/paramiko-1.15.2-py2.7.egg/paramiko/client.py", line 121, in load_host_keys
    self._host_keys.load(filename)
  File "/usr/lib/python2.7/site-packages/paramiko-1.15.2-py2.7.egg/paramiko/hostkeys.py", line 94, in load
    with open(filename, 'r') as f:
IOError: [Errno 2] No such file or directory: '/home/osmanl/.ssh/known_hosts'

【问题讨论】:

    标签: python ssh nested paramiko


    【解决方案1】:

    尝试下面的编辑代码,它应该可以工作:

    #!/usr/bin/python
    #
    # Paramiko
    #
    import paramiko
    import sys
    import subprocess
    #
    # we instantiate a new object referencing paramiko's SSHClient class
    #
    vm = paramiko.SSHClient()
    vm.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    vm.connect('192.168.115.103', username='osmanl', password='xxxxxx')
    #
    vmtransport = vm.get_transport()
    dest_addr = ('10.103.53.26', 22) #edited#
    local_addr = ('192.168.115.103', 22) #edited#
    vmchannel = vmtransport.open_channel("direct-tcpip", dest_addr, local_addr)
    #
    jhost = paramiko.SSHClient()
    jhost.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    #jhost.load_host_keys('/home/osmanl/.ssh/known_hosts') #disabled#
    jhost.connect('10.103.53.26', username='latiu', password='xxxx', sock=vmchannel)
    #
    stdin, stdout, stderr = jhost.exec_command("show version | no-more") #edited#
    #
    print stdout.read() #edited#
    #
    jhost.close()
    vm.close()
    # End
    

    【讨论】:

    • 为了阐明代码中的所有地址和端口: 1) local_addr 应该是本地 IP 和端口。不是服务器 A 的 IP 和端口。但实际上,该值并未真正使用。例如,PuTTY 在进行端口转发时会通过 '0.0.0.0'0 那里。 2)jhost.connect 中的'10.103.53.26' 也没有真正使用。它可能仅用于主机密钥验证,此代码通过使用 AutoAddPolicy 显式跳过的内容(有什么问题 - 要获得正确的解决方案,请使用正确的解决方案,请参阅 Paramiko “Unknown Server”)。
    【解决方案2】:

    我知道 OP 已经特别要求 Paramiko,但我可以使用 fabric 轻松做到这一点。这是我的解决方案

    from fabric import Connection
    
    out = Connection('host1').run('host2 uptime')
    print(out.stdout.strip())
    

    这对我来说很好用,而且我也将输出存储在一个变量中。

    【讨论】:

    • 在其他解决方案上花费了大约一个小时后,我在几分钟内就完成了这项工作。很棒的推荐!
    【解决方案3】:

    我找到了通过 jumphost 登录到远程服务器的最简单途径。这太棒了!

        link :https://pypi.org/project/jumpssh/
        import jumpssh
    

    【讨论】:

      【解决方案4】:

      在阅读接受的答案后,对源地址和目标地址https://stackoverflow.com/a/36096801/1303321 有点困惑,所以参考https://www.programcreek.com/python/?code=grycap%2Fim%2Fim-master%2FIM%2FSSH.py 这是我最终得到的工作解决方案:

      def __run_remote_command(self, command: str) -> Tuple[str, str]:
              """
              Private method to run a command in the remote machine via SSH.
              This method establishes the connection; fires the command; collects the output then closes the connection
              :param command: command which needs to be invoked in the remote machine
              :return (stdout, stderr) : Tuple of string containing the standard output and error of the command execution
              """
              stdout, stderr = '', ''
              with paramiko.SSHClient() as jhost:
                  jhost.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                  private_key = paramiko.RSAKey.from_private_key_file(filename=RESOURCES_SERVER_SSH_KEY)
                  try:
                      jhost.connect(hostname=JUMPHOST_SERVER_URL, username=RESOURCES_SERVER_SSH_USERNAME, pkey=private_key)
                      jhost_transport = jhost.get_transport()
                      dest_addr = (RESOURCES_SERVER_URL, 22)
                      local_addr = (JUMPHOST_SERVER_URL, 22)
                      jhost_channel = jhost_transport.open_channel("direct-tcpip", dest_addr, local_addr)
      
                      with paramiko.SSHClient() as target_server:
                          target_server.set_missing_host_key_policy(paramiko.AutoAddPolicy())
                          target_server_private_key = paramiko.RSAKey.from_private_key_file(filename=RESOURCES_SERVER_SSH_KEY)
                          target_server.connect(hostname=RESOURCES_SERVER_URL, username=RESOURCES_SERVER_SSH_USERNAME, pkey=target_server_private_key, sock=jhost_channel)
      
                          self.logger.info(f"Invoking {command} on remote host {RESOURCES_SERVER_URL} over SSH")
                          _, stdout, stderr = target_server.exec_command(command)
                          stdout = stdout.read().decode('utf-8')
                          stderr = stderr.read().decode('utf-8')
                  except SSHException as ssh_ex:
                      self.logger.error(f"Failed to connect to {RESOURCES_SERVER_URL} ")
                      self.logger.exception(ssh_ex, exc_info=True)
                      raise BaseException()
              return (stdout, stderr)
      

      【讨论】:

        猜你喜欢
        • 2017-08-27
        • 2010-12-27
        • 2014-10-25
        • 2020-12-11
        • 2012-05-31
        • 2020-04-27
        相关资源
        最近更新 更多