Tag Archives: bastion

Remote port forwarding via SSH

Imagine that you want to access a specific port on a remote server from your local machine. Basically, a “remote port forwarding”.

This remote server is not accessible directly from internet. It is NAT’d behind firewall.
To access the remote server you need to connect firstly to a remote bastion server (accessible from internet) and from there, you will be able to access the server.
Your current machine is also within restricted network and unable to ssh out. You can ssh into a local bastion server only. From this local bastion you can ssh out.

As long as you have access to the 2 bastions servers, you will be able to run the following script.

+-------------------------------+                  +-------------------------------+
|                               |                  |                               |
| +--------+         +--------+ |                  | +--------+         +--------+ |
| | LOCAL  |         | LOCAL  | |                  | | REMOTE |         | REMOTE | |
| | MACHINE| +-----> | BASTION| +---> INTERNET +---> | BASTION| +-----> | SERVER | |
| |        |         |        | |                  | |        |         |        | |
| +--------+         +--------+ |                  | +--------+         +--------+ |
|                               |                  |                               |
+-------------------------------+                  +-------------------------------+

The script points/links a local_port on your local machine to the ssh port of the remote bastion, via your local bastion.
After that, it will connect the remote port or the remote server to a new_local_port, ssh’ing via local_port.

Example below shows a way to have the VNC port 5900 available locally on port 5910.
I’m using port 8888 as local port.
Local Bastion ssh port is 8022.
Remote Bastion ssh port is 9022.

Example:

ssh -N -f -p 8022 -L8888:remote_bastion:9022 local_bastion_user@local_bastion
ssh -N -f -p 8888 -L5910:remote_server:5900 remote_bastion_user@localhost

 

And here a full script:

#!/bin/bash
#
# ============================================ #
# PORT FORWARD from CURRENT_HOST to DEST_HOST  #
# via LOC_BASTION and REMOTE_BASTION           #
# ============================================ #
#
# The scripts creates an SSH tunnel connecting
# the local port TUN_LOC_PORT to the REMOTE_BASTION ssh port
# via LOC_BASTION.
# After that, it forwards the remote port DEST_FW_PORT to
# DEST_FW_PORT using the ssh tunnel just created.
#
###########################################################

LOC_BASTION_HOST=""
LOC_BASTION_USER=""
LOC_BASTION_SSH_PORT=""

REMOTE_BASTION_HOST=""
REMOTE_BASTION_USER=""
REMOTE_BASTION_SSH_PORT=""

DEST_HOST=""
DEST_USER=""
DEST_FW_PORT="5900"

TUN_LOC_PORT="8888"
LISTENING_LOC_PORT=""

############################################################

CHECK_TUNS=$(ps aux | grep "[s]sh -N -f -p $LOC_BASTION_SSH_PORT -L$TUN_LOC_PORT:$REMOTE_BASTION_HOST:$REMOTE_BASTION_SSH_PORT $LOC_BASTION_USER@$LOC_BASTION_HOST" | awk '{print $2}')

N_TUNS=$(echo $CHECK_TUNS | wc -l)

create_tunnel(){
  # Create a connection between localhost:$TUN_LOC_PORT to MIDDLE_BOX:SSH_PORT
  # It will ask for MIDDLE_BOX's password
  # -N -f keep the connection open in background executing No commands
  ssh -N -f -p $LOC_BASTION_SSH_PORT -L$TUN_LOC_PORT:$REMOTE_BASTION_HOST:$REMOTE_BASTION_SSH_PORT $LOC_BASTION_USER@$LOC_BASTION_HOST
  echo "Created new tunnel"
}

check_tunnel(){
nc -w 1 -z localhost $TUN_LOC_PORT > /dev/null 2>&1
}

reset_tunnel() {
for PID in $CHECK_TUNS; do
   kill -9 $PID > /dev/null 2>&1
   echo "Found multiple tunnels. Killed all."
done
}


# Hidden function. Add 'cleanup' as argument to close all the tunnels
[ "$1" == "cleanup" ] && reset_tunnel && exit 0

if [ $N_TUNS -eq 0 ] ; then
   create_tunnel
elif [ $N_TUNS -eq 1 ] ; then
   check_tunnel
   if [ $? -eq 0 ] ; then
      echo "Tunnel already up and running"
   else
      reset_tunnel
      create_tunnel
   fi
else
   reset_tunnel
   create_tunnel
fi


