I need to forward to multiple ports which are sits behind a server
server1(22) -> Server2(mysql, 3360) = local 3360
-> Server3(http, 8080) = local 8080
-> Server4(oracle,1234) = local 1234
I can only access Server2,3, and 4 via server1.
I am using Python ssltunnel package https://pypi.org/project/sshtunnel/
In example1&2, I can only specify one remote&local bind address.
Not sure how to connect multiple servers(2,3,4)
Example1
from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder(
'pahaz.urfuclub.ru',
ssh_username="pahaz",
ssh_password="secret",
remote_bind_address=('127.0.0.1', 8080)
)
server.start()
print(server.local_bind_port) # show assigned local port
# work with `SECRET SERVICE` through `server.local_bind_port`.
server.stop()
Example 2
import paramiko
import sshtunnel
with sshtunnel.open_tunnel(
(REMOTE_SERVER_IP, 443),
ssh_username="",
ssh_pkey="/var/ssh/rsa_key",
ssh_private_key_password="secret",
remote_bind_address=(PRIVATE_SERVER_IP, 22),
local_bind_address=('0.0.0.0', 10022)
) as tunnel:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('127.0.0.1', 10022)
# do some operations with client session
client.close()
print('FINISH!')
I could use any other Python package that can do the job.
Both examples can be modified slightly to work the way you want.
There is the singular versions of bindings (local_bind_address & remote_bind_address) and the plural versions of bindings (local_bind_addresses & remote_bind_addresses.
The singular verisons expects a tuple containing variables for the connections, while the plural versions expects a list of one or more tuple(s).
Here is a modified version of your example 2:
import paramiko
import sshtunnel
tunnels = [("172.16.0.1", 80),
("172.16.0.2", 22)]
localPorts = [("127.0.0.1", 1180),
("127.0.0.1", 10022)]
with sshtunnel.open_tunnel(
(REMOTE_SERVER_IP, 22),
ssh_username="",
ssh_pkey="/var/ssh/rsa_key",
ssh_private_key_password="secret",
remote_bind_addresses=tunnels,
local_bind_addresses=localPorts
) as tunnel:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('127.0.0.1', 10022)
# do some operations with client session
client.close()
If the lengths of the lists are the same length, then the IP-addresses / ports will correspond with each other.
In my example above, the following is happening:
Connection: 172.16.0.1 Port: 80, Is tunneled via: 127.0.0.1 Port: 1180
Connection: 172.16.0.2 Port: 22, Is tunneled via: 127.0.0.1 Port:
10022
I am adding this solution for multiple hops on multiple ports:
I have this setup:
the goal is to access the database by calling my machine on port 33306. This isn't possible because only gateway2 is allowed to speak to the database. We cant access gateway2 because only gateway1 is allowed to speak to it.
the following is the corresponding ssh .config file:
Host gateway1
HostName gtw1_IP_address
User gtw1_user
IdentityFile "path_to_gtw1_ssh_key"
IdentitiesOnly True
Host gateway2
User gtw2_user
Hostname gtw2_IP_address
IdentityFile "path_to_gtw2_ssh_key"
IdentitiesOnly True
# mysql
LocalForward 127.0.0.1:33306 127.0.0.1:3306
ProxyCommand ssh -W %h:%p switch-cede
this is how I reproduce it in python:
from sqlalchemy import create_engine
import config
import pandas as pd
import sshtunnel
from paramiko import SSHClient
with sshtunnel.open_tunnel(
ssh_username='gtw1_user',
ssh_address_or_host=('gtw1_IP_address', 22),
remote_bind_addresses=[('gtw2_IP_address', 22), ('gtw2_IP_address', 33306)],
local_bind_addresses=[('0.0.0.0', 22), ('0.0.0.0', 33306)], #this line is optional
ssh_pkey=path_to_gtw1_ssh_key,
) as tunnel1: # tunnel1 is the tunnel between myMachine and gateway1 I believe
print(tunnel1.local_bind_ports)
with sshtunnel.open_tunnel(
ssh_address_or_host=('localhost', tunnel1.local_bind_ports[0]),
remote_bind_addresses=[('127.0.0.1', 22),('127.0.0.1', 3306)],
local_bind_addresses=[('0.0.0.0', 22), ('127.0.0.1', 33306)],
ssh_username='gtw2_user',
ssh_pkey=path_to_gtw2_ssh_key,
) as tunnel2: # tunnel2 is the tunnel between gtw1 and gtw2 I believe
print(tunnel2.local_bind_ports)
db = create_engine(
f"mysql+pymysql://{config.USER}:{config.PASSWORD}#{config.HOST}:{config.PORT}/{config.DATABASE}")
print(db)
query = "SELECT * FROM randomTable LIMIT 10;"
df = pd.read_sql(query, db)
print(df)
# note that config is a file holding the credentials to connect to the database
I have a web app running on AWS Ubuntu and I am unable to connect to a database via ssh tunneling. I am able to access the db via MySQL workbench's SSH tunneling option but access via SSH tunneling on Python fails to work. Kindly suggest ways to solve it or of accessing a Phpmyadmin MySQL database other than via SSH tunneling.
from os.path import expanduser
pkeyfilepath = '/html/fbads/phpmyadmin-ec2.pem'
home = expanduser('~')
print(pkeyfilepath)
print("hello")
print(home)
mypkey = paramiko.RSAKey.from_private_key_file(home + pkeyfilepath)
print(mypkey)
server = SSHTunnelForwarder(
('ec2-52-91-169-11.compute-1.amazonaws.com', 22),
ssh_username="ec2-user",
ssh_pkey="~/html/fbads/phpmyadmin-ec2.pem",
remote_bind_address=('phpmyadmin.cpsisadn02rn.us-east-1.rds.amazonaws.com', 3306)
)
server.start()
print(server)
local_port = str(server.local_bind_port)
engine = create_engine('mysql://{}:{}#{}:{}/{}'.format("root", "passwd", "127.0.0.1", local_port, "passwd"))
dataDF = pd.read_sql("SELECT * FROM test;", engine) #testing teh connection
#server.stop() #use this command to stop the connection
I am using PyMySQL to connect to a database running on localhost. I can access the database just fine using the username/password combiunation in both the command line and adminer so the database does not appear to be the probem here.
My code is as follow. However, when using the host="127.0.0.1" options, I get an OperationalError and an Errno 111. Using the same code, but connecting via the socket Mariadb runs on is fine.
import pymysql.cursors
from pprint import pprint
# This causes an OperationalError: (pymysql.err.OperationalError) (2003, "Can't connect to MySQL server on 'localhost' ([Errno 111] Connection refused)")
# connection = pymysql.connect(
# host="127.0.0.1",
# port=3306,
# user="root",
# password="S3kr37",
# db="my_test",
# )
# This works.
connection = pymysql.connect(
user="root",
password="S3kr37",
db="my_test",
unix_socket="/var/lib/mysql/mysql.sock"
)
try:
with connection.cursor() as cursor:
sql = "select * from MySuperTable"
cursor.execute(sql)
results = cursor.fetchall()
pprint(results)
finally:
connection.close()
What am I doing wrong?
PS: Note that this question has the same problem but the solution offered is the socket. That is no good enough: I want to know why I cannot use the hostname as the documentation suggests.
Errorcode 2003 (CR_CONN_HOST_ERROR) is returned by the client library, in case the client wasn't able to establish a tcp connection to the server.
First you should check, if you can connect via telnet or mysql command line client to your server.
If not, check the server configuration file:
does the server run on port 3306?
is IPv4 disabled?
is skip-networking enabled?
is bind-address activated (with another IP?
I want create proxy/socks service from my ssh linux server. I already created port forwarder with sshtunnel for mysql, example code:
from sshtunnel import SSHTunnelForwarder
from sqlalchemy import create_engine
from sqlalchemy.engine.url import URL
with SSHTunnelForwarder(('mydomain.com', 22), ssh_username='root', ssh_password='password', local_bind_address=('127.0.0.1', 3306), remote_bind_address=('127.0.0.1', 3306)) as server:
myDB = URL(drivername='mysql+pymysql', host='127.0.0.1', database='test_db', username='root', password='THawr_tapH3f', port=3306)
engine = create_engine(name_or_url=myDB)
connection = engine.connect()
connection.close()
I want to transform my ssh linux machine in proxy/socks4/5 service with python; how can I do this?
I have a database available on a remote host. When I use putty and SSH, I am able to access it. The database itself has no password. Only, the SSH connection has a password. But, when I try to connect to it using Python, it asks for password. I'm new to postgres and paramiko.
Here's what I've tried:
import psycopg2
import paramiko
import time
t = paramiko.Transport(('xxx.com', 22))
t.connect(username="xxx", password='xxx')
c = paramiko.Channel(t)
conn = psycopg2.connect("dbname='xxx'")
curs = conn.cursor()
sql = "select * from xxx"
curs.execute(sql)
rows = curs.fetchall()
print(rows)
Other method that I tried was:
import os, psycopg2
os.system("ssh xxx#xxx.com -fNL 5432:localhost:5432 -p 22")
while True:
try:
conn = psycopg2.connect("dbname='xxx'")
curs = conn.cursor()
sql = "select * from xxx"
curs.execute(sql)
rows = curs.fetchall()
print(rows)
except:
print "I am unable to connect to the database"
This gives me a 'Could not request local forwarding' error.
Is there some other way to go about this?
I have a Windows 7 (x64) machine with Python 2.7. Please help me. Thanks.
You should connect to the remote server and make port forwarding of remote PostgreSQL to a local port.
Without paramiko, it's something like this:
# start port forwarding
$ ssh -L PGSQL_LOCAL_PORT:localhost:PGSQL_REMOTE_PORT user#xxx.com
# in python
psycopg.connect("dbname='xxx' host='localhost' port='PGSQL_LOCAL_PORT'")
Here is an example of doing this with paramiko
https://code.ros.org/trac/wg-ros-pkg/browser/pkg/trunk/paramiko/demos/forward.py?rev=30
Note: Port forwarding is blocking operation. So, you have to start port forwarding in separate thread/process.