pythonsslsshrpyc

RPyC connection through proxy


Context

I have a private server, reachable by using a public server as a proxy

|------|       |------|       |-------|
|Remote|  ->   |Public|  ->   |Private|
|------|       |------|       |-------|

I can connect to the private server (ssh keys are correctly set up) with

user@remote:$ ssh user@public
user@public:$ ssh user@private
user@private:$

Or in one line:

user@remote:$ ssh -o ProxyCommand='ssh -W %h:%p user@public' user@private

Problem:

Now, I wish to be able to send RPyC requests from the remote machine directly to the private server.

As an insight for why I need it: the remote machine has a camera while the private server has gpus (and there is a good connection between the two)

What I've tried so far

I managed to run a SSL connection as in RPyC SSH connection

conn = rpyc.ssl_connect("private", port = 12345, keyfile="/path/to/my.key", certfile="/path/to/my.cert")

with key and certificate obtained with something like Create a self signed X509 certificate in Python.

Now, it works IF the client has been launched from the public server. I don't know how to redirect the SSL connection from the remote machine.

Something else that I have tried is to declare a plumbum SshMachine as the Zero-Deploy tutorial indicate (https://rpyc.readthedocs.io/en/latest/docs/zerodeploy.html)

mach = SshMachine("user@private", ssh_opts=["-o ProxyCommand='ssh -W %h:%p user@public'"]

I can launch a Zero-Deploy server using this, but this is not satisfying because it uses a fresh (temporary) copy of python and I need to use the installed libraries from private server (e.g. cuda setup).

Of course, I cannot combine the two approaches since ssl_connect requires a string as hostname and raises an exception if given a SshMachine.

Constraints

I don't have root access neither to private nor public servers, but any library that can be installed with pip is ok. I have tried looking e.g. at paramiko but I am not sure where to start...

Update

I found a solution (see answer https://stackoverflow.com/a/68535406/6068769), but I still have a few questions so I don't accept it yet:

plumbum.machine.session.SSHCommsError: SSH communication failed
Return code:   | 255
Command line:  | 'true '
stderr:        | /bin/bash: line 0 : exec: ssh -W private:22 user@public : not found

I can live with opening the connection beforehand but it would be cleaner if I don't have to.


Solution

  • Ok, I was not far, I just missed the method rpyc.ssh_connect.

    Here is the MWE:

    ## Server
    import rpyc
    
    class MyService(rpyc.Service):
        def on_connect(self, conn):
            pass
    
        def on_disconnect(self, conn):
            pass
    
        def exposed_some_computations(self, input):
            return 2*input
    
    if __name__ == "__main__":
            from rpyc.utils.server import ThreadedServer
            server = ThreadedServer(MyService, port=12345)
            server.start()
    
    ## Client
    from plumbum import SshMachine
    import rpyc
    
    mach = SshMachine("user@private", ssh_opts=["-o ProxyCommand='ssh -W %h:%p user@public'"])
    
    conn = rpyc.ssh_connect(mach, 12345)
    result = conn.root.exposed_some_computations(18)