如何使用 python 打开 SSH 隧道?

发布于 2024-10-06 12:45:28 字数 104 浏览 3 评论 0原文

我正在尝试使用 django 连接到远程 mysql 数据库。
文档规定需要先打开SSH隧道才能连接数据库。
是否有一个 python 库可以在设置某些设置时打开 SSH 隧道?

I am trying to connect to a remote mysql database using django.
The documentation specifies that it is required to open an SSH tunnel first to connect to the database.
Is there a python library that can open an SSH tunnel whenever certain settings are set?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

黑白记忆 2024-10-13 12:45:28

你可以尝试 paramiko转发 功能。有关 paramiko 概述,请参阅 这里

You could try paramiko's forward functionality. For a paramiko overview, see here.

秉烛思 2024-10-13 12:45:28

尝试使用 sshtunnel 包

这很简单:

pip install sshtunnel
python -m sshtunnel -U vagrant -P vagrant -L :3306 -R 127.0.0.1:3306 -p 2222 localhost

披露:我是这个包的作者和维护者。

Try use sshtunnel package.

This is simple:

pip install sshtunnel
python -m sshtunnel -U vagrant -P vagrant -L :3306 -R 127.0.0.1:3306 -p 2222 localhost

Disclosure: I'm the author and maintainer of this package.

情栀口红 2024-10-13 12:45:28

这是 Python3 的代码片段(但您应该能够毫无困难地将其改造为 Python2)。它在单独的线程中运行 SSH 隧道;然后主线程执行一些操作来通过 SSH 隧道获取网络流量。

在此示例中,ssh 隧道将本地端口 2222 转发到本地主机上的端口 80。主要活动包括运行

curl http://localhost:2222

,即从端口 2222 获取网页。SshTunnel

类使用 4 个参数进行初始化:本地和远程端口、远程用户和远程主机。它所做的就是通过以下方式启动 SSH:

ssh -N -L localport:remotehost:remoteport remoteuser@remotehost

为了使这项工作正常进行,您需要对远程用户@远程主机进行无密码登录(通过远程服务器上已知的 ~/.ssh/id_rsa.pub)。
这样运行的 ssh 隧道是在一个线程上;主要任务必须在另一项任务中。 ssh 隧道线程被标记为守护进程,以便一旦主活动终止它就会自动停止。

我没有提供完整的 MySQL 连接示例,因为它应该是不言自明的。一旦 SshTunnel 设置了本地 TCP 端口,您就可以通过 MySQL 客户端、curl 或其他方式连接到它。

import subprocess
import time
import threading

class SshTunnel(threading.Thread):
    def __init__(self, localport, remoteport, remoteuser, remotehost):
        threading.Thread.__init__(self)
        self.localport = localport      # Local port to listen to
        self.remoteport = remoteport    # Remote port on remotehost
        self.remoteuser = remoteuser    # Remote user on remotehost
        self.remotehost = remotehost    # What host do we send traffic to
        self.daemon = True              # So that thread will exit when
                                        # main non-daemon thread finishes

    def run(self):
        if subprocess.call([
            'ssh', '-N',
                   '-L', str(self.localport) + ':' + self.remotehost + ':' + str(self.remoteport),
                   self.remoteuser + '@' + self.remotehost ]):
            raise Exception ('ssh tunnel setup failed')


if __name__ == '__main__':
    tunnel = SshTunnel(2222, 80, 'karel', 'localhost')
    tunnel.start()
    time.sleep(1)
    subprocess.call(['curl', 'http://localhost:2222'])

Here is a code snippet for Python3 (but you should be able to retrofit it into Python2 without difficulty). It runs an SSH tunnel in a separate thread; then the main thread does something to get network traffic over the SSH tunnel.

In this example, the ssh tunnel forwards local port 2222 to port 80 on localhost. The main activity consists of running

curl http://localhost:2222

ie., fetching a webpage but from port 2222.

The class SshTunnel is initialized with 4 parameters, the local and remote port, the remote user, and the remote host. All it does, is start SSH in the following way:

ssh -N -L localport:remotehost:remoteport remoteuser@remotehost

In order to make this work, you'll need a password-less login for remoteuser@remotehost (via ~/.ssh/id_rsa.pub that's known on the remote server).
The thus running ssh tunnel is on one thread; the main task must be in another one. The ssh tunnel thread is marked as daemon so that it will automatically stop once the main activity terminates.

I didn't put in a full MySQL connectivity example because it should be self-explanatory. Once SshTunnel sets up a local TCP port, you can connect to it - be it via your MySQL client, curl, or whatever.

import subprocess
import time
import threading

class SshTunnel(threading.Thread):
    def __init__(self, localport, remoteport, remoteuser, remotehost):
        threading.Thread.__init__(self)
        self.localport = localport      # Local port to listen to
        self.remoteport = remoteport    # Remote port on remotehost
        self.remoteuser = remoteuser    # Remote user on remotehost
        self.remotehost = remotehost    # What host do we send traffic to
        self.daemon = True              # So that thread will exit when
                                        # main non-daemon thread finishes

    def run(self):
        if subprocess.call([
            'ssh', '-N',
                   '-L', str(self.localport) + ':' + self.remotehost + ':' + str(self.remoteport),
                   self.remoteuser + '@' + self.remotehost ]):
            raise Exception ('ssh tunnel setup failed')


if __name__ == '__main__':
    tunnel = SshTunnel(2222, 80, 'karel', 'localhost')
    tunnel.start()
    time.sleep(1)
    subprocess.call(['curl', 'http://localhost:2222'])
