Various major changes
This commit is contained in:
parent
45b82a06a3
commit
c0d3b1941f
80
README.md
80
README.md
|
@ -1,15 +1,35 @@
|
||||||
|
|
||||||
# secure-reverse-ssh-tunnel
|
# secure-reverse-ssh-tunnel
|
||||||
|
|
||||||
This project provides ready-to-use tools to configure a remote host via an ssh tunnel and a jump host.
|
This project provides ready-to-use tools to configure a remote host via an ssh tunnel and a jump host.
|
||||||
|
|
||||||
## Example
|
## Example
|
||||||
|
|
||||||
Consider this situation:
|
### Premise:
|
||||||
- a) Your personal computer (behind NAT)
|
- HTE) Host you wish to expose. Currently network restricted (behind a FW or a NAT)
|
||||||
- b) A remote machine, like an internal server (behind NAT)
|
- EUD) End user device such as a laptop or mobile device provided with an ssh client.
|
||||||
|
- JH) A host publicly accessible over the internet (or a network accessible to voth HTE and EUD) running Openssh server.
|
||||||
|
|
||||||
To connect to your "b" machine you should configure the remote router to expose something and this should be avoided when unnecessary.
|
### Scenario:
|
||||||
So using "c" (jump server) we can create a tunnel from "b" to "c" and connect "a" to "c" and jump to "b" securely, using SSH and our private keys.
|
|
||||||
|
- EUD wants to access a service running on HTE, but HTE can be accessed only from within its own network.
|
||||||
|
- EUD can generate outgoing traffic to the internet or external networks.
|
||||||
|
- HTE can't accept incoming connections from the internet or other networks.
|
||||||
|
- HTE can generate outoing traffic to the internet or external networks.
|
||||||
|
- JH is accessible to both HTE and EUD and runs an Openssh server.
|
||||||
|
|
||||||
|
Normally, to allow communication between EUD and HTE, you would need to setup a portforward for HTE on its network's edge router. Then have EUD connect to the edge router's Public IP at the forwarded port.
|
||||||
|
|
||||||
|
This might not be feasible or out of HTE's control, thus an ssh reverse tunnel can be used.
|
||||||
|
By using a jump server we can establish a tunnel from HTE to JH and respectively a communication from EUD to JH securely, using SSH and our private keys.
|
||||||
|
At this point EUD can access HTE's service just like any other service running on JH.
|
||||||
|
The Reverse tunnel binds HTE's port to JH's network-interface:port (JumHost's localhost by default, see **GatewayPorts yes**)
|
||||||
|
Every request sent to JH binded port is going to be forarded to HTE's port.
|
||||||
|
|
||||||
|
**In ssh cli terms:**
|
||||||
|
```bash
|
||||||
|
ssh -R ${JH_PORT}:localhost:${HTE_PORT} ${USER}@${TARGET}
|
||||||
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
## Support us
|
## Support us
|
||||||
|
@ -23,20 +43,20 @@ Whether you use this project, have learned something from it, or just like it, p
|
||||||
## Components
|
## Components
|
||||||
|
|
||||||
- setup-remote-host.sh: This script must be run as root after setup step
|
- setup-remote-host.sh: This script must be run as root after setup step
|
||||||
- authorized_keys: should contains the signatures you want to use for remotehost
|
- authorized_keys: should contains the ssh pubkey for HTE
|
||||||
- config: example host configuration for "a" computer
|
- config: example host configuration for "EUD" computer
|
||||||
- secure-tunnel@.service: SystemD example but ready to use service
|
- secure-tunnel@.service: SystemD ready to use example service
|
||||||
- targets/* : contains multiple targets that need to be used as jump servers
|
- targets/* : contains multiple targets that need to be used as jump servers
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
## Setup
|
## Setup
|
||||||
|
|
||||||
Before run the script as root user, you should:
|
Before you run the script as root user, you should:
|
||||||
1) append signature of your ssh keys into authorized_keys
|
1) append your keypair's pubkey into JH authorized_keys
|
||||||
2) adjust various targets using the example provided and remove the example
|
2) edit targets based on the example provided
|
||||||
3) adjust your ~/.ssh/config like the provided one
|
3) adjust your EUD's ~/.ssh/config like the one provided.
|
||||||
4) now you are able to run the script as root on the remote machine "b".
|
4) now you are able to run the script as root on HTE.
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
@ -69,15 +89,43 @@ netstat -tupln | grep 20001
|
||||||
|
|
||||||
You should see your port associated to autossh process :)
|
You should see your port associated to autossh process :)
|
||||||
|
|
||||||
|
### Remote port forwarding
|
||||||
|
|
||||||
|
By default **sshd** will bind forwarded ports only to the server's loopback interface (localhost, 127.0.0.0/8)
|
||||||
|
|
||||||
|
For instance the following reverse tunnel :
|
||||||
|
```bash
|
||||||
|
ssh -R ${JH_PORT}:localhost:${HTE_PORT} ${USER}@${TARGET}
|
||||||
|
```
|
||||||
|
would result in a bind like this:
|
||||||
|
```bash
|
||||||
|
127.0.0.1:${JH_PORT} LISTEN pid/sshd
|
||||||
|
```
|
||||||
|
To expose forwarded ports over every jumphost's IP add the following to `/etc/ssh/sshd_config`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
GatewayPorts yes
|
||||||
|
```
|
||||||
|
###### Note:
|
||||||
|
Every forwarded port will now be publicly exposed (unless FW rules are in place.)
|
||||||
|
|
||||||
|
A better aproach would be:
|
||||||
|
```bash
|
||||||
|
GatewayPorts userspecified
|
||||||
|
```
|
||||||
|
The reverse tunnel above becomes;
|
||||||
|
```bash
|
||||||
|
ssh -R ${JH_ADDR}:${JH_PORT}:localhost:${HTE_PORT} ${USER}@${TARGET}
|
||||||
|
```
|
||||||
|
|
||||||
### Local port forward
|
### Local port forward
|
||||||
|
|
||||||
You can use your jump server "c" even to expose locally a web interface of your remote host "b" or something else with:
|
You could use your Jump Host even to bind to a local port a web interface of a remote host or something else with:
|
||||||
```bash
|
```bash
|
||||||
ssh -N -L <LOCALPORT>:127.0.0.1:<REMOTEPORT> <TARGET>
|
ssh -N -L ${LOCALPORT}:127.0.0.1:${JH_PORT} ${USER}${TARGET}
|
||||||
```
|
```
|
||||||
|
|
||||||
For example to access the pihole web interface :)
|
For example to access a remote pihole web interface locally :)
|
||||||
|
|
||||||
___
|
___
|
||||||
|
|
||||||
|
|
|
@ -5,8 +5,10 @@ After=network.target
|
||||||
[Service]
|
[Service]
|
||||||
Environment="AUTOSSH_GATETIME=0"
|
Environment="AUTOSSH_GATETIME=0"
|
||||||
EnvironmentFile=/etc/default/secure-tunnel@%i
|
EnvironmentFile=/etc/default/secure-tunnel@%i
|
||||||
ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -NR ${REMOTE_PORT}:localhost:22 ${USER}@${TARGET}
|
ExecStart=/usr/bin/autossh -M 0 -o "ServerAliveInterval 30" -o "ServerAliveCountMax 3" -o "ExitOnForwardFailure" -NR ${JH_PORT}:localhost:22 ${USER}@${TARGET}
|
||||||
User=autossh
|
User=autossh
|
||||||
|
Restart=on-failure
|
||||||
|
RestartSec=5s
|
||||||
|
|
||||||
[Install]
|
[Install]
|
||||||
WantedBy=multi-user.target
|
WantedBy=multi-user.target
|
||||||
|
|
|
@ -0,0 +1,132 @@
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
REMOTE_USER="root"
|
||||||
|
|
||||||
|
function check_if_running_as_root {
|
||||||
|
if [[ $EUID -ne 0 ]]; then
|
||||||
|
echo "This script must be run as root."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OK: Root user detected."
|
||||||
|
}
|
||||||
|
|
||||||
|
check_if_running_as_root
|
||||||
|
|
||||||
|
read -p "Did you run this script on the remote host? " -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
echo "Please rerun this script on HTE as root user."
|
||||||
|
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
read -p "Did you setup various targets and adjusted configurations as described in README?" -n 1 -r
|
||||||
|
echo
|
||||||
|
if [[ ! $REPLY =~ ^[Yy]$ ]]
|
||||||
|
then
|
||||||
|
echo "Please read README and rerun this script."
|
||||||
|
[[ "$0" = "$BASH_SOURCE" ]] && exit 1 || return 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
function check_necessary_packages {
|
||||||
|
echo "NEXT: Checking for valid package manager."
|
||||||
|
|
||||||
|
APT_GET_CMD=$(which apt-get)
|
||||||
|
YUM_CMD=$(which yum)
|
||||||
|
DNF_CMD=$(which dnf)
|
||||||
|
|
||||||
|
if [[ ! -z $APT_GET_CMD ]]; then
|
||||||
|
echo "OK: apt-get found."
|
||||||
|
apt-get --yes install autossh
|
||||||
|
elif [[ ! -z $YUM_CMD ]]; then
|
||||||
|
echo "OK: yum found."
|
||||||
|
yum install autossh
|
||||||
|
elif [[ -z $DNF_CMD ]]; then
|
||||||
|
echo "OK: yum found."
|
||||||
|
dnf install autossh
|
||||||
|
else
|
||||||
|
echo "No valid package manager found. Exiting."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
|
||||||
|
echo "OK: Autossh installed"
|
||||||
|
}
|
||||||
|
|
||||||
|
function check_for_autossh_user {
|
||||||
|
echo "NEXT: Check for existence of autossh dedicated user."
|
||||||
|
|
||||||
|
if [ ! id -u autossh >/dev/null 2>&1 ]; then
|
||||||
|
echo "The user is missing so we will create for you."
|
||||||
|
useradd -m -s /bin/false autossh
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ ! id -u autossh >/dev/null 2>&1 ]; then
|
||||||
|
echo "There are some problems with user creation. Exiting."
|
||||||
|
exit 1;
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
function adjust_ssh_folder_for {
|
||||||
|
homedir=$( getent passwd $REMOTE_USER | cut -d: -f6 )
|
||||||
|
|
||||||
|
echo "NEXT: Setup ${1} home: ${homedir}."
|
||||||
|
|
||||||
|
mkdir -p "${homedir}/.ssh"
|
||||||
|
touch -a "${homedir}/.ssh/authorized_keys"
|
||||||
|
|
||||||
|
if [ ! -s authorized_keys ]; then
|
||||||
|
echo "WARNING: authorized_keys in setup folder seems empty so you should manually setup host authorized_keys or rerun this script."
|
||||||
|
fi
|
||||||
|
cat authorized_keys >> "${homedir}/.ssh/authorized_keys"
|
||||||
|
|
||||||
|
echo "OK: Files and content ready."
|
||||||
|
echo "NEXT: Setup file and folder permissions."
|
||||||
|
|
||||||
|
chown -R "$1":"$1" "${homedir}/.ssh"
|
||||||
|
chmod 700 "${homedir}/.ssh"
|
||||||
|
chmod 600 "${homedir}/.ssh/authorized_keys"
|
||||||
|
|
||||||
|
echo "OK: File and folder permissions setup."
|
||||||
|
}
|
||||||
|
|
||||||
|
function setup_systemd_service_if_available {
|
||||||
|
echo "NEXT: Checking for systemd."
|
||||||
|
|
||||||
|
SYSTEMCTL_CMD=$(which systemctl)
|
||||||
|
if [[ ! -z $SYSTEMCTL_CMD ]]; then
|
||||||
|
echo "NEXT: Copy targets into /etc/default."
|
||||||
|
|
||||||
|
cp -n targets/* /etc/default/
|
||||||
|
|
||||||
|
echo "OK: Targets copied."
|
||||||
|
echo "NEXT: Setup systemd service."
|
||||||
|
|
||||||
|
cp secure-tunnel@.service /etc/systemd/system/
|
||||||
|
systemctl daemon-reload
|
||||||
|
|
||||||
|
echo "OK: Systemd service created."
|
||||||
|
else
|
||||||
|
echo "WARNING: No systemd installation found. You should manually setup an autossh service to keep tunnel alive."
|
||||||
|
fi
|
||||||
|
}
|
||||||
|
|
||||||
|
check_necessary_packages
|
||||||
|
check_for_autossh_user
|
||||||
|
|
||||||
|
adjust_ssh_folder_for "${REMOTE_USER}"
|
||||||
|
setup_systemd_service_if_available
|
||||||
|
|
||||||
|
echo -e "All done. Remaining steps:\n
|
||||||
|
- generate an ssh keypair with ssh-keygen for user autossh and push pubkey to the jump server
|
||||||
|
i.e. ssh-keygen -f autossh@"$jumpserver-ip" -c "$USER@$HOSTNAME" && ssh-copy-id -i autossh@"$jumpserver-ip" user@"$jumpserverip"
|
||||||
|
- Edit JumpHost's /etc/ssh/sshd_config with
|
||||||
|
|
||||||
|
Match User autossh
|
||||||
|
AllowTcpForwarding yes
|
||||||
|
X11Forwarding no
|
||||||
|
PermitTunnel yes
|
||||||
|
GatewayPorts no
|
||||||
|
AllowAgentForwarding no
|
||||||
|
|
||||||
|
- configure your client's (EUD) ~/.ssh/config like the provided one with this repo \n"
|
|
@ -1,3 +1,3 @@
|
||||||
USER=autossh
|
USER=autossh
|
||||||
TARGET=example
|
TARGET=jumphost
|
||||||
REMOTE_PORT=20001
|
JH_PORT=20001
|
||||||
|
|
Loading…
Reference in New Issue