The quick, bad and dirty way to automate SSH jump connections.
As you probably know on many setups the hosts are not directly accessible but there is an SSH gateway on the between (also known as bastion server) which has security enhancements and is configured to allow / disallow access based on IP filtering.
The manual way
to connect to a host over an SSH gateway is to use the -J parameter that defines the gateway
$ ssh -J user@ssh-gateway-server user@server1
But this is unproductive because you will need to write a lot of things each time you want to connect to a host, like usernames, the gateway ip addresses etc.
The good and correct way
to do this is to create entries on the ssh_config file like this!
### The SSH Gateway host
Host ssh-gw1
HostName ssh-gw1
User username### Host accessible over SSH Gateway
Host server1
HostName server1
ProxyJump ssh-gw1
User username
But this way has a managerial problem, needs initial configuration and needs maintenance to stay up to date, this is ok on a small scale environment or for an an organization that has a dedicated team to maintain this, but it can backfire and have access problems which can led to more serious problems hard to track in case of emergency.
The quick and dirty way
You can avoid any configuration and use some “shell script magic”, the only configuration you need to apply is the list of the SSH gateway servers and the script will check if the server that you want to connect is accessible with one of the SSH gateways, if it is it will establish the connection, you can also pass any parameters that you normally would pass to an SSH command.
Parameters:
- host_username: the username that will used to connect to the remote server
- gw_username: the username that will used to connect to the SSH gateway
- use_ssh_pass: if “true” will read the ssh password from file in ~/pass (very bad practice)
- gw: this list is the SSH gateway list of server
#!/bin/bashif [ "$1" = "" ]; then
exit
fi# Username, addapt this to match your needs
declare -a host_username="username"# Gateway username
declare -a gw_username="username"# Enable or Disable sshpass
declare -a use_ssh_pass="true"# SSH Gateways
declare -a gw=("gw1" "gw2" "gw3" "gw4")for gateway in "${gw[@]}"
do
if [ "$use_ssh_pass" == "true" ]; then
SSH_RESULT=$(sshpass -f ~/pass ssh -J $gw_username"@"$gateway $host_username"@"$1 'echo OK' 2>&1)
SSH_CAN_CONNECT=$(echo $SSH_RESULT | tr -s " " | rev | cut -d " " -f1 | rev)if [ "$SSH_CAN_CONNECT" == "OK" ]; then
sshpass -f ~/pass ssh -J $gw_username"@"$gateway $host_username"@"$1 ${@:2}
exit
fi
else
SSH_RESULT=$(ssh -J $gw_username"@"$gateway $host_username"@"$1 'echo OK' 2>&1)
SSH_CAN_CONNECT=$(echo $SSH_RESULT | tr -s " " | rev | cut -d " " -f1 | rev)if [ "$SSH_CAN_CONNECT" == "OK" ]; then
ssh -J $gw_username"@"$gateway $host_username"@"$1 ${@:2}
exit
fi
fidone
How to install the script
Execution rights are needed for this script, also its good to be placed to a PATH directory.
$ chmod +x <script_name>
$ cp script_name /usr/bin
How to use the script
You can use it like the normal ssh command, but there will be significant slower because it will try in sequence to connect with an SSH gateway, but after connection this will work like normal SSH
$ <script_name> ssh_host
You can even pass commands like usual ssh
$ <script_name> ssh_host ls
file1.txt
file2.txt
I really hope that you will not need such an ugly hack, but in real life often we need a compromise of best practices and effectiveness.