GNU parallel - running with proxy host - parallel-processing

I've been recently dealing with GNU parallel and parallel computation. I have two machines available, one where I work and one behind a proxy machine, so I work at A, I can access C only via B and I can not compute on B.
My question is, how do I create the hosts file for GNU parallel to understand I want to share files with machine C? I have enabled password-less logins to both B and C from B.
Thank you!

From: https://www.gnu.org/software/parallel/man.html#EXAMPLE:-Using-remote-computers-behind-NAT-wall
EXAMPLE: Using remote computers behind NAT wall
If the workers are behind a NAT wall, you need some trickery to get to them.
If you can ssh to a jump host, and reach the workers from there, then the obvious solution would be this, but it does not work:
parallel --ssh 'ssh jumphost ssh' -S host1 echo ::: DOES NOT WORK
It does not work because the command is dequoted by ssh twice where as GNU parallel only expects it to be dequoted once.
So instead put this in ~/.ssh/config:
Host host1 host2 host3
ProxyCommand ssh jumphost.domain nc -w 1 %h 22
It requires nc(netcat) to be installed on jumphost. With this you can simply:
parallel -S host1,host2,host3 echo ::: This does work
No jumphost, but port forwards
If there is no jumphost but each server has port 22 forwarded from the firewall (e.g. the firewall's port 22001 = port 22 on host1, 22002 = host2, 22003 = host3) then you can use ~/.ssh/config:
Host host1.v
Port 22001
Host host2.v
Port 22002
Host host3.v
Port 22003
Host *.v
Hostname firewall
And then use host{1..3}.v as normal hosts:
parallel -S host1.v,host2.v,host3.v echo ::: a b c
No jumphost, no port forwards
If ports cannot be forwarded, you need some sort of VPN to traverse the NAT-wall. TOR is one options for that, as it is very easy to get working.
You need to install TOR and setup a hidden service. In torrc put:
HiddenServiceDir /var/lib/tor/hidden_service/
HiddenServicePort 22 127.0.0.1:22
Then start TOR: /etc/init.d/tor restart
The TOR hostname is now in /var/lib/tor/hidden_service/hostname and is something similar to izjafdceobowklhz.onion. Now you simply prepend torsocks to ssh:
parallel --ssh 'torsocks ssh' -S izjafdceobowklhz.onion \
-S zfcdaeiojoklbwhz.onion,auclucjzobowklhi.onion echo ::: a b c
If not all hosts are accessible through TOR:
parallel -S 'torsocks ssh izjafdceobowklhz.onion,host2,host3' echo ::: a b c

Related

Detect that a host is reachable via a jump host

I have setup a tunnel through a jump host as such :
ssh -o ProxyCommand='ssh -W %h:%p bastion' -i my-emr.pem -ND 8888 hadoop#ip-my.ec2.internal
bastion is a host I have defined in my ~/.ssh/config
This way I can access ip-my.ec2.internal etc. via a SOCKS5 proxy. I want to test whether this host is accessible via SOCKS5 proxy. Is there a command I can use? I can test if the bastion host is accessible using a command like this :
nc -G 2 -z my-bastion.com 22
Anyway I can extend the above command to test if the end host which is ip-my.ec2.internal?
It looks like all your testing in the nc command is whether port 22 will allow a connection within 2 seconds. That's not the same thing whether you can can make an SSH connection to my-bastion. It doesn't even prove that you can connect to my-bastion at all. It is not uncommon for firewalls to accept connections that they will not pass any data for.
If you want the same level of weak testing you'd do the same thing along the lines of:
ssh bastion nc -G 2 -z ip-my.ec2.internal 8888
There are lots of ways for this to incorrectly return that it is reachable when it isn't, just as there are lots of ways for your other nc command can fail. But it might give you some useful information for managing a UI.
The only way to know that network connection is possible is to attempt the actual network connection you want. As a rule, you should not pre-flight network connections. Just attempt them, and deal with connection errors (which can happen even if your pre-flights pass). If the goal is to avoid long waits, then shorten your timeouts (which will lead to more false-negatives when the network is slow).

Complex SSH tunnel

I have a complex SSH tunnel problem I'm trying to solve and can't seem to get it quite right.
Simply put:
ME -> Bastion:22 -> Instance:8500
Bastion uses a different username and key than instance. I would like to be able to access port 1234 on instance from localhost:1234
Right now I have the following:
Host bastion
HostName bastion.example.com
ForwardAgent yes
IdentityFile ~/.ssh/id_ecdsa
User spanky
Host internal
ForwardAgent yes
HostName consul.internal
IdentityFile ~/.ssh/aws.pem
ProxyJump bastion
User ec2-user
Port 8500
But I don't think I've got it.
The following two commands work, but I'm trying to distill them into a working config:
ssh -L 2222:10.0.0.42:22 bastion.example.com -N -i ~/.ssh/id_ecdsa
ssh -L 8500:localhost:8500 ec2-user#localhost -N -i ~/.ssh/aws.pem -p 2222
With a current version of ssh, you should be able to use:
ssh -L1234:localhost:1234 -J spanky#bastion.example.com ec2-user#consul.internal
From man ssh:
-J destination
Connect to the target host by first making a ssh
connection to the jump host described by destination and then
establishing a TCP forwarding to the ultimate destination from there.
Multiple jump hops may be specified separated by comma characters.
This is a shortcut to specify a ProxyJump configuration directive.

Secure copy over two IPs on the same network to the local machine [duplicate]

I wonder if there is a way for me to SCP the file from remote2 host directly from my local machine by going through a remote1 host.
The networks only allow connections to remote2 host from remote1 host. Also, neither remote1 host nor remote2 host can scp to my local machine.
Is there something like:
scp user1#remote1:user2#remote2:file .
First window: ssh remote1, then scp remot2:file ..
Second shell: scp remote1:file .
First window: rm file; logout
I could write a script to do all these steps, but if there is a direct way, I would rather use it.
Thanks.
EDIT: I am thinking something like opening SSH tunnels but i'm confused on what value to put where.
At the moment, to access remote1, i have the following in $HOME/.ssh/config on my local machine.
Host remote1
User user1
Hostname localhost
Port 45678
Once on remote1, to access remote2, it's the standard local DNS and port 22. What should I put on remote1 and/or change on localhost?
I don't know of any way to copy the file directly in one single command, but if you can concede to running an SSH instance in the background to just keep a port forwarding tunnel open, then you could copy the file in one command.
Like this:
# First, open the tunnel
ssh -L 1234:remote2:22 -p 45678 user1#remote1
# Then, use the tunnel to copy the file directly from remote2
scp -P 1234 user2#localhost:file .
Note that you connect as user2#localhost in the actual scp command, because it is on port 1234 on localhost that the first ssh instance is listening to forward connections to remote2. Note also that you don't need to run the first command for every subsequent file copy; you can simply leave it running.
Double ssh
Even in your complex case, you can handle file transfer using a single command line, simply with ssh ;-)
And this is useful if remote1 cannot connect to localhost:
ssh user1#remote1 'ssh user2#remote2 "cat file"' > file
tar
But you loose file properties (ownership, permissions...).
However, tar is your friend to keep these file properties:
ssh user1#remote1 'ssh user2#remote2 "cd path2; tar c file"' | tar x
You can also compress to reduce network bandwidth:
ssh user1#remote1 'ssh user2#remote2 "cd path2; tar cj file"' | tar xj
And tar also allows you transferring a recursive directory through basic ssh:
ssh user1#remote1 'ssh user2#remote2 "cd path2; tar cj ."' | tar xj
ionice
If the file is huge and you do not want to disturb other important network applications, you may miss network throughput limitation provided by scp and rsync tools (e.g. scp -l 1024 user#remote:file does not use more than 1 Mbits/second).
But, a workaround is using ionice to keep a single command line:
ionice -c2 -n7 ssh u1#remote1 'ionice -c2 -n7 ssh u2#remote2 "cat file"' > file
Note: ionice may not be available on old distributions.
This will do the trick:
scp -o 'Host remote2' -o 'ProxyCommand ssh user#remote1 nc %h %p' \
user#remote2:path/to/file .
To SCP the file from the host remote2 directly, add the two options (Host and ProxyCommand) to your ~/.ssh/config file (see also this answer on superuser). Then you can run:
scp user#remote2:path/to/file .
from your local machine without having to think about remote1.
With openssh version 7.3 and up it is easy. Use ProxyJump option in the config file.
# Add to ~/.ssh/config
Host bastion
Hostname bastion.client.com
User userForBastion
IdentityFile ~/.ssh/bastion.pem
Host appMachine
Hostname appMachine.internal.com
User bastion
ProxyJump bastion # openssh 7.3 version new feature ProxyJump
IdentityFile ~/.ssh/appMachine.pem. #no need to copy pem file to bastion host
Commands to run to login or copy
ssh appMachine # no need to specify any tunnel.
scp helloWorld.txt appMachine:. # copy without intermediate jumphost/bastion host copy.**
ofcourse you can specify bastion Jump host using option "-J" to ssh command, if not configured in config file.
Note scp does not seems to support "-J" flag as of now. (i could not find in man pages. However above scp works with config file setting)
There is a new option in scp that add recently for exactly this same job that is very convenient, it is -3.
TL;DR For the current host that has authentication already set up in ssh config files, just do:
scp -3 remote1:file remote2:file
Your scp must be from recent versions.
All other mentioned technique requires you to set up authentication from remote1 to remote2 or vice versa, which not always is a good idea.
Argument -3 means you want to move files from two remote hosts by using current host as intermediary, and this host actually does the authentication to both remote hosts, so they don't have to have access to each other.
You just have to setup authentication in ssh config files, which is fairly easy and well documented, and then just run the command in TL;DR
The source for this answer is https://superuser.com/a/686527/713762
This configuration works nice for me:
Host jump
User username
Hostname jumphost.yourorg.intranet
Host production
User username
Hostname production.yourorg.intranet
ProxyCommand ssh -q -W %h:%p jump
Then the command
scp myfile production:~
Copies myfile to production machine.
a simpler way:
scp -o 'ProxyJump your.jump.host' /local/dir/myfile.txt remote.internal.host:/remote/dir

How to connect to a server using another server by ssh in shell script?

The scenario is like:
SERVER_A="servera.com"
SERVER_A_UNAME="usera"
SERVER_B="serverb.com"
SERVER_B_UNAME="userb"
I want to write a shell script which will fist connect to server A, and then only it would be connected to server B. Like:
#!/bin/sh
ssh $SERVER_A_UNAME#$SERVER_A ...and then
ssh $SERVER_B_UNAME#$SERVER_B
But I am not able to do it. It does connect to server A only. How can I achieve it?
You may be able to find some help with this previous question:
How to use bash/expect to check if an SSH login works
Depending on your situation you might also to execute an remote ssh command and wait for positive feedback.
See:
How to use SSH to run a shell script on a remote machine?
you should have a look at ssh ProxyCommands that lets you do indirect connects automatically. basically you put the following in you .ssh/config
Host gateway1
# nichts
Host gateway2
ProxyCommand ssh -q gateway1 nc -q0 gateway2 22
Host targethost
ProxyCommand ssh -q gateway2 nc -q0 targethost 22
and then you can run ssh targethost successfully even if targethost is not reachable directly. you can read more about this e.g. here http://sshmenu.sourceforge.net/articles/transparent-mulithop.html

Is it possible to forward ssh requests that come in over a certain port to another machine?

I have a small local network. Only one of the machines is available to the outside world (this is not easily changeable). I'd like to be able to set it up such that ssh requests that don't come in on the standard port go to another machine. Is this possible? If so, how?
Oh and all of these machines are running either Ubuntu or OS X.
Another way to go would be to use ssh tunneling (which happens on the client side).
You'd do an ssh command like this:
ssh -L 8022:myinsideserver:22 paul#myoutsideserver
That connects you to the machine that's accessible from the outside (myoutsideserver) and creates a tunnel through that ssh connection to port 22 (the standard ssh port) on the server that's only accessible from the inside.
Then you'd do another ssh command like this (leaving the first one still connected):
ssh -p 8022 paul#localhost
That connection to port 8022 on your localhost will then get tunneled through the first ssh connection taking you over myinsideserver.
There may be something you have to do on myoutsideserver to allow forwarding of the ssh port. I'm double-checking that now.
Edit
Hmmm. The ssh manpage says this: **Only the superuser can forward privileged ports. **
That sort of implies to me that the first ssh connection has to be as root. Maybe somebody else can clarify that.
It looks like superuser privileges aren't required as long as the forwarded port (in this case, 8022) isn't a privileged port (like 22). Thanks for the clarification Mike Stone.
#Mark Biek
I was going to say that, but you beat me to it! Anyways, I just wanted to add that there is also the -R option:
ssh -R 8022:myinsideserver:22 paul#myoutsideserver
The difference is what machine you are connecting to/from. My boss showed me this trick not too long ago, and it is definitely really nice to know... we were behind a firewall and needed to give external access to a machine... he got around it by ssh -R to another machine that was accessible... then connections to that machine were forwarded into the machine behind the firewall, so you need to use -R or -L based on which machine you are on and which you are ssh-ing to.
Also, I'm pretty sure you are fine to use a regular user as long as the port you are forwarding (in this case the 8022 port) is not below the restricted range (which I think is 1024, but I could be mistaken), because those are the "reserved" ports. It doesn't matter that you are forwarding it to a "restricted" port because that port is not being opened (the machine is just having traffic sent to it through the tunnel, it has no knowledge of the tunnel), the 8022 port IS being open and so is restricted as such.
EDIT: Just remember, the tunnel is only open so long as the initial ssh remains open, so if it times out or you exit it, the tunnel will be closed.
(In this example, I am assuming port 2222 will go to your internal host. $externalip and $internalip are the ip addresses or hostnames of the visible and internal machine, respectively.)
You have a couple of options, depending on how permanent you want the proxying to be:
Some sort of TCP proxy. On Linux, the basic idea is that before the incoming packet is processed, you want to change its destination—i.e. prerouting destination NAT:
iptables -t nat -A PREROUTING -p tcp -i eth0 -d $externalip --dport 2222 --sport
1024:65535 -j DNAT --to $internalip:22
Using SSH to establish temporary port forwarding. From here, you have two options again:
Transparent proxy, where the client thinks that your visible host (on port 2222) is just a normal SSH server and doesn't realize that it is passing through. While you lose some fine-grained control, you get convenience (especially if you want to use SSH to forward VNC or X11 all the way to the inner host).
From the internal machine: ssh -g -R 2222:localhost:22 $externalip
Then from the outside world: ssh -p 2222 $externalip
Notice that the "internal" and "external" machines do not have to be on the same LAN. You can port forward all the way around the world this way.
Forcing login to the external machine first. This is true "forwarding," not "proxying"; but the basic idea is this: You force people to log in to the external machine (so you control on who can log in and when, and you get logs of the activity), and from there they can SSH through to the inside. It sounds like a chore, but if you set up simple shell scripts on the external machine with the names of your internal hosts, coupled with password-less SSH keypairs then it is very straightforward for a user to log in. So:
On the external machine, you make a simple script, /usr/local/bin/internalhost which simply runs ssh $internalip
From the outside world, users do: ssh $externalip internalhost and once they log in to the first machine, they are immediately forwarded through to the internal one.
Another advantage to this approach is that people don't get key management problems, since running two SSH services on one IP address will make the SSH client angry.
FYI, if you want to SSH to a server and you do not want to worry about keys, do this
ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no
I have an alias in my shell called "nossh", so I can just do nossh somehost and it will ignore all key errors. Just understand that you are ignoring security information when you do this, so there is a theoretical risk.
Much of this information is from a talk I gave at Barcamp Bangkok all about fancy SSH tricks. You can see my slides, but I recommend the text version as the S5 slides are kind of buggy. Check out the section called "Forward Anything: Simple Port Forwarding" for info. There is also information on creating a SOCKS5 proxy with OpenSSH. Yes, you can do that. OpenSSH is awesome like that.
(Finally, if you are doing a lot of traversing into the internal network, consider setting up a VPN. It sounds scary, but OpenVPN is quite simple and runs on all OSes. I would say it's overkill just for SSH; but once you start port-forwarding through your port-forwards to get VNC, HTTP, or other stuff happening; or if you have lots of internal hosts to worry about, it can be simpler and more maintainable.)
You can use Port Fowarding to do this. Take a look here:
http://portforward.com/help/portforwarding.htm
There are instructions on how to set up your router to port forward request on this page:
http://www.portforward.com/english/routers/port_forwarding/routerindex.htm
In Ubuntu, you can install Firestarter and then use it's Forward Service feature to forward the SSH traffic from a non standard port on your machine with external access to port 22 on the machine inside your network.
On OS X you can edit the /etc/nat/natd.plist file to enable port fowarding.
Without messing around with firewall rules, you can set up a ~/.ssh/config file.
Assume 10.1.1.1 is the 'gateway' system and 10.1.1.2 is the 'client' system.
Host gateway
Hostname 10.1.1.1
LocalForward 8022 10.1.1.2:22
Host client
Hostname localhost
Port 8022
You can open an ssh connection to 'gateway' via:
ssh gateway
In another terminal, open a connection to the client.
ssh client

Resources