33

I need to create tunneling to read information from a database. I use Paramiko, but I have not worked with tunneling yet. Please provide an example of a simple code that creates and closes a tunnel.

ZygD
  • 22,092
  • 39
  • 79
  • 102
Ivan
  • 333
  • 1
  • 3
  • 4

5 Answers5

16

At work we usually create ssh tunnels forwarding ports. The way we do that is, by using the standard command ssh -L port:addr:port addr with subprocess running in a separate thread. I found this useful link: https://github.com/paramiko/paramiko/blob/master/demos/forward.py with an example of doing port forwarding with paramiko.

Nikhil Wagh
  • 1,376
  • 1
  • 24
  • 44
dario
  • 300
  • 1
  • 2
  • thanks for the link but I can not run this code. He asks arguments. but the arguments that I enter not working. Give an example please line launch. – Ivan Nov 18 '11 at 05:34
  • 5
    Example: this command: "ssh -L 5555:machine2:55 machine1" will connect to machine1:22 and it will forward any connection from your computer:5555 through machine1:22 to machine2:55. Suppose you want to forward your own ssh service to another port, the command to do that is: "ssh -L 5555:localhost:22 localhost". So if you do "ssh localhost -p 5555" it will connect you to your own localhost:22.To do that using the paramiko "forward.py" demo, you have to run it this way: "python forward.py localhost -p 5555 -r localhost:22". Execute it and in another terminal run ssh localhost -p 5555 – dario Nov 18 '11 at 12:21
  • @dario For creating multiple forwards with -L1, -L2, -Ln? – realnot Apr 16 '19 at 17:57
15

I used sshtunnel for my projects. Example of the forwarding remote local MySQL port to the host local port:

pip install sshtunnel
python -m sshtunnel -U root -P password -L :3306 -R 127.0.0.1:3306 -p 2222 localhost
pahaz
  • 837
  • 9
  • 13
12

Even though this does not use paramiko, I believe it's a very clean solution to implement (similar to @dario's answer but without managing the thread in python).

There's this little-mentioned feature in openssh client that allows us to control a ssh process through a unix socket, quoting 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.

So you can start background process of ssh (with -Nf) and then check (or terminate) it with a another ssh call.

I use this in a project that requires a reverse tunnel to be established

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 makes sure the ssh command will fail if the tunnel cannot be established, otherwise it will not exit.

Community
  • 1
  • 1
Filipe Pina
  • 2,201
  • 23
  • 35
  • I'm intrigued with this solution. Once I'm connected, how may I send commands to the server?, e.g.: "ifconfig" and get the output back in my client?. Thanks. – subzero May 23 '20 at 03:39
  • Using this exactly, you cannot @subzero. This was meant to answer OP question which was controlling an ssh tunnel – Filipe Pina Jun 01 '22 at 18:33
0

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, 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")
alexdlaird
  • 1,174
  • 12
  • 34
-5

I used paramiko for some project I had a year ago, here is the part of my code where I connected with another computer/server and executed a simple python file:

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()

stdin, stdout and sdterr contain the inputs/outputs of the command you executed.

From here, I think you can make the connection with the database.

Here is some good information about paramiko.

juliomalegria
  • 24,229
  • 14
  • 73
  • 89