From charlesreid1

Setting up networking between containers and host.

Stunnel

Configuring

Stunnel networking configuration:

The stunnel server is running in a Docker container. Here is the stunnel server configuration file:

# server config,
# stunnel server will listen for stunnel clients connecting on port 443
# traffic will be decrypted and forwarded to local port 22

output	= /var/log/stunnel4/stunnel.log
cert	= /etc/stunnel/stunnel.fullchain.pem
key		= /etc/stunnel/stunnel.key.pem
pid		= /var/run/stunnel4/stunnel.pid
client	= no
[ssh]
accept	= 443
connect = 127.0.0.1:22

Note this is the same as is in the d-stunnel repo on git.charlesreid1.com: https://git.charlesreid1.com/docker/d-stunnel

Binding Ports 443 and 22

Stunnel server listens on port 443 (internal). This is mapped to port 443 (external) on the host using the -p 443:443 flag when executing docker run.

Stunnel forwards traffic on to 127.0.0.1 port 22. This port needs to be bound, somehow, to somewhere. Keep it simple: bind container port 22 (internal) to host port 22 (external) using -p 22:22 when executing docker run.

Running Container

Now the container should be started up, and stunnel should be run from within the container:

docker run \
	--network=host \
	-p 443:443 -p 22:22 \
	-ti cmr_stunnel \
	/bin/bash

Note: if you leave out the --network=host flag, and you try and listen on port 22, you will see an error:

$ ./run_docker.sh
docker: Error response from daemon: driver failed programming external connectivity on endpoint adoring_torvalds (53df66409442dab5e2a035d16238927ad004a34e410035878042a22f57af623f): Error starting userland proxy: listen tcp 0.0.0.0:22: bind: address already in use.

This is because you're asking the host to dedicate port 22 to listening to the Docker container, but there is already a service (SSH) running on the host, independent of Docker, that is listening for connections.

By specifying that the docker container should use the network host, you are avoiding the need for the host to listen on the network interface itself, and forward any traffic along to other ports. The host and container are simply utilizing the same port, on the same network interface. This allows the Docker container to communicate with the host using port 22 - the host is listening on port 22, and the docker container is forwarding traffic to port 22.

Checking Container Networking

Use two commands to check that the container has been correctly bound to the two ports:

$ nmap localhost
$ netstat -tulpn

Here is what the output of nmap looks like after running the Docker container:

$ nmap localhost

Starting Nmap 7.01 ( https://nmap.org ) at 2017-03-30 23:27 UTC
Nmap scan report for localhost (127.0.0.1)
Host is up (0.00012s latency).
Other addresses for localhost (not scanned): ::1
Not shown: 997 closed ports
PORT    STATE SERVICE
22/tcp  open  ssh
80/tcp  open  http
443/tcp open  https

Nmap done: 1 IP address (1 host up) scanned in 0.07 seconds

And here is the output of the netstat command:

$ netstat -tulpn
(Not all processes could be identified, non-owned process info
 will not be shown, you would have to be root to see it all.)
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address           Foreign Address         State       PID/Program name
tcp        0      0 0.0.0.0:22              0.0.0.0:*               LISTEN      -
tcp        0      0 0.0.0.0:443             0.0.0.0:*               LISTEN      -
tcp6       0      0 :::80                   :::*                    LISTEN      -
tcp6       0      0 :::22                   :::*                    LISTEN      -

Note that the SSH service is not run in a Docker container, it is run on the host machine.

Connecting to Container

Now set up an stunnel client to connect to the stunnel server and test out the port mapping:

$ cat stunnel.conf
# client config,
# will ssh directly to local port 2222
# ssh -p 2222 root@localhost
# stunnel client connects to remote stunnel server at IP A.B.C.D over external port 443

output 	= /var/log/stunnel4/stunnel.log
cert 	= /usr/local/etc/stunnel/fullchain.pem
key		= /usr/local/etc/stunnel/privkey.pem
pid 	= /var/run/stunnel4/stunnel.pid
client  = yes
[ssh]
accept 	= 2222
connect = A.B.C.D:443

Now start stunnel on the client to establish a connection with the server:

$ stunnel

(Make sure you check the error log and resolve any error messages that are printed. See Stunnel/Client for more.)

Once the stunnel connection is made, you should be able to connect to the remote server via a local port:

$ ssh -p 2222 root@localhost
The authenticity of host '[localhost]:2222 ([127.0.0.1]:2222)' can't be established.
ECDSA key fingerprint is SHA256:9DL2ohTkZFI9oaqUtMlA5X7gTJW/mmWbC+z7DyrZHzo.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added '[localhost]:2222' (ECDSA) to the list of known hosts.
root@localhost's password:
Welcome to Ubuntu 16.04.2 LTS (GNU/Linux 4.9.7-x86_64-linode80 x86_64)

 * Documentation:  https://help.ubuntu.com
 * Management:     https://landscape.canonical.com
 * Support:        https://ubuntu.com/advantage
Last login: Wed Mar 29 06:44:50 2017 from 127.0.0.1

root@localhost:~# ifconfig

<shows IP config information for remote stunnel server>

Network Equals Host Flag

Note that you can also configure the container to share networks with the host, by adding --network=host when executing docker run.


Flags