通过ssh隧道访问远程数据库(Python 3)

8

即使阅读了几篇关于ssh隧道的文章,我仍然无法理解这个脚本中CLI ssh命令的哪些参数。基本上,我需要通过ssh隧道连接到某个服务器(我称其为'ssh_tunnel_host:22'),然后使用此隧道连接到db_host。

with SSHTunnelForwarder(
    ('ssh_tunnel_host', 22),
    ssh_username="ssh_username",
    ssh_pkey="/somepath/id_rsa",
    local_bind_address=('0.0.0.0', 1234),
    remote_bind_address=('127.0.0.1', 3306)
) as tunnel:
    client = paramiko.SSHClient()
    client.load_system_host_keys()
    client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    client.connect('127.0.0.1', 1234)
    db_connection = pymysql.connect(host=db_host, port=3306, db='mysql', user='user',
                                    password='password', charset='utf8mb4')

请问:

  1. local_bind_address是什么 - 是我的本地地址还是ssh_tunnel_host的本地地址?我在哪里可以找到IP和端口号?
  2. 根据上一个问题 - remote_bind_address是什么 - 是ssh_tunnel_host或db_host的地址?我在哪里可以找到这些IP和端口号?
  3. 我应该使用client.connect()连接到哪里?本地绑定还是远程绑定?

(我尝试阅读文档但仍然不清楚)

2个回答

16

类比为代理连接。您连接到ssh_tunnel_host:22,并要求它代理从其<db host>:3306(即db_host的3306端口)访问的内容,由ssh_tunnel_host提供给您,即客户端。

您可以指定本地(对于您而言)想要代理连接可用的IP地址和端口,或者让客户端选择一个空闲的端口。省略local_bind_address会自动选择可用的端口。

然后,您连接到实际上是代理到remote_bind_address:3306的本地端口。

local_bind_address <-> ssh_tunnel_host <-> remote_bind_address

代码应该如下:

db_host = '<address reachable only by ssh_tunnel_host>'
with SSHTunnelForwarder(
    ('ssh_tunnel_host', 22),
    ssh_username="ssh_username",
    ssh_pkey="/somepath/id_rsa",
    remote_bind_address=(db_host, 3306)
) as tunnel:
    port = tunnel.local_bind_port
    db_connection = pymysql.connect(
        host='127.0.0.1', port=port, db='mysql', user='user',
        password='password', charset='utf8mb4')
  1. 本地到客户端地址。设置一个地址,或让客户端选择并从 tunnel.local_bind_port 找到其端口。

  2. 您希望ssh_tunnel_host代理回您的地址。如果是服务器本地服务,则IP将为127.0.0.1和服务端口。它也可以是任何其他IP或ssh_tunnel_host网络中不可见于SSH隧道主机外部的IP。

  3. 没有。该隧道提供了一个本地IP:端口,用于代理远程连接。一旦建立了隧道,就不需要其他客户端。只需连接到本地IP:端口即可。


现在无法尝试您的建议。但是为什么数据库主机不参与连接链呢? - Vladimir Kolenov
ssh_tunnel_host看,DB主机不是127.0.0.1:3306吗?否则它是如何被隧道化的。根据(2),如果DB主机不是隧道主机的本地主机,则需要将其作为远程绑定地址,即remote_bind_address=(db_host, 3306) - danny
谢谢,最终我连接到了我的数据库,并将db_host设置为remote_bind_address主机 - 我想我没有清楚地说出我的数据库不在ssh_tunnel_host上,而是在另一台只能通过ssh_tunnel_host访问的服务器上:remote_bind_address =(db_host,3306) - Vladimir Kolenov
感谢您澄清,已更新答案以反映这一点。 - danny

-1

我们的情况类似,我已经厌倦了在尝试连接到 MS Sqlserver 数据库之前确保 SSH 隧道正常运行。因此,我们有一个远程服务器(ip1),在该服务器上安装了一个带有 MSSqlserver 的 docker。当然,当您登录该服务器时,可以将 docker ip 转发到该机器上的 localhost。因此,如果您在 ip1 内部,则可以将服务器访问为 localhost。

所有版本的 MS Sqlserver 强制执行端口 1433 作为访问端口。

因此,您有 ip1->localhost:1433->MSSqlserver

因此,SSH 创建了一个隧道,以使用简单的 SSH user@ip1 访问 ip1,但是您需要转发 remoteserver 上的 localhost:1433,以使其像本地操作。

from sshtunnel import SSHTunnelForwarder
import values

server = SSHTunnelForwarder(
    (values.remote_server_ip, values.remote_server_port),
    ssh_username=values.remote_server_username,
    ssh_pkey=values.rsa_path+values.rsa_file,
    ssh_private_key_password=values.rsa_passphrase,
    remote_bind_address=(values.private_server_ip, values.private_server_port),
    local_bind_address=(values.db_server_ip, values.db_server_port) )
try:
    server.start()
except:
    print("trouble connecting to the tunnel. we will asume it is already up")
else:
    print("server is started and on port ",server.local_bind_port)  # show assigned local port

在这里做一些工作然后

try:
    server.stop()
except:
    print("could not stop the server. assume it is already down")
else:
    print("stopped the server successfully")

而 values.py 包含值为

remote_server_ip = "....remote ip...."
remote_server_port = 22
private_server_ip = "localhost"
private_server_port = 1433
db_server_ip = "localhost"
db_server_port = 1433
remote_server_username = "...."
rsa_passphrase = "...."
rsa_path = "˜/.ssh/"
rsa_file = "id_rsa"

尝试/捕获异常是一个非常糟糕的想法。 - nck

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接