cranberry
cranberry

Reputation: 221

fabric: how to double tunnel

Situation: A and B are remote hosts. Local machine can SSH into A, but not B. B ONLY accepts SSH connections from A.

Question: Is it possible to use fabric on the local machine to execute commands on Host B, preferably without having to install fabric on A?

Upvotes: 19

Views: 7825

Answers (7)

Pascal Sotin
Pascal Sotin

Reputation: 1

In Fabric 2+, the API has been reorganized and the module fabric.api no longer exists, thus deprecating several answers on this page.

Addressing the question of "double tunnel" is still possible in this modern API, and still uses the concept of gateway, but relies on the Connection objects.

from fabric import Connection

c1 = Connection('remote_machineA', user='user')
c2 = Connection('remote_machineB', user='user', gateway=c1)
c2.run('hostname')

Note that this answer is only valid if we interpret the statement B ONLY accepts SSH connections from A as Due to network restrictions, [...].

Both hosts A and B should have your local SSH public key as authorized key (so, in some sense, B does accept SSH connections from the local machine). The public keys stored on A are not used to log on B.

Upvotes: 0

gasman
gasman

Reputation: 25227

As a variation on yeforriak's answer, if you only want to do this for an individual task, you can do:

from fabric.api import *

@with_settings(forward_agent=True, gateway='user@remote_MachineA')
@hosts(['user@remote_MachineB'])
def function1():
  run('hostname')

Upvotes: 1

yeforriak
yeforriak

Reputation: 1715

I managed to achieve this with env.gateway as follows:

from fabric.api import *

env.forward_agent = True
env.gateway = 'user@remote_MachineA'
env.hosts = ['user@remote_MachineB']

def function1():
  run('hostname')

env.forward_agent = True is there only to enable forwarding of your local SSH agent to the remote end

Alternatively, you can use ssh ProxyCommand, example here and tell fabric to use your ~/.ssh/config using use_ssh_config = True, documentation here

Upvotes: 13

Fernando Martin
Fernando Martin

Reputation: 689

Since Fabric v1.5+ there is a method called remote_tunnel to solve cranberry situation

I have used a simple command (hostname) to illustrate the solution but any other command may be used instead. As you can see, we have invoked a command to be executed on remote_machineB from local_machine by using remote_machineA as jump host:

from fabric.api import settings, env, run, remote_tunnel

env.hosts=["user@remote_machineA"]

def funct1():
    def func1b(host):
        with settings(host_string=host):
            run("hostname")

    with remote_tunnel(remote_port=22022, local_port=22,
                       local_host="remote_machineB", remote_bind_address="0.0.0.0"):
        funct1b("user@remote_machineA:22022")

If you execute this fab file in local_machine this is what we get:

[user@local_machine ~]# fab hostname_check
[user@remote_machineA] Executing task 'hostname_check'
[user@remote_machineA:22022] run: hostname
[user@remote_machineA:22022] rtunnel: opened reverse tunnel: (u'X.X.3.75', 55804) -> ('X.X.3.78', 22) -> ('remote_machineB', 22)
[user@remote_machineA:22022] out: remote_machineB
[user@remote_machineA:22022] out:

Terminated

To do so it is very important to configure this jump machine ssh daemon with GatewayPorts yes. Otherwise remote tunnel would be accessible only from localhost.

Check:

tcp        0      0 127.0.0.1:22022         0.0.0.0:*               LISTEN     

versus:

tcp        0      0 0.0.0.0:22022           0.0.0.0:*               LISTEN     

For more info check official documentation http://docs.fabfile.org/en/latest/api/core/context_managers.html#fabric.context_managers.remote_tunnel

Upvotes: 3

Hassek
Hassek

Reputation: 8995

I'll just leave this here: http://www.popcornfarmer.com/2009/01/ssh-tunneling-tutorial/

Upvotes: 2

jsw
jsw

Reputation: 2203

Looks like this might to the trick:

https://gist.github.com/856179

Upvotes: 4

LHMathies
LHMathies

Reputation: 2434

I'm just going to answer the SSH part: Yes, you can set up a double tunnel -- one SSH from local to A that tunnels from a secondary local port (like 2121) to port 21 on B, and then you can SSH to localhost:2121 and login on B. I've done stuff like that with PuTTY.

Implementing that in fabric is left as an exercise.

Upvotes: 0

Related Questions