Search code examples
pythonunixparamikossh-tunnel

sshtunnel keyboard-interactive


I'd like to use sshtunnel without authentication for a password or private key for the 2nd Example (Fig.2) given in the docs.

from the docs (slightly modified for the private-server part):

----------------------------------------------------------------------

                            |
-------------+              |    +----------+               +---------
    LOCAL    |              |    |  REMOTE  |               | PRIVATE
    CLIENT   | <== SSH ========> |  SERVER  | <== SSH ==>   | SERVER
-------------+              |    +----------+               +---------
                            |
                         FIREWALL

----------------------------------------------------------------------

The allowed authentication method is "keyboard-interactive" (multi-step authentication) as described in Erick's post

So what I do already have from above is a paramiko transport- and a paramiko channel object. My question:
how to plug these both objects into the sshtunnel Forwarder class to achieve something like this in unix shell (local port forwarding):
ssh -L localhost:port-local-client:PRIVATE_SERVER:port-private-server user@REMOTE_SERVER

Here's some example-code from Erick's post: What I want to achieve is to use the transport for further cmds, see below ...

import forward # the forward.py script, referenced by Kirk

#Create a socket and connect it to PORT on the REMOTE_SERVER
sock = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
sock.connect(("REMOTE_SERVER", PORT))

#Make a Paramiko Transport object using the socket
transport = paramiko.Transport(sock)

#Tell Paramiko that the Transport is going to be used as a client
transport.start_client(timeout=10)

#Begin authentication with "my_handler" being a callable which returns the server prompt-list
transport.auth_interactive(USERNAME, my_handler)

# this doesn't come back, since class "ForwardServer" ... serve_forever() ...
forward.forward_tunnel(PORT, "PRIVATE_SERVER", PORT, transport)

# However, what I'd like to accomplish is to "surf" the transport /channel and
# operate cmds on it as such:

#Opening a session creates a channel along the socket to the server
channel = transport.open_session(timeout=10)

#Now the channel can be used to execute commands
stdout = channel.exec_command("touch Hello_Private_Server!")

Solution

  • Basically I was after these 2 lines ...

    # span the local port forwarding (ssh -L)
    REMOTE_SERVER_Channel = transport.open_channel("direct-tcpip", (PRIVATE_SERVER, PORT), (LOCAL_CLIENT, PORT))
    
    # create a new paramiko-client (with corresponding policy)
    ...
    # and crack it open with the distant channel
    tunnelClient.connect(PRIVATE_SERVER, username=ssh-USERNAME, password=ssh-PASSWORD, sock=REMOTE_SERVER_Channel)
    

    So, what do you think, is this attempt too 'wordy' or am I using the paramiko classes (Channel, Client, Transport) efficiently?