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).
