I am posting the question and the answer, I found, as well, incase it would help someone. The following were my minimum requirements:
1. Client machine is Windows 10 and remote server is Linux
2. Connect to remote server via SSH through HTTP Proxy
3. HTTP Proxy uses Basic Authentication
4. Run commands on remote server and display output
The purpose of the script was to login to the remote server, run a bash script (check.sh) present on the server and display the result. The Bash script simply runs a list of commands displaying the overall health of the server.
There have been numerous discussions, here, on how to implement HTTP Proxy or running remote commands using Paramiko. However, I could not find the combination of both.
from urllib.parse import urlparse
from http.client import HTTPConnection
import paramiko
from base64 import b64encode
# host details
host = "remote-server-IP"
port = 22
# proxy connection & socket definition
proxy_url = "http://uname001:passw0rd123#HTTP-proxy-server-IP:proxy-port"
url = urlparse(proxy_url)
http_con = HTTPConnection(url.hostname, url.port)
auth = b64encode(bytes(url.username + ':' + url.password,"utf-8")).decode("ascii")
headers = { 'Proxy-Authorization' : 'Basic %s' % auth }
http_con.set_tunnel(host, port, headers)
http_con.connect()
sock = http_con.sock
# ssh connection
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
try:
ssh.connect(hostname=host, port=port, username='remote-server-uname', password='remote-server-pwd', sock=sock)
except paramiko.SSHException:
print("Connection Failed")
quit()
stdin,stdout,stderr = ssh.exec_command("./check")
for line in stdout.readlines():
print(line.strip())
ssh.close()
I would welcome any suggestions to the code as I am a network analyst and not a coder but keen to learn and improve.
I do not think that your proxy code is correct.
For a working proxy code, see How to ssh over http proxy in Python?, particularly the answer by #tintin.
As it seems that you need to authenticate to the proxy, after the CONNECT command, add a Proxy-Authorization header like:
Proxy-Authorization: Basic <credentials>
where the <credentials> is base-64 encoded string username:password.
cmd_connect = "CONNECT {}:{} HTTP/1.1\r\nProxy-Authorization: Basic <credentials>\r\n\r\n".format(*target)
Related
I'm a little over my head when it comes to this SSH thing. Basically I am trying to access a friends server through and SSH tunnel using twisted conch. He has given me the following information:
MONGO_HOST = "ip address"
MONGO_DB = "server name"
MONGO_USER = "user name"
MONGO_PASS = "server password"
I was able to get this information to work using the python library motor.motor_asyncio (I need this be async compatible in order to use with other libraries) but for reasons that I can get into if necessary, will not work on the raspberry pi that I plan on running this program on.
Long story short, I was wondering if anyone could help me with some sample code to access my friends server using the information given above with twisted.conch.
I looked on the twisted.conch readthedocs, but the example needs more information than I can provide (I think) and is WAY over my head in terms of networking/SSH/etc.
Thanks in advance. I am willing to put in the work, but I need to know where to look.
Here is my relevant bit of code so far:
from motor.motor_asyncio import AsyncIOMotorClient
from sshtunnel import SSHTunnelForwarder
MONGO_HOST = "host address"
MONGO_DB = "server name"
MONGO_USER = "username"
MONGO_PASS = "password"
server = SSHTunnelForwarder(
MONGO_HOST,
ssh_username=MONGO_USER,
ssh_password=MONGO_PASS,
remote_bind_address=('address', gate),
local_bind_address=('address', gate)
)
server.start()
client = AsyncIOMotorClient('address', gate)
db = client.server_name
You can forward ports with Conch like this:
rom twisted.internet.defer import Deferred
from twisted.conch.scripts import conch
from twisted.conch.scripts.conch import ClientOptions, SSHConnection
from twisted.conch.client.direct import connect
from twisted.conch.client.default import SSHUserAuthClient, verifyHostKey
from twisted.internet.task import react
def main(reactor):
# authenticate as this user to SSH
user = "sshusername"
# the SSH server address
host = "127.0.0.1"
# the SSH server port number
port = 22
# a local port number to listen on and forward
localListenPort = 12345
# an address to forward to from the remote system
remoteForwardHost = "127.0.0.1"
# and the port number to forward to
remoteForwardPort = 22
conch.options = ClientOptions()
conch.options.parseOptions([
# don't ask the server for a shell
"--noshell",
# set up the local port forward
"--localforward={}:{}:{}".format(
localListenPort,
remoteForwardHost,
remoteForwardPort,
),
# specify the hostname for host key checking
host,
])
# don't stop when the last forwarded connection stops
conch.stopConnection = lambda: None
# do normal-ish authentication - agent, keys, passwords
userAuthObj = SSHUserAuthClient(user, conch.options, SSHConnection())
# create a Deferred that will tell `react` when to stop the reactor
runningIndefinitely = Deferred()
# establish the connection
connecting = connect(
host,
port,
conch.options,
verifyHostKey,
userAuthObj,
)
# only forward errors so the reactor will run forever unless the
# connection attempt fails. note this does not set up reconnection for a
# connection that succeeds and then fails later.
connecting.addErrback(runningIndefinitely.errback)
return runningIndefinitely
# run the reactor, call the main function with it, passing no other args
react(main, [])
Some of the APIs are weird because they are CLI focused. You don't have to do it this way but port forwarding is most easily accessible with these APIs rather than the APIs that are more focused on programmatic use.
I am writing a Python code to SSH or Telnet remote hosts, execute some commands and get the result output. Here we have a jump server, so the code must be "connected" with this server and from it, Telnet or SSH the remote hosts.
All my approaches work fine within the jump server, for example I can get the output of commands inside it. The problem is when I try to remote connect to hosts from it.
import paramiko
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('IP', 22, username="user", password="pass")
stdin, stdout, stderr = client.exec_command("command")
for line in stdout:
print('... ' + line.strip('\n'))
client.close()
Using the library jumpssh get same results, and I am not will able to Telnet hosts. I tried the follow approach, but get the error
Administratively prohibited.
from jumpssh import SSHSession
gateway_session = SSHSession('jumpserver','user', password='pass').open()
remote_session = gateway_session.get_remote_session('IP',password='pass')
print(gateway_session.get_cmd_output('command'))
In the last company i worked we had a license from an SSH client that supports Python scripts, and worked fine in a more "textual" treatment.
There is any way of accomplish same task natively in Python?
SSHSession is trying to open direct-tcpip port forwarding channel over the gateway_session.
"administratively prohibited" is OpenSSH sshd server message indicating that direct-tcpip port forwarding is disabled.
To enable port forwarding, set AllowTcpForwarding and DisableForwarding directives in sshd_config appropriately.
If you cannot enable the port forwarding on the server, you cannot use jumpssh library.
If you have a shell access to the server, you can use ProxyCommand-like approach instead.
See Paramiko: nest ssh session to another machine while preserving paramiko functionality (ProxyCommand).
I am trying to use Paramiko to make an SSH communication between 2 servers on a private network. The client server is a web server and the host server is going to be a "worker" server. The idea was to not open up the worker server to HTTP connections. The only communication that needs to happen, is the web server needs to pass strings to a script on the worker server. For this I was hoping to use Paramiko and pass the information to the script via SSH.
I set up a new user and created a test script in Python 3, which works when I run it from the command line from my own user's SSH session. I put the same code into my Django web app, thinking that it should work, since it tests OK from the command line, and I get the following error:
Server 'worker-server' not found in known_hosts
Now, I think I understand this error. When performing the test script, I was using a certain user to access the server, and the known hosts information is saved to ~/.ssh/known_hosts even though the user is actually a 3rd party user created just for this one job. So the Django app is running under a different user who doesn't find the saved known hosts info because it doesn't have access to that folder. As far as I can tell the user which Apache uses to execute the Django scripts doesn't have a home directory.
Is there a way I can add this known host in a way that the Django process can see it?
Script:
import paramiko
client = paramiko.SSHClient()
client.load_system_host_keys()
client.connect('worker-server', 22, 'workeruser', 'workerpass')
code = "123wfdv"
survey_id = 111
stdin, stdout, stderr =
client.exec_command('python3 /path/to/test_script/test.py %s %s' % ( code, survey_id ))
print( "ssh successful. Closing connection" )
stdout = stdout.readlines()
client.close()
print ( "Connection closed" )
output = ""
for line in stdout:
output = output + line
if output!="":
print ( output )
else:
print ( "There was no output for this command" )
You can hard-code the host key in your Python code, using HostKeys.add:
import paramiko
from base64 import decodebytes
keydata = b"""AAAAB3NzaC1yc2EAAAABIwAAAQEA0hV..."""
key = paramiko.RSAKey(data=decodebytes(keydata))
client = paramiko.SSHClient()
client.get_host_keys().add('example.com', 'ssh-rsa', key)
client.connect(...)
This is based on my answer to:
Paramiko "Unknown Server".
To see how to obtain the fingerprint for use in the code, see my answer to:
Verify host key with pysftp.
If using pysftp, instead of Paramiko directly, see:
PySFTP failing with "No hostkey for host X found" when deploying Django/Heroku
Or, as you are connecting within a private network, you can give up on verifying host key altogether, using AutoAddPolicy:
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect(...)
(This can be done only if you really do not need the connection to be secure)
I have a python script, that is working only if my server is available. So before the script is beginning, i want to ping my server or rather checking the availability of the server.
There are already some related SO questions.
E.g
pyping module
response = pyping.ping('Your IP')
if response.ret_code == 0:
print("reachable")
else:
print("unreachable")
ping process in python
response = os.system("ping -c 1 " + hostname)
These answers works well, but only as ROOT user!
When i use this solutions as a common user i get the following error message:
ping: Lacking privilege for raw socket.
I need a solution, that i can do that as a common user, because i run this script in a jenkins job and have not the option to run in as root.
Would trying to perform a HTTP HEAD request, assuming the machine has a http server running, suffice?
from http.client import HTTPConnection # python3
try:
conn = HTTPConnection(host, port, timeout)
conn.request("HEAD", "/")
conn.close()
# server must be up
except:
# server is not up, do other stuff
I have a very basic piece of Python code:
import smtplib
server = smtplib.SMTP(host, port)
problems = server.sendmail(from_addr, to_addr, message)
Is there solution to run it behind an HTTP proxy? I am using Python 3.4.1 on Linux with the http_proxy variable set.
Now I am getting a timeout from SMTP, but if I run this code from a proxy-free network, it works OK.
Is there solution to run it behind an HTTP proxy?
No, HTTP is a different protocol than SMTP and the proxy is for HTTP only. If you are very lucky you might be able to create a tunnel using the CONNECT command to the outside SMTP server, but usually the ports used for CONNECT are restricted so that you will not be able to create a tunnel to an outside host port 25 (i.e. SMTP).