如何复用已创建的SSH隧道执行远程命令并验证主机密钥?
自动化多远程VNC连接的问题与解决方案
需求背景
我正尝试自动化启动多台远程系统的VNC客户端,目前通过LocalForward 15900 127.0.0.1:5900实现端口转发,但因可能同时运行多个VNC查看器,本地端口需动态配置而非硬编码。计划实现脚本完成以下步骤:
- 查找未使用的本地端口(
freePort); - 以指定用户身份SSH连接到远程计算机;
- 创建从远程5900端口到本地
freePort的隧道; - 远程执行
x11vnc -xkb -display :0 -localhost命令; - 本地执行
vncviewer localhost:freePort命令。
已实现步骤1,并使用SSHTunnelForwarder完成隧道创建,现在需要解决两个问题:
- 如何复用已创建的SSH隧道执行远程命令,而非新建连接?
- 如何基于
known_hosts数据库验证远程主机密钥?
解决方案
复用已创建的SSH隧道执行远程命令
SSHTunnelForwarder基于paramiko实现,创建并启动隧道后,它的ssh_client属性就是已经建立好的SSH连接实例,直接用这个实例执行远程命令即可,完全不需要新建连接。示例代码如下:
from sshtunnel import SSHTunnelForwarder import socket import subprocess # 步骤1:获取空闲本地端口 def get_free_port(): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('', 0)) return s.getsockname()[1] free_port = get_free_port() # 配置并启动SSH隧道 with SSHTunnelForwarder( ('remote_host', 22), ssh_username='your_username', ssh_pkey='~/.ssh/id_rsa', # 优先用密钥登录,也可替换为ssh_password local_bind_address=('127.0.0.1', free_port), remote_bind_address=('127.0.0.1', 5900) ) as tunnel: # 复用已有SSH连接执行远程x11vnc命令 # 加&让命令后台运行,避免阻塞脚本 stdin, stdout, stderr = tunnel.ssh_client.exec_command( 'x11vnc -xkb -display :0 -localhost &' ) # 可选:捕获输出用于排查问题 print("命令输出:", stdout.read().decode()) print("错误信息:", stderr.read().decode()) # 步骤5:启动本地VNC查看器 subprocess.run(['vncviewer', f'localhost:{free_port}'])
基于known_hosts验证远程主机密钥
要让SSH连接严格遵循known_hosts的验证规则,需要加载本地的known_hosts文件,并配置paramiko的密钥验证策略,避免连接到不可信主机。示例代码如下:
from sshtunnel import SSHTunnelForwarder from paramiko import HostKeys, RejectPolicy import os import socket import subprocess def get_free_port(): with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s: s.bind(('', 0)) return s.getsockname()[1] free_port = get_free_port() # 加载本地known_hosts文件 known_hosts_path = os.path.expanduser('~/.ssh/known_hosts') host_keys = HostKeys(filename=known_hosts_path) # 配置带密钥验证的SSH隧道 with SSHTunnelForwarder( ('remote_host', 22), ssh_username='your_username', ssh_pkey='~/.ssh/id_rsa', local_bind_address=('127.0.0.1', free_port), remote_bind_address=('127.0.0.1', 5900), host_keys=host_keys, # 拒绝未知主机,若需自动添加可替换为AutoAddPolicy()(不推荐生产环境) missing_host_key_policy=RejectPolicy() ) as tunnel: # 执行远程命令与启动VNC逻辑同上 stdin, stdout, stderr = tunnel.ssh_client.exec_command( 'x11vnc -xkb -display :0 -localhost &' ) subprocess.run(['vncviewer', f'localhost:{free_port}'])
内容的提问来源于stack exchange,提问作者Mikhail T.
相关产品推荐
相关产品推荐

