Skip to content

Commit

Permalink
Add a filter chain to allow persistent rules
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Jacob Wen committed May 15, 2017
1 parent 37e20af commit a60d046
Show file tree
Hide file tree
Showing 5 changed files with 83 additions and 42 deletions.
5 changes: 5 additions & 0 deletions controller.go
Original file line number Diff line number Diff line change
Expand Up @@ -813,6 +813,10 @@ func (c *controller) NewNetwork(networkType, name string, id string, options ...
}
}()

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

addToStore:
// First store the endpoint count, then the network. To avoid to
// end up with a datastore containing a network and not an epCnt,
Expand Down Expand Up @@ -841,6 +845,7 @@ addToStore:
if !c.isDistributedControl() {
c.Lock()
arrangeIngressFilterRule()
arrangeUserFilterRule()
c.Unlock()
}

Expand Down
44 changes: 2 additions & 42 deletions drivers/bridge/setup_ip_tables.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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},
Expand Down
29 changes: 29 additions & 0 deletions firewall_linux.go
Original file line number Diff line number Diff line change
@@ -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)
}
}
6 changes: 6 additions & 0 deletions firewall_others.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
// +build !linux

package libnetwork

func arrangeUserFilterRule() {
}
41 changes: 41 additions & 0 deletions iptables/iptables.go
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

0 comments on commit a60d046

Please sign in to comment.