Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add a filter chain to allow persistent rules #1675

Merged
merged 1 commit into from
May 17, 2017

Conversation

wenjianhn
Copy link
Contributor

Allow users to configure firewall policies in way that persists
docker operations/restarts. Docker will not delete or modify any
pre-existing rules from the DOCKER-FORWARD-TOP filter chain. This
allows the user to create in advance any rules required to further
restrict access from/to the containers.

Fixes moby/moby/issues/29184
Fixes moby/moby/issues/23987
Related to moby/moby/issues/24848

Signed-off-by: Jacob Wen jian.w.wen@oracle.com

@@ -13,6 +13,7 @@ import (
const (
DockerChain = "DOCKER"
IsolationChain = "DOCKER-ISOLATION"
fwdTopChain = "DOCKER-FORWARD-TOP"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I would call this DOCKER-USER to specify it is left to the user to manage.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1.

In service_linux.go:
// In the filter table FORWARD chain first rule should be to jump to INGRESS-CHAIN

@aboch
Copy link
Contributor

aboch commented Mar 8, 2017

Thanks @wenjianhn for the change.

I think the new DOCKE-USER chain, not being driver specific, should be installed by the libnetwork core and not bridge driver. Can you please move the logic into controller.go at the end of New() after the network drivers initialization is done.
Feel free to make ensureJumpRule and addReturnRule methods of the iptables pkg.

@wenjianhn
Copy link
Contributor Author

@aboch Looks like we also need to use APPEND instead of INSERT when add rules in the drivers.
Otherwise, "-A FORWARD -j DOCKER-USER" will be in the bottom.

https://github.com/wenjianhn/libnetwork/tree/draft/docker-user-chain
Rules created by the above patch:

# Generated by iptables-save v1.4.21 on Thu Mar  9 09:57:38 2017
*filter
:INPUT ACCEPT [0:0]
:FORWARD ACCEPT [0:0]
:OUTPUT ACCEPT [0:0]
:DOCKER - [0:0]
:DOCKER-ISOLATION - [0:0]
:DOCKER-USER - [0:0]
-A FORWARD -j DOCKER-ISOLATION
-A FORWARD -o docker0 -j DOCKER
-A FORWARD -o docker0 -m conntrack --ctstate RELATED,ESTABLISHED -j ACCEPT
-A FORWARD -i docker0 ! -o docker0 -j ACCEPT
-A FORWARD -i docker0 -o docker0 -j ACCEPT
-A FORWARD -j DOCKER-USER
-A DOCKER-ISOLATION -j RETURN
-A DOCKER-USER -j RETURN
COMMIT
# Completed on Thu Mar  9 09:57:38 2017

@aboch
Copy link
Contributor

aboch commented Mar 10, 2017

For that, you would call in iptables.EnsureJumpRule("FORWARD", dockerUserChain) in controller.go after the call to c.addNetwork(network)

@wenjianhn
Copy link
Contributor Author

@aboch The CI failed. It doesn't seem to be related to my changes.
Could you rebuild it?

@aboch
Copy link
Contributor

aboch commented Mar 13, 2017

@wenjianhn

test -z "$(golint ./... | grep -Ev 'vendor|.pb.go:' | tee /dev/stderr)"
iptables/iptables.go:469:1: exported function AddReturnRule should have comment or be unexported
iptables/iptables.go:487:1: comment on exported function EnsureJumpRule should be of the form "EnsureJumpRule ..."

those are the reason for the failure. Please add the comments.

return nil
}

err := RawCombinedOutput(append([]string{"-I", chain}, args...)...)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Logically this should be a "-A", the return rule is anyway expected to appear at the end of the chain.
The original function was coded with the notion it would be used right after chain creation, as it was a bridge private function.
Now that the function is a public method, we should not assume anything like that.

I know this is from the existing code.
But given we are touching it now, I think it is the right time to fix this.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch.

service_linux.go Outdated

err = iptables.EnsureJumpRule("FORWARD", userChain)
if err != nil {
logrus.Warnf("Failed to create the jump rule for %s: %v", userChain, err)
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Failed to ensure the jump rule to %s: %v...

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

service_linux.go Outdated
@@ -260,6 +260,7 @@ func (sb *sandbox) rmLBBackend(ip, vip net.IP, fwMark uint32, ingressPorts []*Po
}
}

const userChain = "DOCKER-USER"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's keep this file for service related things only.
Please move this const and the arrangeUserFilterRule() function to controller.go or network.go

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done. Moved it to controller.go.

@aboch
Copy link
Contributor

aboch commented Mar 13, 2017

Thanks @wenjianhn
Also please invoke arrangeUserFilterRule() at https://github.com/docker/libnetwork/blob/master/controller.go#L746 after the calling arrangeUserFilterRule()

@aboch
Copy link
Contributor

aboch commented Mar 14, 2017

Thanks @wenjianhn

LGTM

@aboch
Copy link
Contributor

aboch commented Apr 28, 2017

Please rebase

@wenjianhn
Copy link
Contributor Author

@aboch The test fail. It doesn't seem to be related to my changes.

go build -o "bin/dnet-$GOOS-$GOARCH" ./cmd/dnet
# github.com/docker/libnetwork/vendor/github.com/vishvananda/netns
vendor/github.com/vishvananda/netns/netns.go:27: undefined: syscall.Stat_t
vendor/github.com/vishvananda/netns/netns.go:28: undefined: syscall.Fstat
vendor/github.com/vishvananda/netns/netns.go:31: undefined: syscall.Fstat
vendor/github.com/vishvananda/netns/netns.go:39: undefined: syscall.Stat_t
vendor/github.com/vishvananda/netns/netns.go:43: undefined: syscall.Fstat
vendor/github.com/vishvananda/netns/netns.go:57: cannot use int(*ns) (type int) as type syscall.Handle in argument to syscall.Close
Makefile:53: recipe for target 'cross-local' failed
make: *** [cross-local] Error 2
make: *** [circle-ci-cross] Error 2
make circle-ci returned exit code 2

@aboch
Copy link
Contributor

aboch commented May 2, 2017

Yes, weird cross-compilation issue. No changes in that vendoring.
I will rebuild the ci.

@stowns
Copy link

stowns commented May 12, 2017

Any updates on this issue? We're currently having to use a custom shell script for starting/restarting docker stacks to solve this problem.

@aboch
Copy link
Contributor

aboch commented May 12, 2017

@wenjianhn Please move the current definition of arrangeFilterRules into a linux specific file and add stubs for it for non linux platforms

controller.go Outdated
@@ -841,6 +845,7 @@ addToStore:
if !c.isDistributedControl() {
c.Lock()
arrangeIngressFilterRule()
arrangeUserFilterRule()
c.Unlock()
}

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Instead of calling arrangeUserFilterRule two times can you move it after the if !c.isDistributedControl() { block ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch. Thanks.

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@wenjianhn arrangeIngressFilterRule() is done inside the !c.isDistributedControl() because it applies only in the swarm mode. But the user chain is needed in non-swarm mode as well. Can you add this after the if !c.isDistributedControl() block

 		c.Lock()
 		arrangeUserFilterRule()
  		c.Unlock()

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@sanimej CircleCI timed out. Could you rebuild it?

@sanimej
Copy link

sanimej commented May 15, 2017

@wenjianhn This needs another rebase and couple of minor comments to be addressed. Can you please take care of that and we can merge it in time for 17.06. Sorry about the delay in the review.

@wenjianhn
Copy link
Contributor Author

@sanimej Sure thing.

Allow users to configure firewall policies in a way that persists
docker operations/restarts. Docker will not delete or modify any
pre-existing rules from the DOCKER-USER filter chain. This allows
the user to create in advance any rules required to further
restrict access from/to the containers.

Fixes moby/moby#29184
Fixes moby/moby#23987
Related to moby/moby#24848

Signed-off-by: Jacob Wen <jian.w.wen@oracle.com>
@sanimej
Copy link

sanimej commented May 17, 2017

Thanks @wenjianhn. LGTM

@thaJeztah
Copy link
Member

@sanimej will this be in a vendor bump for 17.06?

@peterthomassen
Copy link

Thanks a lot for making this happen!

From the code comments, I gather that one has to add rules to the DOCKER-USER chain if they should be persistent.

  • Is that correct?
  • Is there already documentation for this? (I could not find any.)

@sanimej
Copy link

sanimej commented May 17, 2017

@thaJeztah We will do a vendor in later in the day.

@peterthomassen Yes, any custom rules you want to run before the docker added rules should be in the DOCKER-USER chain. This will be included in the 17.06 release notes/documentation.

@mavenugo
Copy link
Contributor

@sanimej I have asked @aboch to take care of the vendoring with an existing open moby PR.

@thaJeztah
Copy link
Member

ping @mstanleyjones this was included in docker 17.06 (through commit moby/moby@46392f2, which is part of moby/moby#32981), however, because it was part of another "changelog" issue, probably may not have been clear as a separate feature.

Given that this is a much-requested feature, we should include this somewhere in the documentation

paigehargrave pushed a commit to docker/docs that referenced this pull request Feb 26, 2019
Extra information:

$ docker run -d -p 7777:6379 --name data1 redis
$ docker run -d -p 8888:6379 --name data2 redis
$ sudo iptables -N DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER-redis1 -s 192.168.56.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis1 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -N DOCKER-USER-redis2
$ sudo iptables -A DOCKER-USER-redis2 -s 10.0.24.0/24 -p tcp -m tcp -j RETURN
$ sudo iptables -A DOCKER-USER-redis2 -j REJECT --reject-with icmp-port-unreachable
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 7777 -j DOCKER-USER-redis1
$ sudo iptables -A DOCKER-USER -i eth0 -p tcp -m conntrack --ctorigdstport 8888 -j DOCKER-USER-redis2

"I think an example like this belongs in the docs as it probably covers what 99% of users are looking for: the ability to expose ports using `-p` but still be able to control traffic to them using common filters like `-s`."


Note that --ctorigdstport matches the original destination port of the first packet of the connection, not the packet being filtered. So the dropping rule will also drop responses to the outgoing connections from Docker to the world on 5000-9999! Add --ctdir ORIGINAL to the DROP rule to match only incoming packets. See github.com/moby/moby/issues/22054#issuecomment-466663033

You can also specify which chains docker should use. For example, in the filter table, specify another chain instead of `FORWARD`. This allows you to use traditional tools to manage the firewall and decide when to pass control to docker.

Information pulled from:
moby/moby#33567
https://unrouted.io/2017/08/15/docker-firewall/
moby/libnetwork#1675
@azeemdin
Copy link

I have "iptables": false in /etc/docker/daemon.json. I am using docker swarm mode. But docker is adding DOCKER-INGRESS iptables rules. Is there any workaround to avoid this?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

docker does not respect previously setup FORWARD rules Docker should not update FORWARD chain on startup
8 participants