Hello all,
this is my first post here. My background: I have been administering Linux servers for over a decade. About a week ago I did a Discourse installation on a server (Debian Bullseye). I like it so far great!
Now I wanted to implement the usual hardening measures on the host system (eg. webserver). This includes nftables rulesets among other things. I generally use these:
#!/usr/sbin/nft -f
####################
# Purge/Flush #
####################
flush ruleset
####################
# Incoming Traffic #
####################
table inet filter {
chain input {
type filter hook input priority 0; policy drop;
# Allow loopback interface
iifname lo accept
# Rate limit ICMPv4|ICMPv6 traffic
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem, router-solicitation, router-advertisement } limit rate over 5/second drop
ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, parameter-problem, echo-reply, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert } limit rate over 5/second drop
# Allow packets to established/related connections
ct state established,related accept
# Drop invalid connections
ct state invalid drop
# Allow ICMPv4: Ping requests | Error messages | Router selection messages
ip protocol icmp icmp type { echo-request, echo-reply, destination-unreachable, time-exceeded, parameter-problem, router-solicitation, router-advertisement } accept
# Allow ICMPv6 traffic (https://tools.ietf.org/html/rfc4890#page-18)
ip6 nexthdr icmpv6 icmpv6 type { destination-unreachable, packet-too-big, time-exceeded, echo-request, parameter-problem, echo-reply, nd-router-solicit, nd-router-advert, nd-neighbor-solicit, nd-neighbor-advert, ind-neighbor-solicit, ind-neighbor-advert } accept
# Allow SSH access on port 2222 [rate limit]
tcp dport 2222 ct state new limit rate 3/minute accept
# Allow HTTP / HTTPS traffic
tcp dport { http, https } accept
# Reject other packets
ip protocol tcp reject with tcp reset
ip6 nexthdr tcp reject with tcp reset
}
####################
# Forward Traffic #
####################
chain forward {
type filter hook forward priority 0; policy drop;
}
####################
# Outgoing Traffic #
####################
chain output {
type filter hook output priority 0; policy accept;
# Allow loopback interface
oifname lo accept
}
}
However, after activation Discourse stopped working. I suspect the packages are not being passed to the Docker installation of Discourse. This rule in particular is likely to be problematic:
####################
# Forward Traffic #
####################
chain forward {
type filter hook forward priority 0; policy drop;
}
But before I start tinkering now, I wanted to ask if anyone has already dealt with this issue and has working firewall rules for the base system. Do these rules even make sense for a Docker Discourd installation? So far I have had little to do with Docker.
Some more information. These firewall rules are automatically added by Docker (docker-ce):
table ip nat {
chain DOCKER {
iifname "docker0" counter packets 0 bytes 0 return
iifname != "docker0" meta l4proto tcp tcp dport 443 counter packets 155 bytes 7070 dnat to 172.17.0.2:443
iifname != "docker0" meta l4proto tcp tcp dport 80 counter packets 128 bytes 6263 dnat to 172.17.0.2:80
}
chain POSTROUTING {
type nat hook postrouting priority srcnat; policy accept;
oifname != "docker0" ip saddr 172.17.0.0/16 counter packets 34 bytes 2188 masquerade
meta l4proto tcp ip saddr 172.17.0.2 ip daddr 172.17.0.2 tcp dport 443 counter packets 0 bytes 0 masquerade
meta l4proto tcp ip saddr 172.17.0.2 ip daddr 172.17.0.2 tcp dport 80 counter packets 0 bytes 0 masquerade
}
chain PREROUTING {
type nat hook prerouting priority dstnat; policy accept;
fib daddr type local counter packets 11439 bytes 550595 jump DOCKER
}
chain OUTPUT {
type nat hook output priority -100; policy accept;
ip daddr != 127.0.0.0/8 fib daddr type local counter packets 0 bytes 0 jump DOCKER
}
}
table ip filter {
chain DOCKER {
iifname != "docker0" oifname "docker0" meta l4proto tcp ip daddr 172.17.0.2 tcp dport 443 counter packets 155 bytes 7070 accept
iifname != "docker0" oifname "docker0" meta l4proto tcp ip daddr 172.17.0.2 tcp dport 80 counter packets 128 bytes 6263 accept
}
chain DOCKER-ISOLATION-STAGE-1 {
iifname "docker0" oifname != "docker0" counter packets 588 bytes 44199 jump DOCKER-ISOLATION-STAGE-2
counter packets 1187 bytes 428425 return
}
chain DOCKER-ISOLATION-STAGE-2 {
oifname "docker0" counter packets 0 bytes 0 drop
counter packets 588 bytes 44199 return
}
chain FORWARD {
type filter hook forward priority filter; policy drop;
counter packets 1187 bytes 428425 jump DOCKER-USER
counter packets 1187 bytes 428425 jump DOCKER-ISOLATION-STAGE-1
oifname "docker0" ct state related,established counter packets 316 bytes 370893 accept
oifname "docker0" counter packets 283 bytes 13333 jump DOCKER
iifname "docker0" oifname != "docker0" counter packets 588 bytes 44199 accept
iifname "docker0" oifname "docker0" counter packets 0 bytes 0 accept
}
chain DOCKER-USER {
counter packets 1187 bytes 428425 return
}
chain INPUT {
type filter hook input priority filter; policy accept;
}
}
Cheers