CHECK_PORT_FWD=$(ps aux | grep -q "[s]sh -N -f -p $TUN_LOC_PORT -L$LISTENING_LOC_PORT:$DEST_HOST:$DEST_FW_PORT -l $REMOTE_BASTION_USER localhost")
if [ $? -eq 0 ] ; then
   echo "Port forward already created. Remote port $DEST_FW_PORT should be accessible on localhost port $LISTENING_LOC_PORT"
   exit 0
 else
   # This will create 'link' between $DEST_FW_PORT from $DEST_HOST to $TUN_LOC_PORT on localhost
   echo "Creating link between $DEST_FW_PORT to $TUN_LOC_PORT on localhost via $DEST_HOST"
   ssh -N -f -p $TUN_LOC_PORT -L$LISTENING_LOC_PORT:$DEST_HOST:$DEST_FW_PORT -l $REMOTE_BASTION_USER localhost
   echo "You can now access $DEST_FW_PORT listening on $DEST_HOST from localhost on port $LISTENING_LOC_PORT."
fi

 

SSH tunnel from A to B via jumpbox

Here a basic script that you can use if you want to connect from your local box, via a middle linux machine, to a third host.
It will also allow you to use FoxyProxy on your browser and browse the internal network of the destination box.

BOX_A <==== MIDDLE_BOX ====> BOX_B

The goal is having access from BOX_A to BOX_B via MIDDLE_BOX

MIDDLE_BOX is the only one that can talk withBOX_A and BOX_B

 

#!/bin/bash
#
# ==================================================== #
# Tunnel from CURRENT_HOST to DEST_HOST via MIDDLE_BOX #
# ==================================================== #
#
# The scripts connects the local port 8888 
# to the SSH port on DEST_BOX via MIDDLE_BOX.
#

MIDDLE_BOX_HOST="bastion_server.localdomain.loc"
MIDDLE_BOX_USER="username"
MIDDLE_BOX_SSH_PORT="22"

DEST_BOX_HOST="destination_host.domain.com"
DEST_BOX_USER="username"
DEST_BOX_SSH_PORT="22"

LOC_PORT=8888
SOCK_PORT=9050

############################################################

CHECK_TUNS=$(ps aux | grep "[s]sh -N -f -p $MIDDLE_BOX_SSH_PORT -L$LOC_PORT:$DEST_BOX_HOST:$DEST_BOX_SSH_PORT $MIDDLE_BOX_USER@$MIDDLE_BOX_HOST" | awk '{print $2}')

N_TUNS=$(echo $CHECK_TUNS | wc -l)

create_tunnel(){
  # Create a connection between localhost:$LOC_PORT to MIDDLE_BOX:SSH_PORT
  # It will ask for MIDDLE_BOX's password
  # -N -f keep the connection open in background executing No commands
  ssh -N -f -p $MIDDLE_BOX_SSH_PORT -L$LOC_PORT:$DEST_BOX_HOST:$DEST_BOX_SSH_PORT $MIDDLE_BOX_USER@$MIDDLE_BOX_HOST
  echo "Created new tunnel"
}

check_tunnel(){
nc -w 1 -z localhost $LOC_PORT > /dev/null 2>&1
}

reset_tunnel() {
for PID in $CHECK_TUNS; do
   kill -9 $PID > /dev/null 2>&1
   echo "Found multiple tunnels. Killed all."
done
}

# Hidden function. Add 'cleanup' as argument to close all the tunnels
[ "$1" == "cleanup" ] && reset_tunnel && exit 0

if [ $N_TUNS -eq 0 ] ; then
   create_tunnel
elif [ $N_TUNS -eq 1 ] ; then
   check_tunnel
   if [ $? -eq 0 ] ; then
      echo "Tunnel already up and running"
   else
      reset_tunnel
      create_tunnel
   fi
else
   reset_tunnel
   create_tunnel
fi


CHECK_SOCK=$(ps aux | grep -q "[s]sh -D$SOCK_PORT -p$LOC_PORT $DEST_BOX_USER@localhost")
if [ $? -eq 0 ] ; then
   echo "Sock already created on port $SOCK_PORT - just opening SSH shell on $DEST_BOX_HOST"
   ssh -p$LOC_PORT $DEST_BOX_USER@localhost
 else
   # This will open an SSH shell from DEST_BOX *AND* create a sock proxy on port $SOCK_PORT locally
   # You can use FoxyProxy in your browser to browse the DEST_BOX's network
   # Just set "localhost", dest port "$SOCK_PORT" and select "Socks Proxy"
   echo "Created sock on port $SOCK_PORT and ssh'ing on $DEST_BOX_HOST"
   ssh -D$SOCK_PORT -p$LOC_PORT $DEST_BOX_USER@localhost
fi