ufw-docker
ufw-docker copied to clipboard
Use conntrack to allow incoming responses for outbound connections
To allow responses for outbound connections initiated by internal containers you suggest the following rules:
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p tcp -m tcp --tcp-flags FIN,SYN,RST,ACK SYN -d 172.16.0.0/12
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 192.168.0.0/16
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 10.0.0.0/8
-A DOCKER-USER -j DROP -p udp -m udp --dport 0:32767 -d 172.16.0.0/12
There are some flaws with this approach:
- TCP flags can be tampered (bypasses the firewall, destined application must handle tampered connections)
- UDP is generally allowed for all ports above the range 0:32767 (i.e. /proc/sys/net/ipv4/ip_local_port_range) -> causes #64 and causes problems for apps that choose a source port within the range 0:32767 (e.g. dnsmasq)
Albeit being a stateless approach it would be safer to use the conntrack table (stateful) to allow responses for established connections:
-A DOCKER-USER --ctstate RELATED,ESTABLISHED -j ACCEPT -d 192.168.0.0/16
-A DOCKER-USER --ctstate RELATED,ESTABLISHED -j ACCEPT -d 10.0.0.0/8
-A DOCKER-USER --ctstate RELATED,ESTABLISHED -j ACCEPT -d 172.16.0.0/12
Even UFW is using conntrack to allow incoming responses initiated by local applications (see /etc/ufw/before.rules):
# quickly process packets for which we already have a connection
-A ufw-before-input -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-output -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A ufw-before-forward -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
- Did you consider using conntrack state?
- If so, why did you not use it?
Hi @vodasams57
Thank you for your advice. It's helpful especially in handling UDP traffic. My original thought was to stop new connections from outside networks and can also defense against SYN Flood attacks. But you're right about the issues, especially with how we handle UDP.
If using conntrack
, I'm considering these new rules to block new connections by default:
-A DOCKER-USER --ctstate NEW -j DROP -d 192.168.0.0/16
-A DOCKER-USER --ctstate NEW -j DROP -d 10.0.0.0/8
-A DOCKER-USER --ctstate NEW -j DROP -d 172.16.0.0/12
What do you think about these rules?
Only one concern I have is about the original rules, which have been widely deployed and tested in various environments. It works in most of cases. So, I'm thinking to update the documentation to include both sets of rules. Let users to choose which one they want to use.
hi @chaifeng
thanks for your feedback.
What do you think about these rules?
I would prefer the following approach "allow rules first, block anything else".
# BEGIN UFW AND DOCKER
*filter
:ufw-user-forward - [0:0]
:ufw-docker-logging-deny - [0:0]
:DOCKER-USER - [0:0]
-A DOCKER-USER -j ufw-user-forward
# allow communication between containers
-A DOCKER-USER -j RETURN -s 10.0.0.0/8
-A DOCKER-USER -j RETURN -s 172.16.0.0/12
-A DOCKER-USER -j RETURN -s 192.168.0.0/16
# allow established connections (e.g. initiated by a container)
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN -d 10.0.0.0/8
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN -d 172.16.0.0/12
-A DOCKER-USER -m conntrack --ctstate RELATED,ESTABLISHED -j RETURN -d 192.168.0.0/16
# block anything else
-A DOCKER-USER -j ufw-docker-logging-deny
-A ufw-docker-logging-deny -m limit --limit 3/min --limit-burst 10 -j LOG --log-prefix "[UFW DOCKER BLOCK] "
-A ufw-docker-logging-deny -j DROP
COMMIT
# END UFW AND DOCKER
Only one concern I have is about the original rules, which have been widely deployed and tested in various environments.
I see your point. Nevertheless, in terms of security/firewalling it would make sense to default to the new rules. In addition, this approach makes the rules much more understandable and feels less hacky.
So, I'm thinking to update the documentation to include both sets of rules. Let users to choose which one they want to use.
Good point. I would add a deprecation mark for the old approach and highlight the drawbacks when using it.
hi @chaifeng
did you have time to have a look at my last comment?