title: Securing network access to IPv6 docker containers --- pub_date: 2019-12-14 --- author: ungleich virtualisation team --- twitter_handle: ungleich --- _hidden: no --- _discoverable: yes --- abstract: Configure your firewall correctly for IPv6 docker containers --- body: Like in any situation, we should secure our systems. In the legacy IPv4 world, things are often not clear due to the use of NAT (network address translation). Things are much more transparent and also easier with IPv6. In this article we give easy to follow instructions on how to secure your IPv6 based docker containers. If you don't know yet how to enable IPv6 on your docker containers, you can follow [how to enable IPv6 in docker](https://ungleich.ch/u/blog/how-to-enable-ipv6-in-docker/). ## Docker containers with IPv6 IPv6 was made to restore direct connectivity, like the Internet was designed to be in the first place. So instead of needing to "expose ports" or to add "port forwarding", IPv6 addresses are generally directly reachable. This is nice and general, but if we run containers that are not fully secured, this is a security risk. For this reason we should limit access to our docker containers. ## Network firewall with nftables You might have seen noticed that in the Linux world we are moving from iptables to nftables. In case you need a refresher on the differences, checkout the article about [iptables vs. nftables](https://ungleich.ch/en-us/cms/blog/2018/08/18/iptables-vs-nftables/). ## What to allow, what to filter? So what should be the general general rules for accessing our docker containers? We have made a short list on what we think is a good way to expose your docker containers: First, allow ping6 and various helper packets from icmp6. This way our containers can react on debugging messages from the network and are working in settings with different MTUs. The rule for this in nftables looks as follows: ``` icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept ``` Secondly, allow the tcp ports 22 (ssh), 80 (http) and 443 (https). While http is unencrypted, we need to open it so that letsencrypt certificate verifications can work. And we want to be able to get letsencrypt certificates to secure communication with https. In nftables, this reads as follows: ``` tcp dport { 22, 80, 443 } accept ``` And the rest? We will drop the rest. This is as simple as saying `drop` in nftables. ## Putting it all together So how does this look like in a complete picture? You can use the below configuration directly on your machine, just replace **2001:db8::/64** with your IPv6 docker network. ``` table ip6 filter { chain forward { type filter hook forward priority filter; policy accept; ct state established,related accept ip6 daddr 2001:db8::/64 jump to_docker_container } chain to_docker_container { icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, parameter-problem, echo-request, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert } accept tcp dport { 22, 80, 443 } accept drop } } ``` You can save this snippet as nftables.conf and run `nft -f nftables.conf` to apply it. Use `nftables list ruleset` to see your active rules. ## Proxying insecure applications With the above firewall you can run your insecure applications on any port that is not 22, 80 or 443. And then you can use a side car or proxy to expose it securely. If you use above firewall, we recommend to run your insecure (http) containers on port 8080. This indicates it is http (alike) and is also automatically blocked from the outside world. ## Learning more about this You can give above a direct try with a VM from [IPv6onlyhosting](https://IPv6onlyhosting.com), where you also get a /64 for free per VM. Or you can talk to others about it on the [IPv6.Chat](https://IPv6.chat).