Доступ к удаленной БД через туннель ssh (Python 3)

Я не могу понять (даже после прочтения нескольких статей, посвященных ssh-тюнингу), какие параметры CLI-команды 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()? Локальная или удаленная привязка?

(Я пытался читать документы, но это все еще беспорядок)


person Vladimir Kolenov    schedule 20.07.2017    source источник


Ответы (2)


Думайте об этом как о прокси-соединении. Вы подключаетесь к ssh_tunnel_host:22 и указываете ему прокси-подключения из его <db host>:3306, то есть порт 3306 на db_host, к которому ssh_tunnel_host обращается к вам, клиенту.

Вы можете либо указать локальный (для вас) ip:port, на котором должно быть доступно прокси-соединение, либо позволить клиенту выбрать свободный. Отсутствие 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-адрес или IP-адрес в сети ssh_tunnel_host, который не виден за пределами хоста туннеля SSH.

  3. Нигде. Туннель предоставляет локальный ip:port, который проксирует удаленное соединение. После того, как туннель запущен, никакой другой клиент не нужен. Просто подключитесь к локальному ip:port.

person danny    schedule 20.07.2017
comment
Не могу попробовать ваш совет прямо сейчас. Но почему db host не участвует в цепочке подключения? - person Vladimir Kolenov; 20.07.2017
comment
Разве хост БД 127.0.0.1:3306 не виден из ssh_tunnel_host? Как это туннелируется иначе. Согласно (2), если хост БД не является локальным по отношению к хосту туннеля, вам необходимо указать его в качестве адреса удаленной привязки, т.е. remote_bind_address=(db_host, 3306). - person danny; 20.07.2017
comment
Спасибо, наконец-то я подключился к своей БД, установил db_host в качестве хоста remote_bind_address - я думаю, что я не ясно сказал, что моя БД находится не на ssh_tunnel_host, на другом сервере, к которому я могу получить доступ только через ssh_tunnel_host: remote_bind_address=(db_host, 3306) - person Vladimir Kolenov; 21.07.2017
comment
Спасибо за уточнение, обновленный ответ, чтобы отразить это. - person danny; 21.07.2017

Наша ситуация аналогична, и я устал проверять, что туннель SSH запущен и работает, прежде чем пытаться подключиться к MS Sqlserver db. Итак, у нас есть удаленный сервер (ip1) и на нем мы установили докер с MSSqlserver. Естественно, когда вы входите на этот сервер, вы можете перенаправить IP-адрес докера на локальный хост на этом компьютере. Поэтому, если вы находитесь «внутри» ip1, вы можете получить доступ к серверу как localhost.

MS Sqlserver для всех версий использует порт 1433 в качестве порта доступа.

Итак, у вас есть ip1-›localhost:1433-›MSSqlserver

Таким образом, SSH создает туннель для доступа к ip1, используя простой SSH user@ip1, но вам нужно перенаправить 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"
person Koos Brandt    schedule 12.01.2021