如何使用 Python 和 Paramiko 创建 SSH 隧道?

Posted

技术标签:

【中文标题】如何使用 Python 和 Paramiko 创建 SSH 隧道?【英文标题】:How to create a SSH tunnel using Python and Paramiko? 【发布时间】:2011-12-31 11:14:37 【问题描述】:

我需要创建隧道以从数据库中读取信息。我使用 Paramiko,但我还没有使用过隧道。请提供一个创建和关闭隧道的简单代码示例。

【问题讨论】:

您是在寻找服务器还是客户端,或者两者兼而有之?您确定在 Python 中需要它吗?使用 SSH 建立隧道怎么样? 试试pip install sshtunnel 【参考方案1】:

在工作中,我们通常会创建 ssh 隧道转发端口。我们这样做的方式是,使用标准命令ssh -L port:addr:port addr,子进程在单独的线程中运行。 我发现了这个有用的链接:https://github.com/paramiko/paramiko/blob/master/demos/forward.py,其中有一个使用 paramiko 进行端口转发的示例。

【讨论】:

感谢您的链接,但我无法运行此代码。他提出论据。但我输入的论点不起作用。举个例子请行发射。 示例:此命令:“ssh -L 5555:machine2:55 machine1”将连接到 machine1:22,并将从您的计算机:5555 到 machine1:22 的任何连接转发到 machine2:55。假设您要将自己的 ssh 服务转发到另一个端口,执行此操作的命令是:“ssh -L 5555:localhost:22 localhost”。因此,如果您执行“ssh localhost -p 5555”,它会将您连接到您自己的 localhost:22。要使用 paramiko“forward.py”演示执行此操作,您必须以这种方式运行它:“python forward.py localhost - p 5555 -r 本地主机:22"。执行它并在另一个终端运行 ssh localhost -p 5555 @dario 使用 -L1、-L2、-Ln 创建多个转发?【参考方案2】:

我在我的项目中使用了sshtunnel。将远程本地 mysql 端口转发到主机本地端口的示例:

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

【讨论】:

【参考方案3】:

尽管这不使用 paramiko,但我相信它是一个非常干净的实现解决方案(类似于 @dario's answer,但无需在 python 中管理线程)。

openssh 客户端中有一个鲜为人知的功能,它允许我们通过 unix 套接字控制 ssh 进程,引用 man ssh:

-M      Places the ssh client into “master” mode for connection sharing.  Multiple -M options places ssh
         into “master” mode with confirmation required before slave connections are accepted.  Refer to the
         description of ControlMaster in ssh_config(5) for details.
-S ctl_path
         Specifies the location of a control socket for connection sharing, or the string “none” to disable
         connection sharing.  Refer to the description of ControlPath and ControlMaster in ssh_config(5)
         for details.

因此您可以启动ssh(使用-Nf)的后台进程,然后使用另一个ssh 调用来检查(或终止)它。

我在需要建立反向隧道的项目中使用它

from subprocess import call, STDOUT
import os
DEVNULL = open(os.devnull, 'wb')


CONFIG = dict(
    SSH_SERVER='ssh.server.com',
    SSH_PORT=2222,
    SSH_USER='myuser',
    SSH_KEY='/path/to/user.key',
    REMOTE_PORT=62222,
    UNIX_SOCKET='/tmp/ssh_tunnel.sock',
    KNOWN_HOSTS='/path/to/specific_known_host_to_conflicts',
)


def start():
    return call(
        [
            'ssh', CONFIG['SSH_SERVER'],
            '-Nfi', CONFIG['SSH_KEY'],
            '-MS', CONFIG['UNIX_SOCKET'],
            '-o', 'UserKnownHostsFile=%s' % CONFIG['KNOWN_HOSTS'],
            '-o', 'ExitOnForwardFailure=yes',
            '-p', str(CONFIG['SSH_PORT']),
            '-l', CONFIG['SSH_USER'],
            '-R', '%d:localhost:22' % CONFIG['REMOTE_PORT']
        ],
        stdout=DEVNULL,
        stderr=STDOUT
    ) == 0


def stop():
    return __control_ssh('exit') == 0


def status():
    return __control_ssh('check') == 0


def __control_ssh(command):
    return call(
        ['ssh', '-S', CONFIG['UNIX_SOCKET'], '-O', command, 'x'],
        stdout=DEVNULL,
        stderr=STDOUT
    )

-o ExitOnForwardFailure=yes确保隧道无法建立时ssh命令会失败,否则不会退出。

【讨论】:

我对这个解决方案很感兴趣。连接后,如何向服务器发送命令?例如:“ifconfig”并将输出返回到我的客户端?谢谢。【参考方案4】:

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

pip install pyngrok

并使用它:

from pyngrok import ngrok

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

【讨论】:

这比 sshtunnel 有什么优势?我已经有一个付费的 ngrok 帐户了。【参考方案5】:

我在一年前的某个项目中使用了paramiko,这是我与另一台计算机/服务器连接并执行一个简单的python文件的代码部分:

import paramiko

ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(hostname='...', username='...', password='...')
stdin, stdout, stderr = ssh.exec_command('python hello.py')
ssh.close()

stdinstdoutsdterr 包含您执行的命令的输入/输出。

从这里,我想你可以和数据库建立连接了。

Here is some good information about paramiko.

【讨论】:

这如何回答这个问题?

以上是关于如何使用 Python 和 Paramiko 创建 SSH 隧道?的主要内容,如果未能解决你的问题,请参考以下文章

python3之paramiko模块

python中paramiko模块的使用

Python 学习笔记 - Paramiko 模块

python的paramiko模块简单应用

python(paramiko模块的简单使用)

使用 SFTP 和 Paramiko Python 获取递归文件夹