Various major changes

This commit is contained in:
murdrum 2020-07-31 21:56:43 +02:00
parent 45b82a06a3
commit c0d3b1941f
4 changed files with 201 additions and 19 deletions

View File

@ -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 :)
___ ___

View File

@ -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

132
setup-host-to-expose.sh Executable file
View File

@ -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"

View File

@ -1,3 +1,3 @@
USER=autossh USER=autossh
TARGET=example TARGET=jumphost
REMOTE_PORT=20001 JH_PORT=20001