I'm a beginner at ssh so be kind with my limited knowedge ;)
What I want to do is as follow:
SSH to a PC and then from this PC SSH to another one, see picture below:
SSH Tunnel
Here are the commands I run when I do it manually:
ssh user#155.254.0.1
After this command I will be prompt to enter the password.
From here I ssh again to the next "PC" with the following command:
ssh root#190.22.0.1 -y
and then I get prompt to enter the password.
I tried to use a python script to do it automatically by I was not able to come to the next seconds step.
Here is how the python code looks like:
import subprocess
cmd_1 = ["ls"]
cmd_3 = ['ls', '-l']
def send_top_cmd():
cmd_2 = ['top', "-b", "-n", "5"]
com2 = subprocess.Popen(cmd_2, stdout=out)
com2.wait()
def send_ssh_pc_1():
cmd = ["sshpass", "-p", "'user'", "ssh", "swupdate#155.254.0.1"]
ssh_sga = subprocess.Popen(cmd, stdout=out)
ssh_sga.wait()
def send_ssh_pc_2():
cmd = ["sshpass", "-p", "'root'", "ssh", "root#190.22.0.1"]
ssh_hpa = subprocess.Popen(cmd, stdout=out)
ssh_hpa.wait()
def send_exit():
cmd = ["exit"]
process = subprocess.Popen(cmd, stdout=out)
cmd = ["exit"]
process = subprocess.Popen(cmd, stdout=out)
print("done")
with open('output.txt', 'w') as out:
send_ssh_pc_1() # ssh PC 1
send_ssh_pc_2() # ssh PC 2
send_top_cmd() # Send a simply command
send_exit()
The script fails at the "send_ssh_pc_2()" since I dont have sshpass installed and there's no possibility to install it there :(
Is there a easier way to do it automatically?
So much easier to write as an answer instead of comment.
First, enable RSA authentication for both of your SSH boxes. Then you don't need to worry about passing password. https://www.ssh.com/academy/ssh/public-key-authentication
Then open SSH tunnel from your computer with following command:
ssh -L 2222:190.22.0.1:22 user#155.254.0.1
That will enable tunnel from your local computer port 2222 to host in address 190.22.0.1 port 22. So next you can open SSH connection to the target computer like this.
ssh -p 2222 root#localhost
If your RSA private key is authorized to both user#155.254.0.1 and root#190.22.0.1 no passwords should be asked and you have SSH connection to 192.22.0.1 from your workstation.
Of course you can tunnel any TCP traffic, not just SSH.
*** ADDED ***
Here is example of content of authorized_keys -file (some content removed).
ssh-rsa AAAAB3NzaC1yc2EAAAABIwAAAQEA3fauf5H3kN92Gxx8xerCF***********************************************************************************************************************PPIrUMdf1948pqLspom8SIyeqJeKX8wVqcJch35O0Q4UVlbw== user#host
ssh-rsa AAAAB3Nzaasdfrgaa4634w4gfdewrtfauf5H3kN92Gxx8xerCF***********************************************************************************************************************PPIrUMdf1948pqLspossdfgqrbbsrdtwetdsfgsfdgsd== admin#anotherhost
Related
I am trying to SSH to a server with Python and I have been able to do so successfully. I am able to run the commands within Python successfully with one exception, the main command that is the focus of my program. It is a SIPp command that will only run within the SSH server and in a specific folder.
When I run the command in my terminal, it works perfectly fine; however, when I connect to the SSH server through PExpect or Paramiko (both work fine), I try to send my command but I get the
Error Opening Terminal: Unknown
I have so far, read the docs, tried using os, subprocess, and multiple different ways of connecting with Paramiko and Pxssh. The several people I work with were not able to figure it out either.
The SIPp command that I am trying to send and read the output of:
sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]
# some of the command was left out for simplicity's sake
# there is no issue with the command
Connecting to SSH through Pxssh (PExpect):
from pexpect import pxssh
from getpass import getpass
try:
s = pxssh.pxssh()
hostname = input('hostname: ')
username = input('username: ')
password = getpass("password :", None)
s.login(hostname, username, password)
s.sendline('cd [location of the folder]')
s.prompt()
print(s.before)
s.sendline('sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]') #this is the only line that doesn't work / output anything.
s.prompt()
print(s.before)
s.sendline('ls')
s.prompt()
print(s.before)
s.logout()
except pxssh.ExceptionPxssh as e:
print("Something went wrong. Try again with the correct Host Name, Username, and Password")
print(e)
Connecting to SSH through Paramiko:
from paramiko import client
from getpass import getpass
class ssh:
client = None
def __init__(self, address, username, password):
self.client = client.SSHClient()
self.client.set_missing_host_key_policy(client.AutoAddPolicy())
self.client.connect(address, username=username, password=password, look_for_keys=False)
def sendCommand(self, command):
if self.client:
stdin, stdout, stderr = self.client.exec_command(command)
output = stdout.readlines()
print(output, stderr.readlines())
while not stdout.channel.exit_status_ready():
if stdout.channel.recv_ready():
alldata = stdout.channel.recv(1024)
prevdata = b"1"
while prevdata:
prevdata = stdout.channel.recv(1024)
alldata += prevdata
print(str(alldata, "utf8"))
self.client.close()
else:
print("Connection not opened.")
connection = ssh([ssh info])
connection.sendCommand("cd [location] ; sipp -r 5 -m 20 -trace_msg -inf users.csv -sf register.xml -d 10000 -i [IP addresses]")
Both give me this error: Error opening terminal: unknown.
My guess is that it is not spawning an actual terminal but I can't figure out what to do at this point. Any help would be sincerely appreciated
Your command needs terminal emulation.
Either:
Try to find if there's a way to run the command, so that it does not require the terminal emulation. Maybe -bg switch can help.
Possibly this was a bug in an older version of SIPP. Make sure you have the latest version. See Startup failure when running from environment without TERM.
Or, enable the terminal emulation (what can bring unwanted side effects). With Paramiko SSHClient.exec_command, use its get_pty argument:
stdin, stdout, stderr = self.client.exec_command(command, get_pty=True)
Moin!
Situation: connect to the destination.host over the jump.host and run a command on the destination.host, which connects in the background to the another.host (on this host my ssh key is needed).
Scheme: client --> jump.host --> destination.host --- remote_command with ssh key needed on the other host --> another.host
#!/usr/bin/python
import paramiko
jumpHost=paramiko.SSHClient()
sshKey = paramiko.RSAKey.from_private_key_file('path.to.key/file', password = 'the.passphrase')
jumpHost.set_missing_host_key_policy(paramiko.AutoAddPolicy())
jumpHost.connect('jump.hostname',username='foo', pkey = sshKey)
jumpHostTransport = jumpHost.get_transport()
dest_addr = ('destination.hostname', 22)
local_addr = ('jump.hostname', 22)
jumpHostChannel = jumpHostTransport.open_channel("direct-tcpip", dest_addr, local_addr)
destHost=paramiko.SSHClient()
destHost.set_missing_host_key_policy(paramiko.AutoAddPolicy())
destHost.connect('destination.hostname', username='foo', sock=jumpHostChannel, pkey=sshKey)
destHostAgentSession = destHost.get_transport().open_session()
paramiko.agent.AgentRequestHandler(destHostAgentSession)
stdin, stderr, stdout = destHost.exec_command("my.command.which.connects.to.another.host")
print(stdout.read())
print(stderr.read())
destHost.close()
jumpHost.close()
The above code works well, if run "local" commands on the destination.host - e.g. uname, whoami, hostname, ls and so on... But if i run a command, which connects in the background to another host where my ssh key is needed, the code raised in the error:
raise AuthenticationException("Unable to connect to SSH agent")
paramiko.ssh_exception.AuthenticationException: Unable to connect to SSH agent
If i connect via Putty at the same chain, it works well.
Can anyone give me a hint to resolve my problem?
Thx in advance.
Assumption: Your keys work across jump host and destination host.
Creating a local agent in that case will work. You could manually create it via shell first and test it via iPython.
eval `ssh-agent`; ssh-add <my-key-file-path>
Programmatically this can be done -
# Using shell=True is not a great idea because it is a security risk.
# Refer this post - https://security.openstack.org/guidelines/dg_avoid-shell-true.html
subprocess.check_output("eval `ssh-agent`; ssh-add <my-key-file-path>", shell=True)
I am trying to do something similar and came across this post, I will update if I find a better solution.
EDIT: I have posted the implementation over here - https://adikrishnan.in/2018/10/25/agent-forwarding-with-paramiko/
I have a below script which i'm using to execute commands on remote hosts as a cetralized user, but this script is reads the host file and execute the command one by one however it also remains on the session until its not unlinked from the shell, Hence i want to have a parallel execution saying that when running the script it should be able to fork multiple ssh connection and login to the host and exit immeadiaely after command execution.
Please let me know if you guys have any trick or expert inputs. Though i'm using paramiko as these hosta rae legarcy UNIX hosts where i'm unable to use ansible or like utilities due to some restrictions.
import paramiko
with open('/data/CR9432/SunOS.txt', 'r') as f:
for host in f:
remote_host = host.rstrip()
remote_pass = "pass123"
smart_user = "mtrooper"
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(remote_host, username=smart_user, password=remote_pass)
transport = ssh.get_transport()
session = transport.open_session()
session.set_combine_stderr(True)
session.get_pty()
#for testing purposes we want to force sudo to always to ask for password. because of that we use "-k" key
############################################
#session.exec_command("shutdown -y -i5 -g0")
############################################
stdin = session.makefile('wb', -1)
stdout = session.makefile('rb', -1)
#you have to check if you really need to send password here
stdin.write(remote_pass +'\n')
stdin.flush()
print"\n"
print "------------------------------------------------------------------------------"
print "Command Execution Output On Hostname: "
print "------------------------------------------------------------------------------"
for line in stdout.read().splitlines():
print 'host: %s: %s' % (remote_host, line)
I have a script that SSH connects from Windows7 to a remote ubuntu server and executes a command. The script returns Ubuntu command output to the Windows cmd window in one go after the command has executed and finished. I am just wondering if there is anyway to return real-time SSH output in my script below, or do I always have to wait for the command to finish before seeing the output.
Here's my working code:
import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
host = '9.10.11.12'
port, user, password = 22, 'usr', 'pass'
ssh.connect(host, port, user, password)
stdin,stdout,stderr = ssh.exec_command("cd /opt/app && ./app-tool some_command")
for line in stdout.readlines():
print(line)
ssh.close()
Alternatively, if this is not possible with SSH how would I introduce a spinning cursor icon into the above script? Thanks.
Figured it out in the end, I used 'iter' method in the following line:
for line in iter(stdout.readline,""):
print(line)
The output of your command seems to less than the default buffer size because of which it is getting flushed once the command completes.
By default the bufsize is -1 which means that the system default buffer size is used. If bufsize is set to 1 then it is line buffered.
Use
ssh.exec_command("<cmd>",bufsize=1)
I want to know the disk usage of remote servers and i thought of doing it using ssh
here's what i have done so far:-
def disk_usage(server):
msg=""
ps = subprocess.Popen(["ssh", "-o", "BatchMode=yes", "-l", "mygroup", server, "df -k /some/directory"], stdout=subprocess.PIPE)
out, err = ps.communicate()
if err != None:
msg += "\n"+err
else:
msg = out
return msg
Final_msg = ""
server_list= ['server A','server B','server C']
for server in server_list:
Final_msg+="For Server :"+server+"\n"+disk_usage(server)
print Final_msg
The script works fine, but problem is when the ssh for any server is not configured it just displays a blank output for that server
Output:-
For Server A :
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/cfd/ace 8064048 3581524 4072892 47% /app
For Server B :
For server C :
Filesystem 1K-blocks Used Available Use% Mounted on
/dev/wsa/ace 306423 244524 23243434 90% /app
Here ssh for server B is not configured so i'm getting a blank output because the batchmode is on (BatchMode=yes) for all the ssh connections, but i want the user to know why there was no output.
when i run the same command on the shell for the sever where ssh is not configured i get the below error:
Permission denied (publickey,gssapi-keyex,gssapi-with-mic,password).
I want the same error in my output of the script for that particular server where ssh is not configured.
any ideas?
To detect that an error happened, you should check the returncode attribute of the Popen object (ps).
To get the output from stderr, you have to pass stderr=subprocess.PIPE to Popen, just as you do for stdout.
if your local machine has static ip i would recommend using sockets so your data usage script will connect to your local machine and deliver data.
or if you have domain to post your server info to your web app via urllib.