Skip to content

Commit 90d4b2f

Browse files
authored
Merge pull request #4 from riotkit-org/feature/type-local
Version 2.0 (compatible with current stable)
2 parents 79e7d9e + 40471d9 commit 90d4b2f

13 files changed

+449
-94
lines changed

.dockerignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/Dockerfile

Dockerfile

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
FROM alpine:3.9
2+
3+
COPY ./ /rn
4+
5+
RUN apk add --update bash autossh openssh-client netcat-openbsd grep \
6+
&& rm -rf /var/cache/apk/* \
7+
&& mkdir -p /home/revproxy \
8+
&& addgroup -g 1005 revproxy \
9+
&& adduser -D -u 1005 -h /home/revproxy -G revproxy revproxy \
10+
&& chown -R revproxy:revproxy /home/revproxy
11+
12+
VOLUME "/rn/conf.d"
13+
VOLUME "/home/revproxy/.ssh"
14+
WORKDIR "/rn"
15+
16+
ENTRYPOINT ["/rn/docker-entrypoint.sh"]
17+
CMD ["/rn/bin/bind-network.sh --healthcheck-loop"]

Makefile

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
SUDO=sudo
2+
3+
all: build build_arm
4+
5+
build:
6+
${SUDO} docker build . -t wolnosciowiec/reverse-networking
7+
8+
build_arm:
9+
${SUDO} docker build -f ./armhf.Dockerfile . -t wolnosciowiec/reverse-networking:armhf

README.md

Lines changed: 73 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,26 @@
11
# reverse-networking
2-
Network setup automation scripts written in Bash, based on reverse proxy idea.
3-
Allows to create multiple reverse tunnels from inside of NAT to the external server.
2+
Network setup automation scripts written in Bash.
3+
Allows to create multiple tunnels from inside of NAT to the external server.
4+
5+
Works in two cases:
6+
- #1: Can expose a NAT hidden service to the external server (or to the internet via external server)
7+
- #2: Can encrypt a connection with external server by adding SSH layer (eg. MySQL replication with external server with SSH encryption layer)
48

59
![example structure](./docs/Reverse%20networking%20infrastructure.png "Reverse networking structure")
610

711
## Requirements
812

9-
Those packages needs to be installed:
13+
Those very basic packages needs to be installed:
1014
- bash
1115
- autossh
1216
- ssh (client)
1317
- awk
1418
- grep
1519
- nc
1620

21+
Works with GNU utils as well as with Busybox.
22+
Tested on Arch Linux, Debian and Alpine Linux.
23+
1724
*The remote server needs to support public-key authorization method.*
1825

1926
## Setup
@@ -26,7 +33,7 @@ Those packages needs to be installed:
2633
3. File must be in a proper syntax and implement proper configuration variables
2734
described as an example in the "config-example.sh.md"
2835
```
29-
36+
3037
Send public key to all servers described in your configuration
3138
so the communication could be without a password using a ssh key.
3239

@@ -41,6 +48,66 @@ Your local services should be exposed to the remote server and be
4148
visible on eg. http://localhost:1234, so you need an internal proxy or
4249
a load balancer like nginx to forward the traffic to the internet.
4350

51+
## Docker
52+
53+
Use images `wolnosciowiec/reverse-networking` and `wolnosciowiec/reverse-networking:armhf` to run container with reverse-networking installed.
54+
55+
## Example configurations
56+
57+
58+
##### Expose MySQL from docker container
59+
60+
How to connect between two separate docker networks using SSH, and access a hidden MySQL server.
61+
62+
```gherkin
63+
Given we have a HOST_1 with SSH container + MySQL container
64+
And we have a client HOST_2
65+
When we want to access MySQL:3306 from HOST_2
66+
Then we make a tunnel from HOST_2 to HOST_1 SSH container that exposes db_mysql:3306
67+
And we make it available as a localhost:3307 at HOST_2
68+
```
69+
70+
```bash
71+
PN_USER=revproxy # HOST_1 user in SSH
72+
PN_PORT=9800 # HOST_1 port
73+
PN_HOST=192.168.0.114 # HOST_1 host
74+
PN_VALIDATE=none
75+
PN_TYPE=local # connection type - we access remote resource, not exposing self to remote
76+
PN_SSH_OPTS= # optional SSH options
77+
PORTS[0]="3307>3306>db_mysql" # HOST_1 container name
78+
#PORTS[1]="3307>3306>db_mysql>@gateway" # expose on HOST_2 gateway interface (visible from internet)
79+
```
80+
81+
##### Expose ports to external server
82+
83+
Expose health check endpoints of a machine hidden behind NAT/firewall to an external machine via SSH.
84+
85+
```gherkin
86+
Given we have a HOST_1 that is a VPS with public IP address and SSH server
87+
And we have a HOST_2 that is behind NAT
88+
When we want to access /healthcheck endpoint placed at HOST_2 from internet we call http://some-subdomain.HOST_1/healthcheck
89+
Then we make a tunnel from HOST_2 to HOST_1 exposing a HTTP webserver from HOST_2 to HOST_1:8000
90+
```
91+
92+
```bash
93+
PN_USER=some_host_1_user
94+
PN_PORT=22
95+
PN_HOST=host_1.org
96+
PN_VALIDATE=local
97+
PN_TYPE=reverse
98+
PN_SSH_OPTS=
99+
100+
# optional:
101+
#PN_VALIDATE_COMMAND="curl http://mydomain.org" # custom validation command that will be ran locally or remotely
102+
103+
# destination port on remote server => local port, will be available as localhost:8000 on HOST_1
104+
PORTS[0]="80>8000"
105+
106+
# requires GatewayPorts in SSH to be enabled, can be insecure, will be available at PUBLIC_IP_ADDRESS:8001
107+
# easier option to configure, does not require a webserver to expose local port to the internet
108+
#PORTS[1]="80>8001>@gateway" # port will be available publicly
109+
```
110+
44111
#### Monitoring
45112

46113
There is a tool in `./bin/monitor.sh` that verifies all tunnels by doing a ping
@@ -61,4 +128,5 @@ Use `PN_VALIDATE_COMMAND` for custom validation executed locally or remotely if
61128
Examples:
62129
- PN_VALIDATE_COMMAND="/bin/true" # for testing purposes, try it yourself
63130
- PN_VALIDATE_COMMAND="/bin/false" # for testing
64-
- PN_VALIDATE_COMMAND="curl http://your-domain.org:8002"
131+
- PN_VALIDATE_COMMAND="curl http://your-domain.org:8002"
132+
- PN_VALIDATE_COMMAND="wget -O - -T 2 http://172.28.0.6:3307 2>&1|grep mariadb"

armhf.Dockerfile

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
FROM balenalib/armv7hf-alpine:3.9
2+
3+
COPY ./ /rn
4+
5+
RUN [ "cross-build-start" ]
6+
RUN apk add --update bash autossh openssh-client netcat-openbsd grep \
7+
&& rm -rf /var/cache/apk/* \
8+
&& mkdir -p /home/revproxy \
9+
&& addgroup -g 1005 revproxy \
10+
&& adduser -D -u 1005 -h /home/revproxy -G revproxy revproxy \
11+
&& chown -R revproxy:revproxy /home/revproxy
12+
RUN [ "cross-build-end" ]
13+
14+
VOLUME "/rn/conf.d"
15+
VOLUME "/home/revproxy/.ssh"
16+
WORKDIR "/rn"
17+
18+
ENTRYPOINT ["/rn/docker-entrypoint.sh"]
19+
CMD ["/rn/bin/bind-network.sh --healthcheck-loop"]

bin/add-to-known-hosts.sh

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
#!/bin/bash
2+
3+
#--------------------------------------------
4+
# Kill all previously opened ssh sessions
5+
#
6+
# @author RiotKit Team
7+
# @see riotkit.org
8+
#--------------------------------------------
9+
10+
cd "$( dirname "${BASH_SOURCE[0]}" )"
11+
source include/functions.sh
12+
13+
KNOWN_HOSTS_FILE=~/.ssh/known_hosts
14+
15+
#
16+
# Iterate over each host and fetch it's fingerprint
17+
#
18+
# @framework method
19+
#
20+
executeIterationAction() {
21+
config_file_name=$1
22+
23+
if contains_fingerprint ${PN_HOST} ${PN_PORT}; then
24+
echo " .. Fingerprint already present"
25+
return 0
26+
fi
27+
28+
echo " .. Fetching a fingerprint for ${PN_HOST}:${PN_PORT}"
29+
ssh-keyscan -p "${PN_PORT}" "${PN_HOST}" >> ${KNOWN_HOSTS_FILE}
30+
}
31+
32+
#
33+
# $1 - hostname
34+
# $2 - port
35+
#
36+
contains_fingerprint () {
37+
content=$(cat ${KNOWN_HOSTS_FILE})
38+
host_name=${1}
39+
40+
# non-standard port is differently formatted
41+
if [[ "${2}" != "22" ]]; then
42+
host_name="[${1}]:${2}"
43+
fi
44+
45+
if [[ "${content}" == *"${host_name} ssh-"* ]] \
46+
|| [[ "${content}" == *"${host_name} ecdsa"* ]] \
47+
|| [[ "${content}" == *"${host_name},"* ]]; then
48+
return 0
49+
fi
50+
51+
return 1
52+
}
53+
54+
echo " >> Fetching hosts fingerprint first time"
55+
cat ${KNOWN_HOSTS_FILE}
56+
iterateOverConfiguration

bin/bind-network.sh

Lines changed: 32 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -4,48 +4,41 @@
44
# Bind network ports to the remote server
55
# using a reverse proxy strategy
66
#
7-
# @author Wolnościowiec Team
8-
# @see https://wolnosciowiec.net
7+
# @author RiotKit Team
8+
# @see riotkit.org
99
#--------------------------------------------
1010

1111
cd "$( dirname "${BASH_SOURCE[0]}" )"
1212
source include/functions.sh
1313
DIR=$(pwd)
1414

15-
./kill-previous-sessions.sh
16-
17-
for config_file_name in ../conf.d/*.sh
18-
do
19-
echo " >> Reading $config_file_name"
20-
source "$config_file_name"
21-
22-
for forward_ports in ${PORTS[*]}
23-
do
24-
IFS='>' read -r -a parts <<< "$forward_ports"
25-
source_port=${parts[0]}
26-
dest_port=${parts[1]}
27-
dest_host=""
28-
29-
if [[ "${parts[2]}" ]]; then
30-
dest_host="${parts[2]}:"
31-
32-
if [[ "${dest_host}" == "@gateway:" ]]; then
33-
dest_host="$(getHostIpAddress $PN_HOST):"
34-
fi
35-
fi
36-
37-
echo " --> Forwarding ${dest_host}${source_port}:${PN_HOST}:${dest_port}"
38-
autossh -M 0 -N -f -o "PubkeyAuthentication=yes" -o "PasswordAuthentication=no" -R "${dest_host}${source_port}:localhost:${dest_port}" "${PN_USER}@${PN_HOST}" -p ${PN_PORT}
39-
40-
if [[ $? != 0 ]]; then
41-
echo " ~ The port forwarding failed, please verify if your SSH keys are well installed"
42-
exit 1
43-
fi
44-
done
45-
done
46-
47-
if [[ $1 == "--loop" ]]; then
48-
while true; do
49-
sleep 10
50-
done
51-
fi
15+
#
16+
# @framework method
17+
#
18+
executeIterationAction () {
19+
setupTunnelsForHost "${PN_USER}" "${PN_HOST}" "${PN_PORT}" "${PN_TYPE}" "${PORTS}"
20+
}
21+
22+
main () {
23+
./kill-previous-sessions.sh
24+
iterateOverConfiguration
25+
26+
if [[ $1 == "--loop" ]]; then
27+
echo ' >> Running in a loop'
28+
29+
while true; do
30+
sleep 10
31+
done
32+
fi
33+
34+
if [[ $1 == "--healthcheck-loop" ]]; then
35+
echo " >> Running a healthcheck loop (SLEEP_TIME=${LOOP_SLEEP_TIME})"
36+
37+
while true; do
38+
sleep ${LOOP_SLEEP_TIME:-5}
39+
$(dirname "${BASH_SOURCE[0]}")/../bin/monitor.sh
40+
done
41+
fi
42+
}
43+
44+
main "$@"

0 commit comments

Comments
 (0)