2016-11-16 18 views
1

我有一个远程MySQL数据库托管在Amazon RDS(“D”)上。出于安全目的,它只能通过远程服务器(“C”)访问。 C可以通过ssh通过跳转主机“B”访问。我需要一个双重ssh隧道才能访问远程SQL主机。带跳转主机和远程数据库的SSH隧道转发

[A: local host] -> [B: jump host] -> [C: target host] => [D: RDS MySQL host] 

我想通过Python访问D,使用paramiko和/或sshtunnel。所有的我能找到的信息包括:

到目前为止,我使用的是代理命令的paramiko从A到C.我可以通过执行命令访问d在C上,而不是通过连接mysqldb或sqlalchemy(我的最终目标)。

我当前的代码:

import paramiko 

ssh = paramiko.SSHClient() 
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 
proxy = paramiko.ProxyCommand("ssh -A [email protected]_host -W C_host:12345") 
ssh.connect("C_host", username="C_username", sock=proxy) 

stdin, stdout, stderr = ssh.exec_command("mysql -u D_username -p D_password -h D_host_rds") 
print("STDOUT:\n{}\n\nSTDERR:\n{}\n".format(stdout.read(), stderr.read())) 
# successfully prints out MySQL welcome screen 

我正在寻找这样的事情(在sshtunnel docs从例如2修改):

import paramiko 
from sshtunnel import SSHTunnelForwarder 

with SSHTunnelForwarder(
    intermediate = { 
     ("B_host", 22), 
     ssh_username = "B_username", 
     ssh_password = "B_password")}, 
    remote = { 
     ("C_host", 12345), 
     ssh_username = "C_username", 
     ssh_password = "C_password")}, 
    remote_bind_address=("D_host_rds", 3306), 
    local_bind_address=("0.0.0.0", 3307)) as server: 

    conn = MySQLdb.connect(
     user = "D_username", 
     passwd = "D_password", 
     db = "my_database", 
     host = "127.0.0.1", 
     port = 3307) 

TL;博士:我如何前进一个端口通过Python中的两个ssh跳转?

回答

2

我想通了。它可以与ssh config设置和sshtunnel库中的SSHTunnelForwarder上下文管理器结合使用。

Using the following model and naming conventions

[A: local host] -> [B: jump host] -> [C: target host] => [D: RDS MySQL host]

设置我的〜/ .ssh/config来通过B,从A到C:

Host C_ssh_shortcut 
    HostName C_host 
    User C_user 
    Port 22 
    ForwardAgent yes 
    ProxyCommand ssh [email protected]_host -W %h:%p 

我添加了键/键我用登录到B和C到我的ssh代理:

ssh-add 

最后我设置你p SSHTunnelForwarder:

import sqlalchemy 
from sshtunnel import SSHTunnelForwarder 

with SSHTunnelForwarder(
    "C_ssh_shortcut",      # The SSHTunnelForwarder "ssh_address_or_host" argument, which takes care of bypassing B through the ProxyCommand set up in ~/.ssh/config 
    remote_bind_address=(D_host, 3306), # Points to your desired destination, ie. database host on 3306, which is the MySQL port 
    local_bind_address=('', 1111)   # Gives a local way to access this host and port on your machine. '' is localhost/127.0.0.1, 1111 is an unused port 
) as server: 
    connection_string = "mysql+pymysql://D_user:[email protected]:1111/D_dbname" # note that D_host and D_port were replaced by the host and port defined in "local_bind_address" 
    engine = sqlalchemy.create_engine(connection_string) 
    # do your thing 

从这里,我能够像往常一样使用我的引擎与我的数据库进行交互。

0

您是否找出解决方案?如果是这样,你可以发布它吗?

我目前正在研究这样的事情,并且有一些涉及端口转发的想法。例如,在我的〜/ .ssh/config文件中,我有如下所示的内容。这使我可以通过使用端口转发的中间方法从我的本地到远程直接ssh,即不必首先ssh到中间。

所以现在我可以通过终端中的ssh从本地连接到远程。现在,我正在以编程方式直接从本地到远程进行隧道传输。我希望Python和我的ssh配置文件可以很好地发挥作用,并允许我使用端口转发技巧。如果我得到这个工作,我会跟进我的代码。

(我假设你在Linux或者MacOS。我不知道Windows如何处理它的SSH密钥和配置文件。)

Host remote 
    HostName <remote_host.org> 
    User <username> 
    Port 22 
    ForwardAgent yes 
    ProxyCommand ssh <intermediate> nc %h %p 

Host intermediate 
    HostName <intermediate_host.org> 
    User <username> 
# IdentityFile ~/.ssh/id_rsa 
    ControlMaster auto 
    ControlPath ~/.ssh/master-%[email protected]%h:%p 
    ControlPersist 30m 
+1

我想出了[答案](https://stackoverflow.com/a/44739471/6412017) – blep