pythonsshparamikoopensshssh-tunnel

Failing to establish an SSH tunnel in Python (without Putty)


I'm attempting to automate the process of connecting to a Redshift server using Python without relying on PuTTY. Currently, I'm on a Windows machine, and I need to extract data from PostgreSQL on a Redshift server. However, to achieve this, I have to:

  1. Open the PuTTY .exe

  2. Enter this command in PuTTY: "Putty -P <port_number> -noagent -N -L 5534:<redshift_host>:5534 <username>@<remote_host> -i <private_key_file> -pw <password>"

  3. Wait a few seconds until PuTTY shows the tunnel is open

  4. Open my Jupyter Python Notebook and finally execute my query:

    cxn= psycopg2.connect(user="sql_username", password="sql_password", host="host_ip", port=5534, database="database_name")

Extract the data and store it as a dataframe. Since this is quite a manual and not so efficient process, I have been searching the web to stop using PuTTY altogether and find a new way to create the tunnel and extract my data. I have even converted my .ppk key to a .pem format to use with other libraries. I'm using paramiko and SSHTunnelForwarder, but I have not been successful in actually connecting correctly to my tunnel. Here is my code:

from sshtunnel import SSHTunnelForwarder


ssh_host = <remote_host>
ssh_port = <port_number>
ssh_user = <username>
ssh_key_path = 'ssh_key_redshift.pem'  
ssh_password = <password>

redshift_host = <redshift_host>
redshift_port = 5534
redshift_user = <username>


# Create an SSH tunnel
with SSHTunnelForwarder(
    (ssh_host, ssh_port),
    ssh_username=ssh_user,
    ssh_pkey=ssh_key_path,
    ssh_password=ssh_password,
    remote_bind_address=(redshift_host, redshift_port),
    local_bind_address=('localhost', 5534)
) as tunnel:
    print("SSH Tunnel established successfully.")
    input("Press Enter to close the tunnel...") 

But unfortunately is not working to open and connect the tunnel and when I use shhtunnel.

I have heard of the paramiko library, and I would be thrilled if anyone could assist me with this. Essentially, what I need to do is establish an SSH tunnel using <port_number>, binding the local port 5534 to a Redshift host's port 5534, using the credentials and the key file that I have converted to .pem.


Solution

  • I don't know redshift, but adapted to what I do for postgres or mariadb :

    from sshtunnel import SSHTunnelForwarder
    import redshift_connector
    
    
    ssh_host = <remote_host>
    ssh_port = <port_number>
    ssh_user = <username>
    ssh_key_path = 'ssh_key_redshift.pem'  
    ssh_password = <password>
    
    redshift_host = <redshift_host> # localhost
    redshift_port = 5534 # ! default redshift port is 5539 !
    redshift_user = <username>
    
    
    # Create an SSH tunnel
    with SSHTunnelForwarder (
        ssh_address_or_host=ssh_host,
        ssh_port=ssh_port,
        ssh_username=ssh_user,
        ssh_pkey=ssh_key_path,
        ssh_private_key_password=ssh_password,
        remote_bind_address=(redshift_host, redshift_port)
    ) as tunnel:
        print("SSH Tunnel established successfully.")
    
    
        with redshift_connector.connect(
            host=redshift_host,
            port=tunnel.local_bind_port,
            user=redshift_user,
            # database=?
         ) as conn:
            
            # do your stuff