Related
I have check these answers in StackOverflow but they don't work for me: A1, A2 and A3.
I write my code follows as these answers and got'(1045, "Access denied for user 'root'#'localhost' (using password: YES)")'. Why is that?
my code here:
first try:
from sshtunnel import SSHTunnelForwarder
with SSHTunnelForwarder(
('****.ucd.ie', 22),
ssh_password="***",
ssh_username="s***",
remote_bind_address=('127.0.0.1', 3306)) as server:
con = pymysql.connect(user='root',passwd='***',db='dublinbus',host='127.0.0.1',port=3306)
second try:
from sshtunnel import SSHTunnelForwarder
import pymysql
import pandas as pd
tunnel = SSHTunnelForwarder(('****.ucd.ie', 22), ssh_password='***', ssh_username='s***t',
remote_bind_address=('127.0.0.1', 3306))
tunnel.start()
conn = pymysql.connect(host='127.0.0.1', user='root', passwd='****', port=3306)
data = pd.read_sql_query("SHOW DATABASES;", conn)
third try:
from sshtunnel import SSHTunnelForwarder
import pymysql
with SSHTunnelForwarder(
('****.ucd.ie',22),
ssh_password='****',
ssh_username='s****t',
remote_bind_address=('127.0.0.1', 3306)) as server:
db_connect = pymysql.connect(host='127.0.0.1',
port=3306,
user='root',
passwd='****',
db='dublinbus')
cur = db_connect.cursor()
cur.execute('SELECT stop_num FROM dublinbus.stops limit 10;')
data=cur.fetchone()
print(data[0])
All of them give me: (1045, "Access denied for user 'root'#'localhost' (using password: YES)")
So how could I connect to my remote Mysql via SSH?
Moreover, I use the same 'ssh hostname' and 'mysql hostname' 'mysql server port' in my local mysql workbench. I donot know whether it will have some impact or not.
#I use *** to replace some private information.
this could work:
from sshtunnel import SSHTunnelForwarder
import pymysql
import pandas as pd
server = SSHTunnelForwarder(
ssh_address=('****', 22),
ssh_username="****",
ssh_password="****",
remote_bind_address=("127.0.0.1", 3306))
server.start()
con = pymysql.connect(user='root',passwd='***',db='****',host='127.0.0.1',port=server.local_bind_port)
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 connect to my db manually using these steps:
1>load a putty session with ip 1.1.1.1 and port 1111
2>login as: login1
3>login1#1.1.1.1's password: pwd1
4>[login1#G ~]$ ssh login1#2.2.2.2
5>[login1#l ~]$ MySQL -h 3.3.3.3 -u login2 -p'pwd2' -D mydb
Now I can can query anything successfully like select * from my_table.
I have a python selenium webdriver code from where I want to read my db. I am not able to achieve it because of ssh tunnelling and 3 IP's involved.
from sshtunnel import SSHTunnelForwarder
import MySQLdb
with SSHTunnelForwarder(
('host', 1111),
ssh_password="pwd1
ssh_username="login1",
remote_bind_address=('2.2.2.2', 1111)) as server:
con = None
con = MySQLdb.connect(user='login2',passwd='pwd2',db='mydb',host=3.3.3.3,port=3306)
cur = con.cursor()
I am getting this error:
BaseSSHTunnelForwarderError: Could not resolve IP address for %s, aborting!
When instantiating SSHTunnelForwarder:
The param host is your remote ssh 2.2.2.2.
Argument for remote_bind_address will be for the tunnel, the port is the one you want to tunnel, so your mysql port. ('3.3.3.3', 3306)
Then when connecting to mysql, you want it to pass though the tunnel to access the mysql instance. The tunnel port is server.local_bind_port.
from sshtunnel import SSHTunnelForwarder
import MySQLdb
with SSHTunnelForwarder(
('2.2.2.2', 1111),
ssh_password="pwd1"
ssh_username="login1",
remote_bind_address=('3.3.3.3', 3306)) as server:
con = MySQLdb.connect(
user='login2',passwd='pwd2',
db='mydb',host=1.1.1.1,
port=server.local_bind_port)
I'm using MySqldb with Python 2.7 to allow Python to make connections to another MySQL server
import MySQLdb
db = MySQLdb.connect(host="sql.domain.com",
user="dev",
passwd="*******",
db="appdb")
Instead of connecting normally like this, how can the connection be made through a SSH tunnel using SSH key pairs?
The SSH tunnel should ideally be opened by Python. The SSH tunnel host and the MySQL server are the same machine.
Only this worked for me
import pymysql
import paramiko
import pandas as pd
from paramiko import SSHClient
from sshtunnel import SSHTunnelForwarder
from os.path import expanduser
home = expanduser('~')
mypkey = paramiko.RSAKey.from_private_key_file(home + pkeyfilepath)
# if you want to use ssh password use - ssh_password='your ssh password', bellow
sql_hostname = 'sql_hostname'
sql_username = 'sql_username'
sql_password = 'sql_password'
sql_main_database = 'db_name'
sql_port = 3306
ssh_host = 'ssh_hostname'
ssh_user = 'ssh_username'
ssh_port = 22
sql_ip = '1.1.1.1.1'
with SSHTunnelForwarder(
(ssh_host, ssh_port),
ssh_username=ssh_user,
ssh_pkey=mypkey,
remote_bind_address=(sql_hostname, sql_port)) as tunnel:
conn = pymysql.connect(host='127.0.0.1', user=sql_username,
passwd=sql_password, db=sql_main_database,
port=tunnel.local_bind_port)
query = '''SELECT VERSION();'''
data = pd.read_sql_query(query, conn)
conn.close()
I'm guessing you'll need port forwarding. I recommend sshtunnel.SSHTunnelForwarder
import mysql.connector
import sshtunnel
with sshtunnel.SSHTunnelForwarder(
(_host, _ssh_port),
ssh_username=_username,
ssh_password=_password,
remote_bind_address=(_remote_bind_address, _remote_mysql_port),
local_bind_address=(_local_bind_address, _local_mysql_port)
) as tunnel:
connection = mysql.connector.connect(
user=_db_user,
password=_db_password,
host=_local_bind_address,
database=_db_name,
port=_local_mysql_port)
...
from sshtunnel import SSHTunnelForwarder
import pymysql
import pandas as pd
tunnel = SSHTunnelForwarder(('SSH_HOST', 22), ssh_password=SSH_PASS, ssh_username=SSH_UNAME,
remote_bind_address=(DB_HOST, 3306))
tunnel.start()
conn = pymysql.connect(host='127.0.0.1', user=DB_UNAME, passwd=DB_PASS, port=tunnel.local_bind_port)
data = pd.read_sql_query("SHOW DATABASES;", conn)
credits to https://www.reddit.com/r/learnpython/comments/53wph1/connecting_to_a_mysql_database_in_a_python_script/
If your private key file is encrypted, this is what worked for me:
mypkey = paramiko.RSAKey.from_private_key_file(<<file location>>, password='password')
sql_hostname = 'sql_hostname'
sql_username = 'sql_username'
sql_password = 'sql_password'
sql_main_database = 'sql_main_database'
sql_port = 3306
ssh_host = 'ssh_host'
ssh_user = 'ssh_user'
ssh_port = 22
with SSHTunnelForwarder(
(ssh_host, ssh_port),
ssh_username=ssh_user,
ssh_pkey=mypkey,
ssh_password='ssh_password',
remote_bind_address=(sql_hostname, sql_port)) as tunnel:
conn = pymysql.connect(host='localhost', user=sql_username,
passwd=sql_password, db=sql_main_database,
port=tunnel.local_bind_port)
query = '''SELECT VERSION();'''
data = pd.read_sql_query(query, conn)
print(data)
conn.close()
You may only write the path to the private key file: ssh_pkey='/home/userName/.ssh/id_ed25519' (documentation is here: https://sshtunnel.readthedocs.io/en/latest/).
If you use mysql.connector from Oracle you must use a construction
cnx = mysql.connector.MySQLConnection(...
Important: a construction
cnx = mysql.connector.connect(...
does not work via an SSh! It is a bug.
(The documentation is here: https://dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html).
Also, your SQL statement must be ideal. In case of an error on SQL server side, you do not receive an error message from SQL-server.
import sshtunnel
import numpy as np
with sshtunnel.SSHTunnelForwarder(ssh_address_or_host='ssh_host',
ssh_username="ssh_username",
ssh_pkey='/home/userName/.ssh/id_ed25519',
remote_bind_address=('localhost', 3306),
) as tunnel:
cnx = mysql.connector.MySQLConnection(user='sql_username',
password='sql_password',
host='127.0.0.1',
database='db_name',
port=tunnel.local_bind_port)
cursor = cnx.cursor()
cursor.execute('SELECT * FROM db_name.tableName;')
arr = np.array(cursor.fetchall())
cursor.close()
cnx.close()
This works for me:
import mysql.connector
import sshtunnel
with sshtunnel.SSHTunnelForwarder(
('ip-of-ssh-server', 'port-in-number-format'),
ssh_username = 'ssh-username',
ssh_password = 'ssh-password',
remote_bind_address = ('127.0.0.1', 3306)
) as tunnel:
connection = mysql.connector.connect(
user = 'database-username',
password = 'database-password',
host = '127.0.0.1',
port = tunnel.local_bind_port,
database = 'databasename',
)
mycursor = connection.cursor()
query = "SELECT * FROM datos"
mycursor.execute(query)
Someone said this in another comment. If you use the python mysql.connector from Oracle then you must use a construction cnx = mysql.connector.MySQLConnection(....
Important: a construction cnx = mysql.connector.connect(... does not work via an SSH! This bug cost me a whole day trying to understand why connections were being dropped by the remote server:
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.MySQLConnection(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password)
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection.close()
If you are using python, and all the username, password, host and port are correct then there is just one thing left, that is using the argument (use_pure=True). This argument uses python to parse the details and password. You can see the doc of mysql.connector.connect() arguments.
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.MySQLConnection(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password,
use_pure='True')
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection. Close()
Paramiko is the best python module to do ssh tunneling. Check out the code here:
https://github.com/paramiko/paramiko/blob/master/demos/forward.py
As said in comments this one works perfect.
SSH Tunnel for Python MySQLdb connection
Best practice is to parameterize the connection variables.
Here is how I have implemented. Works like charm!
import mysql.connector
import sshtunnel
import pandas as pd
import configparser
config = configparser.ConfigParser()
config.read('c:/work/tmf/data_model/tools/config.ini')
ssh_host = config['db_qa01']['SSH_HOST']
ssh_port = int(config['db_qa01']['SSH_PORT'])
ssh_username = config['db_qa01']['SSH_USER']
ssh_pkey = config['db_qa01']['SSH_PKEY']
sql_host = config['db_qa01']['HOST']
sql_port = int(config['db_qa01']['PORT'])
sql_username = config['db_qa01']['USER']
sql_password = config['db_qa01']['PASSWORD']
with sshtunnel.SSHTunnelForwarder(
(ssh_host,ssh_port),
ssh_username=ssh_username,
ssh_pkey=ssh_pkey,
remote_bind_address=(sql_host, sql_port)) as tunnel:
connection = mysql.connector.connect(
host='127.0.0.1',
port=tunnel.local_bind_port,
user=sql_username,
password=sql_password)
query = 'select version();'
data = pd.read_sql_query(query, connection)
print(data)
connection.close()