You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

100 lines
5.3 KiB

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# Dockerized reverse SSH tunneling
**Case: You have a linux server (lets say a webserver) behind a corporate firewall / NAT. This means everyone outside the network cant reach that webserver.**
What you *can* do however, is initiate a connection from inside the corporate network. You can use this to set up a connection to a public server; the **middleman**, a VPS you rent at a cloud provider like Hetzner for example. A client would connect to this middleman, and the middleman would in turn pass the request trough the connection you just initiated (the one from server ➡ middleman).
Well use OpenSSH to achieve this. OpenSSH provides the tools we need by default, its secure, and available nearly everywhere.
## The middleman
Get yourself a VPS or other cheap server, and install docker. This guide was tested on a Hetzner cloud instance running alpine-linux.
1. Create a new folder and download the Dockerfile from this repo.
2. Generate an SSH keypair using `ssh-keygen -b 2048 -t rsa -f ./id_rsa -q -N ""`. This keypair will *not* be password protected because were going to automate the connection!
> Use caution with this command. If ran/copied incorrectly, you might be adding these keys to your middleman host OS instead of the docker container!
3. Build the Dockerfile `docker build . -t ssh-reverse-proxy`. This will also copy-paste the keyfile youve just created into the docker container
> I haven't given any thought to the security aspect of including sensitive information in a docker build (the ssh private key). If you plan on pushing this to a docker registry, **please research this topic first!** I figured including it in a local docker build cant hurt since the keys are already accessible on the host anyway.
4. Run the docker image, and publish the ports. Youll need to publish the containers port 22 (ssh) + any port you want to forward from your server. In the example below, we bind ssh to our middlemans port 2222, and allow the server to publish port 80 trough the middleman.
You will set up the ssh tunnel by connecting to middleman:2222!
``` bash
docker run -d \
-p 2222:22 \
-p 80:80 \
--name ssh-reverse-proxy \
ssh-reverse-proxy
```
## Server
This machine will be connecting to the middleman you just configured. Well be using a tool called autossh to monitor the tunnel and make sure its restarted in the event something crashes. In order to load our tunnel at boot, we will create a systemd boot script.
**Setting up the tunnel**
1. Make sure youre logged in as root. Well need the privileges to tunnel our privileged port (80).
2. Install autossh (depending on your OS, something like `apt-get install autossh`)
3. Before we open the tunnel, we need to retrieve the public key we just created from the middleman. You could use scp; `scp user@middleman:/path/to/git/clone/id_rsa.pub ~/reverse_ssh_key`
4. Make sure youve got the correct permissions or ssh will reject the key; `chmod 400 ~/reverse_ssh_key`
5. Create a script that will open the tunnel according to our configuration; `vi ~/autossh.sh`
``` bash
autossh -M 10984 -o PubkeyAuthentication=yes -o PasswordAuthentication=no -i \
/root/reverse_ssh_key \
-R \*:80:localhost:80 \
root@middleman -p 2222 -N
```
And add execute permissions `cmod +x ~/autossh.sh`
You can add as many ports you want, just copy line 2 and paste it between line 2 and 3. Just remember to forward it trough docker as well (middleman step 4).
Run this script in a shell to check if everything is working correctly, before adding it as a service.
**Auto-starting the tunnel**
This will only work for systemd, To check if youre running systemd, run `systemd --version`.
1. Create a file wherever your OS decided systemd files should go, and put the following inside it. For debian its; `vi /etc/systemd/system/reverse-ssh-proxy.service`
``` ini
[Unit]
Description=Reverse ssh tunnel. Publish ports from inside a restricted network.
After=network.target
[Service]
ExecStart=/root/autossh.sh
StandardOutput=inherit
StandardError=inherit
Restart=always
User=root
[Install]
WantedBy=multi-user.target
```
2. Activate the service by running `systemctl daemon-reload && systemctl enable reverse-ssh-proxy`
3. Now start the service (or reboot) `systemctl start reverse-ssh-proxy`
# Notes
Im not responsible for your beef with the sysadmin. If your corporate network is restricted, its probably for a reason.
- Although some thought has been put into security, a double-check can never hurt, right?
- If you really want to get into that docker container, you can use `docker exec -it reverse-ssh-proxy sh` to open a shell. Because of security concerns, you cannot get shell access trough SSH.
- Dockerizing the middleman is actually important for security reasons. It prevents a server from publishing ports that aren't meant to be published. For example, you cant overwrite the middlemans port 22 (and effectively locking yourself out of your middleman-server).
- Starting and stopping the middleman docker container is fine. However, when removing and re-adding the container youll regenerate the OpenSSH server keys. That means the restricted server will show a known_hosts error when trying to reconnect.