I have this scenario:
Local-host ——— jump-host ——- target-machine
I am trying to write a code in Python using Paramiko to first SSH from local-host to jump-host and then SSH from jump-host to the target-machine.
From the target-machine, I want to capture some outputs and store them locally either as a variable or as a file (haven’t got to that point yet).
I found an example from Stack Overflow where they talk about using nested SSH with Paramiko, and I follow it but I get stuck here:
My code:
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
When I run the above, I get this error:
$ 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'
Answers:
Thank you for visiting the Q&A section on Magenaut. Please note that all the answers may not help you solve the issue immediately. So please treat them as advisements. If you found the post helpful (or not), leave a comment & I’ll get back to you as soon as possible.
Method 1
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
Method 2
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.
Method 3
I found this easiest route to login to remote server via jumphost.This works amazing!
link :https://pypi.org/project/jumpssh/
import jumpssh
Method 4
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)
All methods was sourced from stackoverflow.com or stackexchange.com, is licensed under cc by-sa 2.5, cc by-sa 3.0 and cc by-sa 4.0