Skip to content

Instantly share code, notes, and snippets.

@tomgidden
Last active August 4, 2017 11:07
Show Gist options
  • Save tomgidden/6c82bc0ff22a92c21b0ff1d97c89b903 to your computer and use it in GitHub Desktop.
Save tomgidden/6c82bc0ff22a92c21b0ff1d97c89b903 to your computer and use it in GitHub Desktop.
iptables firewall rules to stop Docker being quite so profligate on all interfaces.
# This is to get around what appears to be a colossal flaw in Docker (Swarm)
# at the time of writing.
#
# I'm no expert by any stretch, but I've googled all I can think of, and I
# can't see a way to get Docker to _NOT_ listen on all interfaces when
# exposing a port. As a result, a private unsecured service like
# "Gearman" or "Memcached" gets published to the outside world... there's
# the option of _either_ having it available only to the Docker swarm, or
# to publish it to the entire world; there's no option to have it publish
# to other network interfaces, eg. to our own webservers that are not in
# the cluster.
#
# I was hoping it would be possible to bind a particular `service` to a
# `network`, and have that network only listen on chosen interfaces rather
# than the default ingress network. I've tried, however, and it doesn't
# seem to work. What _IS_ the purpose of `networks:` in a swarm if not
# for this kind of thing?
#
# I just reckon that if Docker's going to be as presumptuous to mess with
# the firewall, it shouldn't do so in such a wide-open way. In my
# opinion, this is a very common use-case; most typical cloud servers
# from, say, Rackspace don't sit behind a hefty firewall and it's up to
# the sysadmin of that cloud server to protect it with `iptables`, `ufw`,
# etc. Docker bypasses all that. So, I'd think it should be a top-level
# command-line option to set the listen address for port publications;
# heck, even the poor man's NAT -- OpenSSH's port forwarding -- allows
# that!
#
# Now, I suppose we can set `--iptables=false` with the Docker daemon and
# stop Docker messing with the node's firewall, but that's a bit
# defeatist.
#
# Of course, I admit the possibility that this _IS_ possible, but as it's
# not documented, I can't really be blamed for thinking this.
#
# I'd _love_ to be educated to the contrary. Please, please, PLEASE let
# me know if there's a better way to do this.
#
# -- Tom Gidden <[email protected]>, 1 August 2017
#
# Refs: https://major.io/2010/07/26/adding-comments-to-iptables-rules/a
# https://docs.docker.com/engine/userguide/networking/#docker-and-iptables
# https://forums.docker.com/t/restricting-external-container-access-with-iptables/2225/3
# https://github.com/moby/moby/issues/26696
# https://serverfault.com/questions/843569/using-private-physical-networks-with-docker-swarm-mode
#
#
# To install:
#
# sudo -s
# curl -L https://gist.github.com/tomgidden/6c82bc0ff22a92c21b0ff1d97c89b903/raw/docker-blocker.service -o /etc/systemd/system/docker-blocker.service
# curl -L https://gist.github.com/tomgidden/6c82bc0ff22a92c21b0ff1d97c89b903/raw/iptables.docker-blocker.rules -o /etc/docker/iptables.docker-blocker.rules
# vi /etc/docker/iptables.docker-blocker.rules
# systemctl enable docker-blocker
# systemctl start docker-blocker
#
# That configuration will block all incoming traffic on the network
# interfaces `eth0` and `eth1` to Docker services. For our Rackspace
# servers, that should do the trick. You may need to alter this to taste.
#
# Also, when you _do_ want to publish a service, you'll have to add a line
# to `/etc/docker/iptables.docker-blocker.rules` above the other '-A's, like this:
#
# -A DOCKER-BLOCKER -i eth0 -p tcp -m tcp --dport 80 -j RETURN
#
# To activate or reactivate:
#
# sudo systemctl restart docker-blocker
[Unit]
Description=Docker-Blocker firewall rules
Documentation=https://gist.github.com/tomgidden/6c82bc0ff22a92c21b0ff1d97c89b903
Requires=docker.service
After=docker.service
[Service]
Type=oneshot
ExecStart=/sbin/iptables-restore -n /etc/docker/iptables.docker-blocker.rules
ExecReload=/sbin/iptables-restore -n /etc/docker/iptables.docker-blocker.rules
[Install]
WantedBy=multi-user.target
# Save this file to /etc/docker/iptables.docker-blocker.rules and
# customise to suit. See instructions in `/etc/systemd/system/docker-blocker.service`
# for more details.
#
# The default contents (ie. if you haven't edited this file already) should
# reject access to Docker service published ports via the `eth0` and `eth1`
# interfaces.
#
*filter
:DOCKER-BLOCKER - [0:0]
-I FORWARD 1 -j DOCKER-BLOCKER
# Allow established traffic. Should be okay. Otherwise things like DNS will break.
-A DOCKER-BLOCKER -m state --state ESTABLISHED,RELATED -j ACCEPT
# Add exceptions here...
# Add any interfaces here that you want blocked by default. Of course, you
# can customise these as much as you like.
-A DOCKER-BLOCKER -i eth0 -j REJECT -m comment --comment "/etc/systemd/system/docker-blocker.service"
-A DOCKER-BLOCKER -i eth1 -j REJECT -m comment --comment "/etc/systemd/system/docker-blocker.service"
# Return to normal service.
-A DOCKER-BLOCKER -j RETURN
COMMIT
@tomgidden
Copy link
Author

Just to reiterate and clarify, I hope that either this script will become unnecessary (obviated by Docker Services being able to specify rules) or someone tells me a better way to do it.

I'm a Docker novice. This script scratches an itch I haven't reached with the current documentation. If you know how this problem should be solved, please tell me!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment