firewall: support ingressPolicy=(open|same-bridge) for isolating bridges as in Docker

This commit adds a new parameter `ingressPolicy` (`string`) to the `firewall` plugin.
The supported values are `open` and `same-bridge`.

- `open` is the default and does NOP.

- `same-bridge` creates "CNI-ISOLATION-STAGE-1" and "CNI-ISOLATION-STAGE-2"
that are similar to Docker libnetwork's "DOCKER-ISOLATION-STAGE-1" and
"DOCKER-ISOLATION-STAGE-2" rules.

e.g., when `ns1` and `ns2` are connected to bridge `cni1`, and `ns3` is
connected to bridge `cni2`, the `same-bridge` ingress policy disallows
communications between `ns1` and `ns3`, while allowing communications
between `ns1` and `ns2`.

Please refer to the comment lines in `ingresspolicy.go` for the actual iptables rules.

The `same-bridge` ingress policy is expected to be used in conjunction
with `bridge` plugin. May not work as expected with other "main" plugins.

It should be also noted that the `same-bridge` ingress policy executes
raw `iptables` commands directly, even when the `backend` is set to `firewalld`.
We could potentially use the "direct" API of firewalld [1] to execute
iptables via firewalld, but it doesn't seem to have a clear benefit over just directly
executing raw iptables commands.
(Anyway, we have been already executing raw iptables commands in the `portmap` plugin)

[1] https://firewalld.org/documentation/direct/options.html

This commit replaces the `isolation` plugin proposal (issue 573, PR 574).
The design of `ingressPolicy` was discussed in the comments of the withdrawn PR 574 ,
but `same-network` was renamed to `same-bridge` then.

Signed-off-by: Akihiro Suda <akihiro.suda.cz@hco.ntt.co.jp>
This commit is contained in:
Akihiro Suda
2021-02-15 14:47:37 +09:00
parent f531419b53
commit 22dd6c553d
5 changed files with 425 additions and 20 deletions

View File

@ -44,7 +44,7 @@ func (c *chain) setup(ipt *iptables.IPTables) error {
// Add the rules to the chain
for _, rule := range c.rules {
if err := insertUnique(ipt, c.table, c.name, false, rule); err != nil {
if err := utils.InsertUnique(ipt, c.table, c.name, false, rule); err != nil {
return err
}
}
@ -55,7 +55,7 @@ func (c *chain) setup(ipt *iptables.IPTables) error {
r := []string{}
r = append(r, rule...)
r = append(r, "-j", c.name)
if err := insertUnique(ipt, c.table, entryChain, c.prependEntry, r); err != nil {
if err := utils.InsertUnique(ipt, c.table, entryChain, c.prependEntry, r); err != nil {
return err
}
}
@ -101,24 +101,6 @@ func (c *chain) teardown(ipt *iptables.IPTables) error {
return utils.DeleteChain(ipt, c.table, c.name)
}
// insertUnique will add a rule to a chain if it does not already exist.
// By default the rule is appended, unless prepend is true.
func insertUnique(ipt *iptables.IPTables, table, chain string, prepend bool, rule []string) error {
exists, err := ipt.Exists(table, chain, rule...)
if err != nil {
return err
}
if exists {
return nil
}
if prepend {
return ipt.Insert(table, chain, 1, rule...)
} else {
return ipt.Append(table, chain, rule...)
}
}
// check the chain.
func (c *chain) check(ipt *iptables.IPTables) error {