nftables on Debian 10 with Docker and no iptables
I run a Debian 10 system with no iptables, and some multi-container services via docker-compose. Dumping some notes here as it can be a real pain.
Installation
Install the userspace tools (the kernel modules are already baked in).
apt-get install nftables
To blacklist the iptables module, create /etc/modprobe.d/noiptables.conf
with the following:
install ip_tables /bin/false
install ip6_tables /bin/false
Start and enable the service:
systemctl enable nftables.service
systemctl start nftables.service
Docker config
In /etc/docker/daemon.json
:
{
"iptables": false
}
Previously the flag –iptables=false was used as a systemd override, but this is no longer the case.
In /etc/systemd/system/docker.service.d/override.conf
:
[Service]
ExecStart=
ExecStart=/usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock --fixed-cidr=172.17.0.0/16
This sets a static range 172.17.0.0/16
for the docker network. If you haven’t used systemd overrides before, the blank ExecStart=
is needed to clear the value before applying a new one.
Then we restart docker:
systemctl daemon-reload
systemctl restart docker
fuck you docker…. (docker-ce will always install iptables userspace tools as a dependency)
# apt-get remove iptables
Reading package lists... Done
Building dependency tree
Reading state information... Done
The following packages were automatically installed and are no longer required:
aufs-dkms aufs-tools cgroupfs-mount dkms libltdl7 linux-headers-amd64
Use 'apt autoremove' to remove them.
The following packages will be REMOVED:
docker-ce iptables
0 upgraded, 0 newly installed, 2 to remove and 5 not upgraded.
After this operation, 112 MB disk space will be freed.
Do you want to continue? [Y/n] n
Abort.
and so
ln -s /sbin/iptables-nft /local/sbin/iptables
nftables rules
A fairly simple config that works for me so far.
/etc/nftables.conf
#!/usr/sbin/nft -f
#whitelist IPs
define home = xxx.xxx.xxx.xxx
define work = xxx.xxx.xxx.xxx
#internal IPs
define docker_ipv4 = 172.17.0.0/16
flush ruleset
table inet filter {
set whitelist_ips {
type ipv4_addr
flags constant, interval
elements = { $home, $work }
}
chain base_checks {
ct state {established, related} accept
ct state invalid drop
}
chain input {
type filter hook input priority 0; policy drop;
jump base_checks
iifname lo accept
ip saddr $docker_ipv4 accept
ip saddr != @whitelist_ips drop
ip protocol icmp accept
tcp dport ssh accept
tcp dport https accept
drop
}
chain forward {
type filter hook forward priority 0; policy drop;
ct state {established,related} accept
ip saddr $docker_ipv4 oif eth0 accept
ip saddr $docker_ipv4 oifname "br-*" accept
}
chain output {
type filter hook output priority 0; policy accept;
}
}
table ip nat {
chain prerouting {
type nat hook prerouting priority 0;
}
chain postrouting {
type nat hook postrouting priority 100;
ip saddr $docker_ipv4 oif eth0 masquerade
}
}
This allows forwarding between docker interfaces and to eth0, NAT to the container network, and a filtered input.
Load up the new rules with systemctl reload nftables
Logging
nftables service logs can be viewed from journalctl --unit=nftables.service
Logging of rules can be set up such as:
ip saddr <someaddress> log prefix "Some Prefix: " accept