docker-fw is a complementary tool for Docker to manage iptables-based custom firewall rules between/towards containers, persistence and two-ways links.
Branch: master
Clone or download
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
src
vendor/github.com
.gitignore Added git submodules for vendor'd depenencies Mar 1, 2016
.gitmodules Added git submodules for vendor'd depenencies Mar 1, 2016
LICENSE
Makefile Added git submodules for vendor'd depenencies Mar 1, 2016
README.md Better example, tested with Docker 1.10.2 Mar 1, 2016
example-iptables.txt Add comment about FORWARD default policy Aug 31, 2015

README.md

Docker-fw

docker-fw is a complementary tool for Docker to manage their iptables firewall rules; it features persistence of rules and dynamic port assignments, in case host or container are restarted.

docker-fw expects your firewall to be using the *filter FORWARD chain with a default policy of REJECT/DROP (or an equivalent rule at bottom); this is default behavior starting from Docker version 1.5.

docker-fw does not work with Docker daemon --restart options because docker-fw would not be called automatically on container start. However, you can customize initialization of containers on host boot script via /etc/rc.local, for example to loop through existing containers and initialize their firewall rules using docker-fw start.

It is also possible to use this utility completely manage your internal docker0 bridge traffic between containers, as it will play nicely along with --icc=false and --iptables=true Docker daemon options.

Willing to contribute? Please submit a pull request or create an issue.

Iptables workflow explanation

This is how docker-fw expects network flow to happen (e.g. iptables explained in human terms) under a strict whitelisting firewall:

  1. no link between FORWARD and DOCKER chains for all traffic from any source (rule FORWARD -o docker0 -j DOCKER added by Docker and removed by docker-fw init)
  2. all internal traffic on FORWARD chain is linked to DOCKER chain (FORWARD -i docker0 -o docker0 -j DOCKER as 1st rule)
  3. existing connections keep being forwarded (rule FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT added by Docker is not touched)
  4. outgoing connections from all containers are kept being forwarded (FORWARD -i docker0 ! -o docker0 -j ACCEPT added by Docker is not touched)
  5. a DROP rule is appeneded on FORWARD table as exiting rule
  6. custom firewall rules are added before such DROP rule (usually with an insert) and/or to the DOCKER chain itself

See also example-iptables.txt.

License

Author is not officially involved with Docker development, thus this is not an official tool either.

docker-fw is licensed under GNU GPL version 2, see LICENSE.

Building

Running the make command should suffice. The Makefile will use a locally-generated GOPATH without populating it with any package; all source code dependencies are submodules under vendor/.

Actions

Init

Removes the iptables rule added by docker daemon at startup -o docker0 -j DOCKER from *filter FORWARD chain. It will fail if docker daemon is not running or if rule does not exist.

docker-fw init

Add actions

'add' is used to add a firewall specification for a container (any network external to Docker circuit, e.g. 192.168.178.0/24 or a public internet address) and targets the FORWARD chain, while 'add-internal'/'add-two-ways' target the INPUT chain. If a valid container id/name is specified, then its IPv4 will be always aliased by docker-fw. Some special values exist for address specification:

  • . to reference the container for which rules are being added
  • / to reference the Docker host (usually 172.17.42.1)

NOTE: referencing the Docker host / is mostly intended for the 'add-internal' action; since it is considered a poor practice to create firewall rules to allow traffic that target the docker host

docker-fw add container-id --source=(1.2.3.4|.|container-id) [--rev-lookup] [--sport=xxxx] [--dest=(1.2.3.4|.|container-id)] [--dport=xxxx] [--protocol=(tcp|udp)] [--filter="-i docker0 -o docker0"]
docker-fw (add-internal|add-two-ways) container-id --source=(1.2.3.4|.|container-id|/) [--rev-lookup] [--sport=xxxx] --dest=(1.2.3.4|.|container-id|/) --dport=xxxx [--protocol=(tcp|udp)] [--filter="-i docker0 -o docker0"]

Some rules to use 'add', 'add-two-ways', 'add-internal' and 'add-input':

  • address specifications (source/destination) can also be in IPv4 subnet notation
  • specifying --dport is mandatory for 'add-internal' action.
  • protocol default is 'tcp'.
  • at least source or destination must be equivalent to '.' (container for which rule is being specified), but cannot be both. If no destination is specified, '.' is assumed.
  • specification of extra iptables filter is optional, and empty by default
  • using --rev-lookup allows to specify a container IPv4 address, that otherwise would be an error (name/id form is preferred)

