Nested SSH using Python Paramiko
I found this easiest route to login to remote server via jumphost.This works amazing!
link :https://pypi.org/project/jumpssh/
import jumpssh
I know OP has specifically asked for Paramiko
but i can do this very easily with fabric
. Here is my solution
from fabric import Connection
out = Connection('host1').run('host2 uptime')
print(out.stdout.strip())
This works just fine for me, and i have the output stored in a variable as well.
After reading accepted answer got bit confused about source and destintation addresses https://stackoverflow.com/a/36096801/1303321, so refering to https://www.programcreek.com/python/?code=grycap%2Fim%2Fim-master%2FIM%2FSSH.py here is what I ended up with working solution:
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)
Try the following edited code, it should work:
#!/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