From 0067b3a8ec73337c8df78dc733b17afba638f2fa Mon Sep 17 00:00:00 2001 From: Jacob Wen Date: Mon, 13 Mar 2017 15:46:46 +0800 Subject: [PATCH] Add a filter chain to allow persistent rules 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 docker/docker#29184 Fixes docker/docker#23987 Related to docker/docker#24848 Signed-off-by: Jacob Wen --- controller.go | 4 +++ drivers/bridge/setup_ip_tables.go | 44 ++----------------------------- firewall_linux.go | 29 ++++++++++++++++++++ firewall_others.go | 6 +++++ iptables/iptables.go | 41 ++++++++++++++++++++++++++++ 5 files changed, 82 insertions(+), 42 deletions(-) create mode 100644 firewall_linux.go create mode 100644 firewall_others.go diff --git a/controller.go b/controller.go index 159e40f646..eb0d9e4b20 100644 --- a/controller.go +++ b/controller.go @@ -844,6 +844,10 @@ addToStore: c.Unlock() } + c.Lock() + arrangeUserFilterRule() + c.Unlock() + return network, nil } diff --git a/drivers/bridge/setup_ip_tables.go b/drivers/bridge/setup_ip_tables.go index 839e16f8ff..769debcb80 100644 --- a/drivers/bridge/setup_ip_tables.go +++ b/drivers/bridge/setup_ip_tables.go @@ -53,7 +53,7 @@ func setupIPChains(config *configuration) (*iptables.ChainInfo, *iptables.ChainI return nil, nil, nil, fmt.Errorf("failed to create FILTER isolation chain: %v", err) } - if err := addReturnRule(IsolationChain); err != nil { + if err := iptables.AddReturnRule(IsolationChain); err != nil { return nil, nil, nil, err } @@ -117,7 +117,7 @@ func (n *bridgeNetwork) setupIPTables(config *networkConfiguration, i *bridgeInt } d.Lock() - err = ensureJumpRule("FORWARD", IsolationChain) + err = iptables.EnsureJumpRule("FORWARD", IsolationChain) d.Unlock() if err != nil { return err @@ -280,46 +280,6 @@ func setINC(iface1, iface2 string, enable bool) error { return nil } -func addReturnRule(chain string) error { - var ( - table = iptables.Filter - args = []string{"-j", "RETURN"} - ) - - if iptables.Exists(table, chain, args...) { - return nil - } - - err := iptables.RawCombinedOutput(append([]string{"-I", chain}, args...)...) - if err != nil { - return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) - } - - return nil -} - -// Ensure the jump rule is on top -func ensureJumpRule(fromChain, toChain string) error { - var ( - table = iptables.Filter - args = []string{"-j", toChain} - ) - - if iptables.Exists(table, fromChain, args...) { - err := iptables.RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) - if err != nil { - return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) - } - } - - err := iptables.RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) - if err != nil { - return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) - } - - return nil -} - func removeIPChains() { for _, chainInfo := range []iptables.ChainInfo{ {Name: DockerChain, Table: iptables.Nat}, diff --git a/firewall_linux.go b/firewall_linux.go new file mode 100644 index 0000000000..8c27c1dd25 --- /dev/null +++ b/firewall_linux.go @@ -0,0 +1,29 @@ +package libnetwork + +import ( + "github.com/Sirupsen/logrus" + "github.com/docker/libnetwork/iptables" +) + +const userChain = "DOCKER-USER" + +// This chain 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. +func arrangeUserFilterRule() { + _, err := iptables.NewChain(userChain, iptables.Filter, false) + if err != nil { + logrus.Warnf("Failed to create %s chain: %v", userChain, err) + return + } + + if err = iptables.AddReturnRule(userChain); err != nil { + logrus.Warnf("Failed to add the RETURN rule for %s: %v", userChain, err) + return + } + + err = iptables.EnsureJumpRule("FORWARD", userChain) + if err != nil { + logrus.Warnf("Failed to ensure the jump rule for %s: %v", userChain, err) + } +} diff --git a/firewall_others.go b/firewall_others.go new file mode 100644 index 0000000000..c41b3e049f --- /dev/null +++ b/firewall_others.go @@ -0,0 +1,6 @@ +// +build !linux + +package libnetwork + +func arrangeUserFilterRule() { +} diff --git a/iptables/iptables.go b/iptables/iptables.go index 818bcb5598..20edb9b5d6 100644 --- a/iptables/iptables.go +++ b/iptables/iptables.go @@ -498,3 +498,44 @@ func parseVersionNumbers(input string) (major, minor, micro int) { func supportsCOption(mj, mn, mc int) bool { return mj > 1 || (mj == 1 && (mn > 4 || (mn == 4 && mc >= 11))) } + +// AddReturnRule adds a return rule for the chain in the filter table +func AddReturnRule(chain string) error { + var ( + table = Filter + args = []string{"-j", "RETURN"} + ) + + if Exists(table, chain, args...) { + return nil + } + + err := RawCombinedOutput(append([]string{"-A", chain}, args...)...) + if err != nil { + return fmt.Errorf("unable to add return rule in %s chain: %s", chain, err.Error()) + } + + return nil +} + +// EnsureJumpRule ensures the jump rule is on top +func EnsureJumpRule(fromChain, toChain string) error { + var ( + table = Filter + args = []string{"-j", toChain} + ) + + if Exists(table, fromChain, args...) { + err := RawCombinedOutput(append([]string{"-D", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to remove jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + } + + err := RawCombinedOutput(append([]string{"-I", fromChain}, args...)...) + if err != nil { + return fmt.Errorf("unable to insert jump to %s rule in %s chain: %s", toChain, fromChain, err.Error()) + } + + return nil +}