'add-two-ways' requires that source is a container and performs two tasks:

  • execute add-internal with the specified rule
  • always make sure that the source container will have a /etc/hosts rule for the source container
  • the internal rules and the custom hosts will be restored when using docker-fw start for the container

These commands can also parse and add multiple rules from a file or stdin (using '-' as filename):

docker-fw add --from=(filename|-)
docker-fw add-internal --from=(filename|-)
docker-fw add-input --from=(filename|-)

When using --from, any other parameter (except --rev-lookup) is disallowed.

Two-ways linking

An example of how to apply two-ways linking (assumes --icc=false on your Docker daemon):

export IMAGE=ubuntu
docker run --detach --name=promoted $IMAGE sleep 1000
docker run --detach --expose=1025 --link promoted:promoted --name=endpoint $IMAGE sleep 1000

## enable iptables + hosts via docker-fw
docker-fw add-two-ways endpoint --source promoted --dport 1025

## test (it's advised to use 2 terminals for these commands)
docker exec endpoint nc -l 1025 &

docker exec promoted sh -c "echo 'Hello from promoted container' | nc endpoint 1025"

Save-hostconfig

Save host configuration of a running and correctly network-enabled container. Such configuration will be used when starting the container through docker-fw. It always happens by default after a successful start.

See also https://github.com/docker/docker/issues/8723

docker-fw save-hostconfig container1 [container2] [container3] [...] [containerN]

Replay

Replay all firewall rules; will not add them again if existing on current iptables and will update the IPv4 addresses referenced in source/destination by looking up the aliases (if any specified). Use --dry-run to display which stateful changes would be applied, and report exit code zero only if there would be none.

docker-fw replay [--dry-run] container1 [container2] [container3] [...] [containerN]

Ls

List all existing firewall rules for specified container(s); if no container is specified, all containers' rules will be displayed.

docker-fw ls [container1] [container2] [container3] [...] [containerN]

Drop

Drop all firewall rules for specified container; iptables rules are deleted and the json file that contains them is deleted from the container directory.

docker-fw drop container1 [container2] [container3] [...] [containerN]

Allow

Allow specified source address (external) as an 'add' command for each of the available published ports of the container.

docker-fw allow container-id ip-address-1 [ip-address-2] [ip-address-3] [...] [ip-address-N]

This command is explicitly meant to allow access from external networks to the container's network address.

Start

docker-fw start [--dry-run] [--paused] [--pull-deps] container1 [container2] [container3] [...] [containerN]

It does the following:

  • sort input list of containers second their dependencies
  • start each of them sequentially (paused when --paused is specified)
  • execute the equivalent of 'replay' action for each container as it is started

The option --paused allows to start containers in paused status (for example in case user doesn't want to allow any activity until all firewall restore operations are completed). The option --pull-deps will automatically make dependant (by link relationship) containers part of the selection. If a container is already started or paused, its state is not changed. By specifying --dry-run containers will be displayed in the order they would be started, but their state will not be changed.

Dependencies

Please note that Docker currently (1.8) lacks a correct dependency DAG when starting containers, thus it does not start them in correct order (unless you use --restart=true has a hack); unfortunately, nothing is mentioned in documentation there regarding this issue, which is solved as explained above by docker-fw start action (even if you don't use any of the other docker-fw features).

See also:

Internals

docker-fw uses Docker API through go-dockerclient, and command-line based iptables access; libiptc is not being used because its API is not published (and it would be a tad too complex, see also go-libiptc).

Container information is retrieved via API when needed and cached for the duration of the execution of docker-fw. Any id/name valid for the Docker API can be used with docker-fw.

Known issues

  • Has some hardcoded features/settings inherited from Docker defaults (e.g. 172.x.x.x subnet)
  • Not thoroughly tested, and no unit tests coverage
  • Stores its .json descriptors in Docker's own containers metadata directory

All of the above can be addressed with some effort, and probably will (in due time); as always, patches welcome!

Troubleshooting

If you see an error like this when running docker-fw init:

2015/01/24 21:01:20 init: Could not find docker-added rule

You have two issues:

  • you didn't RTFM :)
  • you are using Docker older than version 1.5 (it didn't have this PR merged in its codebase)