In diesem Artikel soll gezeigt werden, wie man einen bestehenden Docker Host konfiguriert, so dass einzelne Container über das IPv6 Protokoll erreichbar sind. Dabei soll die jeweilige Adresse eines Containers statisch und über das Internet erreichbar sein.

Der Artikel stellt die Fortsetzung von Vom blanken Server zum Docker Host dar.

Voraussetzungen

Um diese Anleitung nachvollziehen zu können, muss ein Server mit eingerichtetem Docker vorhanden sein. Des Weiteren muss dem Server ein IPv6 Adressraum zugeordnet sein. Der Adressraum muss mindestens eine Größe von /64 aufweisen.

Zu beachten ist, dass die in Containern verwendeten Anwendungen ebenfalls IPv6 unterstützen müssen. Ältere Anwendungen, die lediglich IPv4 unterstützen, können nicht ohne Weiteres erreicht werden.

In den weiteren Schritten wird angenommen, dass auf dem Server ein Debian oder darauf aufbauendes System installiert ist. Bei anderen Systemen können die Schritte abweichen. Der dem Server zugewiesene IPv6 Adressraum ist 2001:db8:1:0::/64.

Docker konfigurieren

  • IPv6 aktivieren
  • Subnetz zuweisen
  • Docker Bridge Network mit weiterem Subnetz erstellen

Um Docker für IPv6 konfigurieren zu können, müssen vom gegebenen /64 Adressraum ein Block der Größe /80 abgetrennt werden. Die Größe ergibt sich daraus, dass Docker bei der Zuweisung von IPv6 Adressen die jeweilige MAC Adresse eines Containers als Suffix der IPv6 Adresse verwendet, sofern keine statische Adresse vergeben wird.

Der /80 Adressraum sollen folgende Adresse haben: 2001:db8:1:0:1::/80

Um IPv6 in Docker zu aktivieren, muss die Datei /etc/default/docker angepasst werden. Die Zeile mit der Zuweisung DOCKER_OPTS muss folgendermaßen angepasst werden:

DOCKER_OPTS="--dns 8.8.8.8 --dns 8.8.4.4 --ipv6 --fixed-cidr-v6='2001:db8:1:0:1::/80'"

Anschließend muss Docker neu gestartet werden. Durch den Neustart legt Docker automatisch die benötigten Einträge in der Routing-Tabelle des Hosts an. Somit werden alle eingehenden Anfragen an den gegebenen Adressraum direkt an Docker und die darin laufenden Container weitergegeben.

Da die MAC Adressen der Container bei jeder Erstellung neu vergeben werden, sind diese nicht als statisch zu betrachten. Somit eignen sie sich nicht, um in einem quad-A DNS Record hinterlegt zu werden.

Zunächst muss ein zusätzliches Bridge Netzwerk für den Adressraum 2001:db8:1:0:1::/80 erstellt werden.

$ docker network create -—driver=bridge -—ipv6 —-subnet=2001:db8:1:0:1::/80 ipv6

Host konfigurieren

Neighbor Discovery Protocol Proxy Daemon

Damit Container aus dem Internet erreichbar sind, muss der Dienst NDPPD installiert werden. Dieser sorgt automatisch dafür, dass Container dem übergeordneten Router bekanntgegeben werden.

$ apt-get install -y ndppd
$ cp /usr/share/doc/ndppd/ndppd.conf-dist /etc/ndppd.conf

Anschließend muss die Konfiguration von NDPPD angepasst werden.

  • rule auf 2001:db8:1:0:1::/80 setzen

ip6tables

Damit über IPv6 angebundene Container Anfragen in das Internet senden können, muss eine POSTROUTING Regel mittels ip6tables gesetzt werden.

$ ip6tables -t nat -A POSTROUTING -s fd00::/80 ! -o docker0 -j MASQUERADE

Dieser Befehl kann in ein Firewall-Script integriert werden.

Für die Erstellung eines Firewall-Scripts mittels ip6tables habe ich mich an folgendem Artikel aus dem Admin Magazin orientiert: https://www.admin-magazin.de/Das-Heft/2014/04/Ein-Basisregelwerk-mit-IP6Tables

#!/bin/bash
IPT="/sbin/ip6tables"
PUB_IF="eth0"
DOCKER_IF="docker0"
HOST_ADDR="2001:db8:1::1"
DOCKER_NET="2001:db8:1:0:1::/80"
$IPT -F

# DROP all unspecified traffic
$IPT -P INPUT DROP
$IPT -P OUTPUT DROP
$IPT -P FORWARD DROP

# Allow loopback
#$IPT -A INPUT -i lo -j ACCEPT
#$IPT -A OUTPUT -o lo -j ACCEPT# Block tunnels

