I just tried out Docker. It is awesome but seems not work nicely with ufw. By default, docker will manipulate the iptables a little bit. The outcome is not a bug but not wha
I don't like the operational overhead required by the iptables: false flag in docker daemon. In fact, from what I see, and please correct me if I am wrong, all the solutions are way too complicated hacks.
Just insert this in /etc/ufw/after.rules, before the *filter section:
*mangle
# Allow a whitelisted ip to access postgres port
-I PREROUTING 1 -s <whitelisted_ip> -p tcp --dport 5432 -j ACCEPT
# Allow everyone to access port 8080
-I PREROUTING 2 -p tcp --dport 8080 -j ACCEPT
# Drop everything else
-I PREROUTING 3 -p tcp -j DROP
COMMIT
There is no need to mess with docker networking or with unnecessary hacks.
Not quite sure what your asking but from what I can gather you would like better control over who can access your apps running inside Docker? I have answered a similar question here to control traffic via a front end proxy rather than with IP tables Block external access to docker containers
Hope this helps
Dylan
With the above approach you can then use UFW to only allow incoming connections to port 80 (ie the proxy). This keeps any port exposure to a minimum with the added bonus that you can control traffic through a proxy configuration & DNS
I've had such problem like months ago and lately decided to describe the issue along with the solution on my blog. Here's the shortcut.
Using --iptables=false
won't help you much with the case you described. It's simply not enough here. By default, none of your containers can do any outgoing connection.
There's a small step you're omitting on your way to have containers behind UFW here. You can use --iptables=false
or create /etc/docker/daemon.json
file with content as follows
{
"iptables": false
}
the result will be the same, but the latter option requires you to restart whole docker service with service docker restart
or even do a reboot if docker had a chance to add iptables rules before you disabled this function.
When it's done, just do two more things:
$ sed -i -e 's/DEFAULT_FORWARD_POLICY="DROP"/DEFAULT_FORWARD_POLICY="ACCEPT"/g' /etc/default/ufw
$ ufw reload
so you set up default forward policy in UFW for accept, and use:
$ iptables -t nat -A POSTROUTING ! -o docker0 -s 172.17.0.0/16 -j MASQUERADE
That way what you're achieving is disabling docker messy behavior in your iptables rules and at the same time docker is provided with necessary routing so containers will do outgoing connections just fine. UFW rules will be still restricted from this point on, though.
Hope this resolves the issue for you and any that gets here in search of an answer.
I described the problem and solution more comprehensively at https://www.mkubaczyk.com/2017/09/05/force-docker-not-bypass-ufw-rules-ubuntu-16-04/
For what it's worth here's an addendum to @mkubaczyk's answer for the case where there are more bridge networks involved in the whole setup. These may be provided by Docker-Compose projects and here's how the proper rules can be generated, given that these projects are controlled by systemd
.
/etc/systemd/system/compose-project@.service
[Unit]
Description=Docker-Compose project: %I
After=docker.service
BindsTo=docker.service
AssertPathIsDirectory=/<projects_path>/%I
AssertFileNotEmpty=/<projects_path>/%I/docker-compose.yml
[Service]
Type=simple
Restart=always
WorkingDirectory=/<projects_path>/%I
ExecStartPre=/usr/bin/docker-compose up --no-start --remove-orphans
ExecStartPre=+/usr/local/bin/update-iptables-for-docker-bridges
ExecStart=/usr/bin/docker-compose up
ExecStop=/usr/bin/docker-compose stop --timeout 30
TimeoutStopSec=30
User=<…>
StandardOutput=null
[Install]
WantedBy=multi-user.target
/usr/local/bin/update-iptables-for-docker-bridges
#!/bin/sh
for network in $(docker network ls --filter 'driver=bridge' --quiet); do
iface=$(docker network inspect --format '{{index .Options "com.docker.network.bridge.name"}}' ${network})
[ -z $iface ] && iface="br-${network}"
subnet=$(docker network inspect --format '{{range .IPAM.Config}}{{.Subnet}}{{end}}' ${network})
rule="! --out-interface ${iface} --source ${subnet} --jump MASQUERADE"
iptables --table nat --check POSTROUTING ${rule} || iptables --table nat --append POSTROUTING ${rule}
done
Obviously, this won't scale that well.
It's also noteworthy that the whole basic concept will disguise the source of any connection for the applications running in a container.
I just made a little script that solves the ufw firewall and docker iptables issue. You can take a look at repo here. It's heavily based on chaifeng/ufw-docker's ufw rules, but automates the manual process. All you have to do is run the container with special label UFW_MANAGED=TRUE
. Please let me know your feedbacks. Of course code is crap, but hopefully it works.
Not saying solutions here are wrong, but they look a bit "terrifying" and error-prune for someone looking for a quick one-step instruction. I came with this problem recently as well, have read all the similar answers online, and have not found anything quick & clear at the time of writing. Surprisingly, my alternative solution is easy to comprehend and manage, and it works: just implement your firewall outside your host machine.
Treating Firewall as first-class citizen seems to have a lot of benefits.