Weave offers a couple of features that fall under the umbrella of security. Since Weave is an overlay-based network solution, it offers the ability to encrypt the overlay traffic as it traverses the physical or underlay network. This can be particularly useful when your containers may need to traverse a public network. In addition, Weave allows you to isolate containers within certain network segments. Weave relies on using different subnets for each isolated segment to achieve this. In this recipe, we'll walk through how to configure both overlay encryption as well as how to provide isolation for different containers across the Weave network.
It is assumed that you're building off the lab we created in the first recipe of this chapter. It is also assumed that the hosts have Docker and Weave installed. Docker should be in its default configuration, and Weave should be installed but not yet peered. If you need to remove the peering defined in previous examples, issue the weave reset
command on each host.
Configuring Weave to encrypt the overlay network is fairly straightforward to accomplish; however, it must be done during the initial configuration of Weave. Using the same lab topology from the previous recipes, let's run the following commands to build the Weave network:
docker1
:weave launch-router --password notverysecurepwd --trusted-subnets 192.168.50.0/24 --ipalloc-range 172.16.16.0/24 --ipalloc-default-subnet 172.16.16.128/25
docker2
, docker3
,and docker4
:weave launch-router --password notverysecurepwd --trusted-subnets 192.168.50.0/24 --ipalloc-range 172.16.16.0/24 --ipalloc-default-subnet 172.16.16.128/25 10.10.10.101
You'll note that the command we run on the hosts is largely the same with the exception of the last three hosts specifying docker1
as a peer in order to build the Weave network. In either case, there are a few additional parameters we've passed to the router during Weave initialization:
--password
: This is what enables the encryption for the communication between Weave nodes. You should, unlike in my example, pick a very secure password to use. This needs to be the same on every node running weave.--trusted-subnets
: This allows you to define subnets of hosts as trusted, which means they don't require their communication to be encrypted. When Weave does encryption it falls back to a slower data path than what is normally used. Since using the --password
parameter turns on encryption end to end, it might make sense to define some subnets as not needing encryption--ipalloc-range
: Here, we define the larger Weave network to be 172.16.16.0/24
. We saw this command used in earlier recipes:--ipalloc-default-subnet
: This instructs Weave to, by default, allocate container IP addresses out of a smaller subnet of the larger Weave allocation. In this case, that's 172.16.16.128/25
.Now, let's run the following containers on each host:
docker1
:weave run -dP --name=web1tenant1 jonlangemak/web_server_1
docker2
:weave run -dP --name=web2tenant1 jonlangemak/web_server_2
docker3
:weave run net:172.16.16.0/25 -dP --name=web1tenant2
jonlangemak/web_server_1
docker4
:weave run net:172.16.16.0/25 -dP --name=web2tenant2
jonlangemak/web_server_2
You'll note that on the host docker3
and docker4
, I added the net:172.16.16.0/25
parameter. Recall when we started the Weave network, we told Weave to by default allocate IP addresses out of 172.16.16.128/25
. We can override this at container runtime and provide a new subnet for Weave to use so long as it's within the larger Weave network. In this case, the containers on docker1
and docker2
will get an IP address within 172.16.16.128/25
because that is the default. The containers on docker3
and docker4
will get an IP address within 172.16.16.0/25
since we overrode the default. We can confirm this once you've started all the containers:
user@docker4:~$ weave status dns web1tenant1 172.16.16.129 26c58ef399c3 12:d2:fe:7a:c1:f2 web1tenant2 172.16.16.64 4c569073d663 ae:af:a6:36:18:37 web2tenant1 172.16.16.224 211c2e0b388e e6:b1:90:cd:76:da web2tenant2 172.16.16.32 191207a9fb61 42:ec:92:86:1a:31 user@docker4:~$
As I mentioned earlier, using distinct subnets is how Weave provides for container segmentation. In this case, the topology would look like this:
The dotted lines symbolize the isolation that Weave is providing for us in the overlay network. Since the tenant1
containers live is a separate subnet from the tenant2
containers, they will not have connectivity. In this manner, Weave is using basic networking to allow for container isolation. We can prove this works with a few tests:
user@docker4:~$ docker exec -it web2tenant2 curl http://web1tenant2 <body> <html> <h1><span style="color:#FF0000;font-size:72px;">Web Server #1 - Running on port 80</span> </h1> </body> </html> user@docker4:~$ docker exec -it web2tenant2 curl http://web1tenant1 user@docker4:~$ docker exec -it web2tenant2 curl http://web2tenant1 user@docker4:~$ user@docker4:~$ docker exec -it web2tenant2 ping web1tenant1 -c 1 PING web1tenant1.weave.local (172.16.16.129): 48 data bytes --- web1tenant1.weave.local ping statistics --- 1 packets transmitted, 0 packets received, 100% packet loss user@docker4:~$
You'll notice that when the web2tenant2
container attempts to access a service within its own tenant (subnet), it works as expected. Attempts to access a service in tenant1
receive no response. However, since DNS is shared across the Weave network, the container can still resolve the IP address of the containers in tenant1
.
This also illustrates an example of encryption and how we can specify certain hosts as being trusted. Regardless of which subnetwork the containers live in, Weave still builds connectivity between all of the hosts. Since we enabled encryption during Weave initialization, all of those connections should now be encrypted. However, we also specified a trusted network. The trusted network defines nodes that do not require encryption between themselves. In our case, we specified 192.168.50.0/24
as being trusted. Since there are two nodes that have those IP addresses, docker3
and docker4
, we should see that the connectivity between them is unencrypted. We can validate that using the weave status connections command on the hosts. We should get the following response:
docker1
(truncated output):<- 10.10.10.102:45888 established encrypted sleeve <- 192.168.50.101:57880 established encrypted sleeve <- 192.168.50.102:45357 established encrypted sleeve
docker2
(truncated output):<- 192.168.50.101:35207 established encrypted sleeve <- 192.168.50.102:34640 established encrypted sleeve -> 10.10.10.101:6783 established encrypted sleeve
docker3
(truncated output):-> 10.10.10.101:6783 established encrypted sleeve
-> 192.168.50.102:6783 established unencrypted fastdp
-> 10.10.10.102:6783 established encrypted sleeve
docker4
(truncated output):-> 10.10.10.102:6783 established encrypted sleeve
<- 192.168.50.101:36315 established unencrypted fastdp
-> 10.10.10.101:6783 established encrypted sleeve
You can see that all the connections show as encrypted with the exception of the connections between the host docker3
(192.168.50.101
) and the host docker4
(192.168.50.102
). Since both hosts need to agree on what a trusted network is, the hosts docker1
and docker2
will never agree for their connections to be unencrypted.