web-dev-qa-db-ja.com

マルチホップsshトンネルを使用してデータベースに到達する

ジャンプホストを介してのみアクセスできるリモートサーバーがいくつかあります。このリモートサーバーで、ローカルにアクセスしたいデータベースをホストするvmsを実行します。各ボックスはLinuxシステムです。私は自分のローカルPC、リモートホストとそのvmsに対してのみsu権限を持っています。

つまり、セットアップは次のようになります。

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

通常、私は3回sshを実行してから、mysqlcliを使用します。

次に、ローカルPCからデータベースをホストするボックスへのトンネルを設定する必要があります。

最終的には、python lib ssh-tunnel とそのクラスSSHTunnelForwarderのようなものを使用したいのですが、bashコマンドから始めてこの種のプロキシをセットアップしたいと思います。

Ssh認証はパスワードベースであり、ホップごとに異なるユーザーが必要です。理想的には、ソリューションは〜/ .ssh/configへの変更を必要としないでしょう

私はこれを見つけました post 、そして私はオプション3が私が必要とするものにかなり近いと思います。

それを明確にするための例。ジャンプホストが次のようになっているとしましょう:[email protected]、私のリモートホストは[email protected]そしてデータベース付きのVMは[email protected]

私が試みることは:

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

ローカルPCポート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のトンネルを経由してVMのポート3306にトンネルします。

その後、私が理解している限り、ローカルPCから127.0.0.1:3306でVM上のデータベースにアクセスできるはずです。

私はそれが理にかなっていることを願っています、私はすべての答えに感謝しています。

1
elmo26

これのおかげで私はそれを解決することができました post

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に設定されていることを確認してください。

1
elmo26

Pythonについてはわかりませんが、最新のsshにはProxyJumpディレクティブがあります。

これは、私の~/.ssh/configファイルの1つからの匿名化されたスニペットです。

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に基づくトンネル)を内部サーバーに確立してから、そのトンネルを介して内部サーバーに接続します。

0
sitaram