
SSH-Tunnel zu einem entfernten Server.
|Tests| |AppVeyor| |readthedocs| |coveralls| |version|
|pyversions| |license|
Autor: Pahaz_
Repo: https://github.com/pahaz/sshtunnel/
Inspiriert von https://github.com/jmagnusson/bgtunnel, das unter Windows nicht funktioniert.
Siehe auch: https://github.com/paramiko/paramiko/blob/master/demos/forward.py
paramiko_sshtunnel_ ist auf PyPI verfügbar, führen Sie also einfach aus:
::
pip install sshtunnel
oder ::
easy_install sshtunnel
oder ::
conda install -c conda-forge sshtunnel
um es in Ihrer Umgebung zu installieren.
Für die Installation aus dem Quellcode klonen Sie das
Repo <https://github.com/pahaz/sshtunnel>_ und führen Sie aus::
python setup.py install
Um die Tests auszuführen, benötigen Sie zunächst
tox <https://testrun.org/tox/latest/>_ und führen Sie aus::
python setup.py test
Eines der typischen Szenarien, in denen sshtunnel hilfreich ist, ist in der
folgenden Abbildung dargestellt. Ein Benutzer muss möglicherweise eine Verbindung zu einem Port eines entfernten Servers (z. B. 8080) herstellen,
bei dem nur der SSH-Port (üblicherweise Port 22) erreichbar ist. ::
----------------------------------------------------------------------
|
-------------+ | +----------+
LOCAL | | | REMOTE | :22 SSH
CLIENT | <== SSH ========> | SERVER | :8080 web service
-------------+ | +----------+
|
FIREWALL (only port 22 is open)
----------------------------------------------------------------------
Abb1: Wie man über einen SSH-Tunnel eine Verbindung zu einem durch eine Firewall blockierten Dienst herstellt.
Wenn der SSH-Server es erlaubt, ist es auch möglich, einen privaten Server
(aus der Perspektive des REMOTE SERVER) zu erreichen, der von außen
(aus der Perspektive des LOCAL CLIENT) nicht direkt sichtbar ist. ::
----------------------------------------------------------------------
|
-------------+ | +----------+ +---------
LOCAL | | | REMOTE | | PRIVATE
CLIENT | <== SSH ========> | SERVER | <== local ==> | SERVER
-------------+ | +----------+ +---------
|
FIREWALL (only port 443 is open)
----------------------------------------------------------------------
Abb2: Wie man über einen SSH-Tunnel eine Verbindung zum PRIVATE SERVER herstellt.
Die API ermöglicht es, den Tunnel zu initialisieren und zu starten oder einen with-
Kontext zu verwenden, der sich um das Starten und Stoppen des Tunnels kümmert:
Der Code, der dem obigen Abb1 entspricht, folgt, wobei die Adresse des entfernten Servers
pahaz.urfuclub.ru lautet, Passwort-Authentifizierung verwendet wird und der lokale Bind-Port
zufällig zugewiesen wird.
.. code-block:: python
from sshtunnel import SSHTunnelForwarder
server = SSHTunnelForwarder(
'alfa.8iq.dev',
ssh_username="pahaz",
ssh_password="secret",
remote_bind_address=('127.0.0.1', 8080)
)
server.start()
print(server.local_bind_port) # show assigned local port
# work with `SECRET SERVICE` through `server.local_bind_port`.
server.stop()
Beispiel für eine Portweiterleitung zu einem privaten Server, der nicht direkt erreichbar ist, unter der Annahme einer passwortgeschützten pkey-Authentifizierung, dass der SSH-Dienst des entfernten Servers auf Port 443 lauscht und dieser Port in der Firewall geöffnet ist (Abb2):
.. code-block:: python
import paramiko
import sshtunnel
with sshtunnel.open_tunnel(
(REMOTE_SERVER_IP, 443),
ssh_username="",
ssh_pkey="/var/ssh/rsa_key",
ssh_private_key_password="secret",
remote_bind_address=(PRIVATE_SERVER_IP, 22),
local_bind_address=('0.0.0.0', 10022)
) as tunnel:
client = paramiko.SSHClient()
client.load_system_host_keys()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
client.connect('127.0.0.1', 10022)
# do some operations with client session
client.close()
print('FINISH!')
Beispiel für eine Portweiterleitung für den lokalen MySQL-Port von Vagrant:
.. code-block:: python
from sshtunnel import open_tunnel
from time import sleep
with open_tunnel(
('localhost', 2222),
ssh_username="vagrant",
ssh_password="vagrant",
remote_bind_address=('127.0.0.1', 3306)
) as server:
print(server.local_bind_port)
while True:
# press Ctrl-C for stopping
sleep(1)
print('FINISH!')
Oder einfach über die CLI:
.. code-block:: console
(bash)$ python -m sshtunnel -U vagrant -P vagrant -L :3306 -R 127.0.0.1:3306 -p 2222 localhost
Öffnen einer SSH-Sitzung, die über zwei Tunnel springt. Der SSH-Transport und die Tunnel werden als Daemon ausgeführt, wodurch beim Schließen nicht auf das Beenden der Verbindungen gewartet wird.
.. code-block:: python
import sshtunnel
from paramiko import SSHClient
with sshtunnel.open_tunnel(
ssh_address_or_host=('GW1_ip', 20022),
remote_bind_address=('GW2_ip', 22),
) as tunnel1:
print('Connection to tunnel1 (GW1_ip:GW1_port) OK...')
with sshtunnel.open_tunnel(
ssh_address_or_host=('localhost', tunnel1.local_bind_port),
remote_bind_address=('target_ip', 22),
ssh_username='GW2_user',
ssh_password='GW2_pwd',
) as tunnel2:
print('Connection to tunnel2 (GW2_ip:GW2_port) OK...')
with SSHClient() as ssh:
ssh.connect('localhost',
port=tunnel2.local_bind_port,
username='target_user',
password='target_pwd',
)
ssh.exec_command(...)
::
$ sshtunnel --help
usage: sshtunnel [-h] [-U SSH_USERNAME] [-p SSH_PORT] [-P SSH_PASSWORD] -R
IP:PORT [IP:PORT ...] [-L [IP:PORT ...]] [-k SSH_HOST_KEY]
[-K KEY_FILE] [-S KEY_PASSWORD] [-t] [-v] [-V] [-x IP:PORT]
[-c SSH_CONFIG_FILE] [-z] [-n] [-d [FOLDER ...]]
ssh_address
Pure python ssh tunnel utils
Version 0.5.1
positional arguments:
ssh_address SSH server IP address (GW for SSH tunnels)
set with "-- ssh_address" if immediately after -R or -L