问题
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?
回答1:
You could try paramiko's forward functionality. For a paramiko overview, see here.
回答2:
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'])
回答3:
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)
回答4:
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.
来源:https://stackoverflow.com/questions/4364355/how-to-open-an-ssh-tunnel-using-python