简体   繁体   English

使Python通过SSH隧道连接到MySQL

[英]Enable Python to Connect to MySQL via SSH Tunnelling

I'm using MySqldb with Python 2.7 to allow Python to make connections to another MySQL server我将MySqldb与 Python 2.7 一起使用,以允许 Python 连接到另一个 MySQL 服务器

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?而不是像这样正常连接,如何使用 SSH 密钥对通过 SSH 隧道建立连接?

The SSH tunnel should ideally be opened by Python. The SSH tunnel host and the MySQL server are the same machine. SSH隧道理想情况下应该由Python开启。SSH隧道主机和MySQL服务器是同一台机器。

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我推荐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/归功于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/ ).您只能写入私钥文件的路径: ssh_pkey='/home/userName/.ssh/id_ed25519' (文档在这里: https : ssh_pkey='/home/userName/.ssh/id_ed25519' )。

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 ).如果您使用 Oracle 的 mysql.connector,则必须使用构造cnx = mysql.connector.MySQLConnection( ... 重要:构造cnx = mysql.connector.connect( ... 不能通过 SSh 工作!这是一个错误.(文档在这里: https : //dev.mysql.com/doc/connector-python/en/connector-python-connectargs.html )。

Also, your SQL statement must be ideal.此外,您的 SQL 语句必须是理想的。 In case of an error on SQL server side, you do not receive an error message from SQL-server.如果 SQL 服务器端出现错误,您不会收到来自 SQL 服务器的错误消息。

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()

Paramiko is the best python module to do ssh tunneling. Paramiko 是执行 ssh 隧道的最佳 Python 模块。 Check out the code here: https://github.com/paramiko/paramiko/blob/master/demos/forward.py在此处查看代码: https : //github.com/paramiko/paramiko/blob/master/demos/forward.py

As said in comments this one works perfect.正如评论中所说,这个完美无缺。 SSH Tunnel for Python MySQLdb connection 用于 Python MySQLdb 连接的 SSH 隧道

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()

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(... .如果您使用 Oracle 中的 python mysql.connector ,那么您必须使用构造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:重要提示:构造cnx = mysql.connector.connect(...无法通过 SSH 工作:这个错误让我花了一整天的时间试图理解为什么连接被远程服务器丢弃:

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).如果您使用的是 python,并且所有用户名、密码、主机和端口都是正确的,那么只剩下一件事了,那就是使用参数 (use_pure=True)。 This argument uses python to parse the details and password.此参数使用 python 来解析详细信息和密码。 You can see the doc of mysql.connector.connect() arguments.您可以查看 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()

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM