使用多跳 ssh 隧道访问数据库

使用多跳 ssh 隧道访问数据库

我们有一些只能通过跳转主机访问的远程服务器。在这些远程服务器上运行虚拟机,这些虚拟机托管我想要本地访问的数据库。每个盒子都是一个 Linux 系统。我在本地 PC、远程主机及其虚拟机上只有 su 权限。

这意味着我们的设置如下所示:

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

通常我会 ssh 三次,然后使用 mysql cli。

现在我需要从我的本地电脑到托管数据库的盒子建立一个隧道。

最终我想使用类似 python 库的东西ssh-隧道及其类 SSHTunnelForwarder。但我想从 bash 命令开始设置这种代理。

ssh 身份验证基于密码,每次跳转都需要不同的用户。理想情况下,解决方案不需要更改 ~/.ssh/config

我发现这个邮政,我认为选项 3 非常接近我的需要。

举个例子来说明。假设 jumphost 是:[email protected],我的远程主机是[email protected],带有数据库的虚拟机是[email protected]

我会尝试的是:

ssh -L 9998:172.1.1.1:22 -N [email protected]

从我的本地电脑端口 9998 到远程主机上的端口 22 建立隧道

我的问题就在这里,我该如何指定用于下一个 ssh 隧道的用户。有人能给我指明正确的方向吗?

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

从我的本地 PC 端口 9999 通过第一个隧道到远程主机上的端口 22

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

从本地 PC 端口 10000 通过端口 9999 上的隧道到达虚拟机上的端口 3306。

据我所知,之后我应该能够从本地电脑通过 127.0.0.1:3306 访问虚拟机上的数据库。

我希望这是有意义的,我感谢每一个答案。

答案1

我能解决这个问题,多亏了这个邮政

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

确保在您使用的每个跃点上将 AllowTcpForwarding 设置为 On。

答案2

我不知道 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 inside(或scp inside:foo bar、或 rsync、或 git 或其他),它“就可以正常工作”(TM)!Ssh 首先自动连接到堡垒,建立到内部服务器的隧道(不是 TCP 端口转发,而是基于 STDIN/STDOUT 的隧道),然后通过该隧道连接到内部服务器。

答案3

这应该可以做到:

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

这将vm使用jumphost&作为代理通过 SSH 连接到 。然后它将上的remotehostTCP 端口与本地 PC 上的端口连接起来。3306vm3306

相关内容