残疾 2024-10-13 12:45:28

这里有一个小类,您可以将其放入代码中:

import subprocess
import random
import tempfile

class SSHTunnel:

    def __init__(self, host, user, port, key, remote_port):
        self.host = host
        self.user = user
        self.port = port
        self.key = key
        self.remote_port = remote_port
        # Get a temporary file name
        tmpfile = tempfile.NamedTemporaryFile()
        tmpfile.close()
        self.socket = tmpfile.name
        self.local_port = random.randint(10000, 65535)
        self.local_host = '127.0.0.1'
        self.open = False

    def start(self):
        exit_status = subprocess.call(['ssh', '-MfN',
            '-S', self.socket,
            '-i', self.key,
            '-p', self.port,
            '-l', self.user,
            '-L', '{}:{}:{}'.format(self.local_port, self.local_host, self.remote_port),
            '-o', 'ExitOnForwardFailure=True',
            self.host
        ])
        if exit_status != 0:
            raise Exception('SSH tunnel failed with status: {}'.format(exit_status))
        if self.send_control_command('check') != 0:
            raise Exception('SSH tunnel failed to check')
        self.open = True

    def stop(self):
        if self.open:
            if self.send_control_command('exit') != 0:
                raise Exception('SSH tunnel failed to exit')
            self.open = False

    def send_control_command(self, cmd):
        return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.user, self.host])

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, type, value, traceback):
        self.stop()

以下是如何使用它,例如使用 MySQL(通常是端口 3306):

with SSHTunnel('database.server.com', 'you', '22', '/path/to/private_key', '3306') as tunnel:
    print "Connected on port {} at {}".format(tunnel.local_port, tunnel.local_host)

Here's a little class that you can drop into your code:

import subprocess
import random
import tempfile

class SSHTunnel:

    def __init__(self, host, user, port, key, remote_port):
        self.host = host
        self.user = user
        self.port = port
        self.key = key
        self.remote_port = remote_port
        # Get a temporary file name
        tmpfile = tempfile.NamedTemporaryFile()
        tmpfile.close()
        self.socket = tmpfile.name
        self.local_port = random.randint(10000, 65535)
        self.local_host = '127.0.0.1'
        self.open = False

    def start(self):
        exit_status = subprocess.call(['ssh', '-MfN',
            '-S', self.socket,
            '-i', self.key,
            '-p', self.port,
            '-l', self.user,
            '-L', '{}:{}:{}'.format(self.local_port, self.local_host, self.remote_port),
            '-o', 'ExitOnForwardFailure=True',
            self.host
        ])
        if exit_status != 0:
            raise Exception('SSH tunnel failed with status: {}'.format(exit_status))
        if self.send_control_command('check') != 0:
            raise Exception('SSH tunnel failed to check')
        self.open = True

    def stop(self):
        if self.open:
            if self.send_control_command('exit') != 0:
                raise Exception('SSH tunnel failed to exit')
            self.open = False

    def send_control_command(self, cmd):
        return subprocess.check_call(['ssh', '-S', self.socket, '-O', cmd, '-l', self.user, self.host])

    def __enter__(self):
        self.start()
        return self

    def __exit__(self, type, value, traceback):
        self.stop()

And here's how you could use it, for example with MySQL (port 3306 usually):

with SSHTunnel('database.server.com', 'you', '22', '/path/to/private_key', '3306') as tunnel:
    print "Connected on port {} at {}".format(tunnel.local_port, tunnel.local_host)
二智少女猫性小仙女 2024-10-13 12:45:28

这个解决方案对我有用。

在终端/CMD 中运行此命令:
pip install paramiko

然后创建一个 python 文件并在该文件中添加以下代码:

import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('server_ip', username='root', password='password')

现在运行 python 文件: python yourfile.py

This solution worked for me.

Run this command in your terminal/CMD:
pip install paramiko

Then create a python file and add this code in that file:

import paramiko
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('server_ip', username='root', password='password')

Now run the python file: python yourfile.py

凑诗 2024-10-13 12:45:28

我是否可以建议尝试像 pyngrok 这样的东西以编程方式为您管理 ngrok 隧道?完全公开,我是它的开发者。 SSH 示例此处,以及 Django 示例此处,但它就像安装 pyngrok 一样简单:

pip install pyngrok

并使用它:

from pyngrok import ngrok

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12345" -> "localhost:22">
ssh_tunnel = ngrok.connect(22, "tcp")

或者公开您的 MySQL 数据库:

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12346" -> "localhost:3306">
mysql_tunnel = ngrok.connect(3306, "tcp")

或者公开 Django 开发服务器:

# <NgrokTunnel: "http://<public_sub>.ngrok.io" -> "http://localhost:8000">
http_tunnel = ngrok.connect(8000)

Might I suggest trying something like pyngrok to programmatically manage an ngrok tunnel for you? Full disclosure, I am the developer of it. SSH example here, and Django example here, but it's as easy as installing pyngrok:

pip install pyngrok

and using it:

from pyngrok import ngrok

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12345" -> "localhost:22">
ssh_tunnel = ngrok.connect(22, "tcp")

Or to expose your MySQL database:

# <NgrokTunnel: "tcp://0.tcp.ngrok.io:12346" -> "localhost:3306">
mysql_tunnel = ngrok.connect(3306, "tcp")

Or to expose to Django dev server:

# <NgrokTunnel: "http://<public_sub>.ngrok.io" -> "http://localhost:8000">
http_tunnel = ngrok.connect(8000)
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文