Использование многоузлового ssh-туннеля для доступа к базе данных

У нас есть несколько удаленных серверов, которые доступны только через jumphost. На этих удаленных серверах запускаются виртуальные машины, на которых размещаются базы данных, к которым я хочу подключиться локально. Каждая коробка - это система Linux. У меня есть только права su на моем локальном компьютере, на удаленном хосте и его виртуальной машине.

Это означает, что наша установка выглядит так:

My local pc --> jumphost --> remotehost --> vm with mysql on 127.0.0.1:3306

Обычно я использую ssh три раза, а затем использую mysql cli.

Теперь мне нужно настроить туннель от моего локального компьютера к ящику, на котором размещена база данных.

В конечном итоге я хочу использовать что-то вроде python lib ssh-tunnel и его класса SSHTunnelForwarder. Но я хочу начать с команд bash для настройки такого прокси.

Аутентификация ssh основана на пароле, и для каждого перехода требуется другой пользователь. В идеале решение не потребует изменений в ~ / .ssh / config

Я нашел этот пост , и я думаю, что варианты 3 довольно близки к тому, что мне нужно.

Пример его создания Чисто. Скажем, jumphost: (скрыт) мой удаленный хост (скрыт), а виртуальная машина с базой данных (скрыта), я бы попробовал:

ssh -L 9998:172.1.1.1:22 -N user1@192.168.11.29

туннель от моего локального порта ПК 9998 до порта 22 на удаленном хосте

Здесь начинается Моя проблема, как мне указать пользователя, используемого для следующих туннелей ssh. Может ли кто-нибудь направить меня в правильном направлении?

ssh -L 9999:10.100.1.1:22-N -p 9998 user2@localhost

туннель от моего локального ПК-порта 9999 через первый туннель к порту 22 на удаленном хосте

ssh -L 10000:locahost:3306 -N -p 9999 user3@localhost

Туннель от локального ПК-порта 10000 через туннель на порту 9999 к порту 3306 на виртуальной машине.

После этого я должен иметь возможность получить доступ к базе данных на виртуальной машине с 127.0.0.1:3306 с моего локального компьютера, насколько я понимаю.

Надеюсь, это имеет смысл, я благодарен за каждый ответ.

1
задан 6 September 2019 в 17:34
3 ответа

Я смог решить эту проблему благодаря этому сообщению

class TunnelNetwork(object):
    def __init__(self, tunnel_info, target_ip, target_port):
        self.tunnel_info = tunnel_info
        self.target_ip = target_ip
        self.target_port = target_port


    def start_tunnels(self):
        self.tunnels = []
        for idx, info in enumerate(self.tunnel_info):
            # if we're not the first element, set the bastion to the local port of the previous tunnel
            if idx > 0:
                info['ssh_address_or_host'] = ('localhost', self.tunnels[-1].local_bind_port)
            # if we are the last element, the target is the real target
            if idx == len(self.tunnel_info) - 1:
                target = (self.target_ip, self.target_port)
            # else, the target is the next bastion
            else:
                if isinstance(self.tunnel_info[idx+1]['ssh_address_or_host'], tuple):
                    target = self.tunnel_info[idx+1]['ssh_address_or_host']
                else:
                    target = (self.tunnel_info[idx+1]['ssh_address_or_host'], 22)

            self.tunnels.append(SSHTunnelForwarder(remote_bind_address=target, **info))
            try:
                self.tunnels[idx].start()
            except:
                return False

        return True

    def stop_tunnels(self):
        for tunnel in reversed(self.tunnels):
            tunnel.stop()    


    def are_tunnels_active(self):
        return self.tunnels and all([t.is_active for t in self.tunnels])


    def get_local_connect_port(self):
        if self.tunnels:
            return self.tunnels[-1].local_bind_port
        else:
            return None

И используйте его с:

tunnel_i = [
    {"ssh_address_or_host": "192.168.11.29",
     "ssh_username": "user1",
     "ssh_password": "",
    },
    {"ssh_address_or_host": "172.1.1.1 ",
     "ssh_username": "user2",
     "ssh_password": "",
    },
    {"ssh_address_or_host": "10.100.1.1",
     "ssh_username": "user3",
     "ssh_password": "",
    }
]

target_ip = "127.0.0.1"
target_port = 3306

tn = TunnelNetwork(tunnel_i, target_ip, target_port)

tn.start_tunnels()

Make убедитесь, что для параметра AllowTcpForwarding установлено значение «Вкл.» на каждом используемом переходе.

1
ответ дан 3 December 2019 в 23:00

Я не знаю о python, но современный ssh ​​имеет директиву ProxyJump .

Вот фрагмент с некоторой анонимизацией из одного из моих ~ /.ssh/config файлов.

host bastion
    user sitaram
    hostname 1.2.3.4
    # external IP of bastion host

host inside
    user not-sitaram
    hostname 172.16.17.18
    # IP of "inside" as seen from "bastion" server
    proxyjump bastion

После этогоЯ просто говорю ssh внутри (или scp внутри: foo bar , или rsync, или git, или что-то еще), и он «просто работает» (TM)! Ssh сначала автоматически подключается к бастиону, устанавливая - не переадресацию порта TCP, а туннель на основе STDIN / STDOUT - к внутреннему серверу, а затем подключается через этот туннель к внутреннему серверу.

0
ответ дан 3 December 2019 в 23:00

Это должно сделать это:

ssh -J jumphost,remotehost vm -L 3306:localhost:3306

Это SSH для vm, используя jumphost и remotehost в качестве прокси. Затем он соединяет TCP-порт 3306 на vm с портом 3306 на локальном компьютере.

0
ответ дан 3 July 2020 в 00:34

Теги

Похожие вопросы