# Allow full outgoing connection but no incomming stuff
$IPT -A INPUT -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A FORWARD -m state --state ESTABLISHED,RELATED -j ACCEPT
$IPT -A OUTPUT -m state --state NEW,ESTABLISHED,RELATED -j ACCEPT

# Block tunnels
$IPT -A INPUT -s 2002::/16 -j DROP
$IPT -A INPUT -s 2001:0::/32 -j DROP
$IPT -A FORWARD -s 2002::/16 -jDROP
$IPT -A FORWARD -s 2001:0::/32 -j DROP

# Block IPv6 in IPv4
$IPT -A INPUT -p 41 -j DROP
$IPT -A FORWARD -p 41 -j DROP

# Block spoofing
$IPT -A INPUT ! -i lo -s ::1/128 -j DROP
$IPT -A INPUT -i $PUB_IF -s FC00::/7 -j DROP
$IPT -A FORWARD -s ::1/128 -j DROP
$IPT -A FORWARD -i $PUB_IF -s FC00::/7 -j DROP

# Allow Docker traffic
$IPT -t nat -A POSTROUTING -s fd00::/80 ! -o $DOCKER_IF -j MASQUERADE
$IPT -A FORWARD -p tcp -i $PUB_IF -d $DOCKER_NET --destination-port 80 -j ACCEPT
$IPT -A FORWARD -p tcp -i $PUB_IF -d $DOCKER_NET --destination-port 443 -j ACCEPT
$IPT -A FORWARD -p icmpv6 -i $PUB_IF -d $DOCKER_NET -j ACCEPT

# Allow ssh
$IPT -A INPUT -p tcp -d $HOST_ADDR --destination-port 22 -j ACCEPT

# Allow ICMP
$IPT -A INPUT -p icmpv6 --icmpv6-type 1 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 2 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 3 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 4 -j ACCEPT
$IPT -A FORWARD -i $PUB_IF -p icmpv6 --icmpv6-type 1 -j ACCEPT
$IPT -A FORWARD -i $PUB_IF -p icmpv6 --icmpv6-type 2 -j ACCEPT
$IPT -A FORWARD -i $PUB_IF -p icmpv6 --icmpv6-type 3 -j ACCEPT
$IPT -A FORWARD -i $PUB_IF -p icmpv6 --icmpv6-type 4 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 133 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 134 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 135 -j ACCEPT
$IPT -A INPUT -p icmpv6 --icmpv6-type 136 -j ACCEPT
$IPT -A OUTPUT -p icmpv6 --icmpv6-type 133 -j ACCEPT
$IPT -A OUTPUT -p icmpv6 --icmpv6-type 134 -j ACCEPT
$IPT -A OUTPUT -p icmpv6 --icmpv6-type 135 -j ACCEPT
$IPT -A OUTPUT -p icmpv6 --icmpv6-type 136 -j ACCEPT
$IPT -A INPUT ! -i $PUB_IF -p icmpv6 --icmpv6-type 128 -j ACCEPT
$IPT -A OUTPUT -p icmpv6 --icmpv6-type 128 -j ACCEPT
$IPT -A FORWARD ! -i $PUB_IF -p icmpv6 --icmpv6-type 128 -j ACCEPT

# Do not log smb/windows sharing packets - too much logging
$IPT -A INPUT -p tcp -i ${PUB_IF} --dport 137:139 -j REJECT
$IPT -A INPUT -p udp -i ${PUB_IF} --dport 137:139 -j REJECT

# drop everything else
$IPT -A INPUT -j DROP
exit 0

Sollte das primäre Netzwerk-Interface nicht eth0 sein, muss die Zeile 4 entsprechend angepasst werden. In Zeile 6 muss die IPv6 Adresse des Servers angegeben werden und in Zeile 7 das für Docker vorgesehene IPv6 Subnetz.

Wie man das Script beim Systemstart aufruft, kann in meinem Artikel Vom blanken Server zum Docker Host übernommen werden.

Container an IPv6 anbinden

Abschließend müssen Container, die über eine statische IPv6 Adresse erreichbar sein sollen, an das Netzwerk angehängt werden. Ein bestehender Container kann mit folgendem Befehl angehängt werden.

$ docker network connect —ip6 2001:db8:1:0:2::2 ipv6 myContainer

Der Container myContainer ist damit über die Adresse 2001:db8:1:0:2::2 aus dem Internet erreichbar. Die Adresse 2001:db8:1:0:2::1 kann nicht vergeben werden, da diese automatisch dem Docker Dienst zugeordnet ist und als Gateway für ausgehende Verbindungen dient.

Zusammenfassung

Es wurde gezeigt, wie ein bestehender Docker Host um IPv6 Funktionen erweitert werden kann. Darin laufende Container können mit statischen IPv6 Adressen versehen werden, die aus dem Internet erreichbar sind.