Reputation: 221
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
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
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
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
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
Reputation: 8995
I'll just leave this here: http://www.popcornfarmer.com/2009/01/ssh-tunneling-tutorial/
Upvotes: 2
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