Skip to content

Commit

Permalink
Enable IP forwarding for Linux mulititenancy (#386)
Browse files Browse the repository at this point in the history
* Enable ipforwarding, prevent ip spoofing and other security concern

* added ovssnat test to circleci

* fixed compiler error

* updated circleci image

* fixed circleci yaml

* updated circleci image

* fixed UT

* fixed UTs

* addressed review comments

* added comments

* addressed review comments

* fixed UT

* separating PRs - removing ip spoofing check changes

* added document for describing multitenancy fields

* fixed docs/cnimultitenancy.md

* removed a condition as it seems to be not working
  • Loading branch information
tamilmani1989 authored Aug 20, 2019
1 parent d7320a9 commit b027258
Show file tree
Hide file tree
Showing 7 changed files with 155 additions and 17 deletions.
5 changes: 3 additions & 2 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,10 @@ jobs:
# docker:
# - image: golang:1.12
machine:
image: circleci/classic:latest
image: ubuntu-1604:201903-01
steps:
- checkout
- run:
- run:
name: Setup-and-test
command: |
sudo -E env "PATH=$PATH" apt-get update
Expand All @@ -34,6 +34,7 @@ jobs:
sudo -E env "PATH=$PATH" go test ./netlink/ -coverprofile coverage-netlink.out
sudo -E env "PATH=$PATH" go test ./store/ -coverprofile coverage-store.out
sudo -E env "PATH=$PATH" go test ./telemetry/ -coverprofile coverage-telemetry.out
sudo -E env "PATH=$PATH" go test ./network/ovssnat/ -coverprofile coverage-ovssnat.out
sudo -E env "PATH=$PATH" go test ./cni/ipam/ -coverprofile coverage-ipam.out
sudo -E env "PATH=$PATH" go test ./cnm/network/ -coverprofile coverage-network.out
sudo -E env "PATH=$PATH" go test ./cns/ipamclient/ -coverprofile coverage-ipamclient.out
Expand Down
7 changes: 4 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,12 @@ COREFILES = \
$(wildcard network/*.go) \
$(wildcard telemetry/*.go) \
$(wildcard network/epcommon/*.go) \
$(wildcard network/ovsnfravnet/*.go) \
$(wildcard network/ovssnat/*.go) \
$(wildcard network/policy/*.go) \
$(wildcard platform/*.go) \
$(wildcard store/*.go)
$(wildcard store/*.go) \
$(wildcard ovsctl/*.go) \
$(wildcard network/ovssnat*.go) \
$(wildcard network/ovsinfravnet*.go)

# Source files for building CNM plugin.
CNMFILES = \
Expand Down
12 changes: 0 additions & 12 deletions cni/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -35,18 +35,6 @@ func NewPlugin(name, version string) (*Plugin, error) {
return nil, err
}

// Initialize logging.
log.SetName(plugin.Name)
log.SetLevel(log.LevelInfo)
err = log.SetTarget(log.TargetLogfile)
if err != nil {
log.Printf("[cni] Failed to configure logging, err:%v.\n", err)
return &Plugin{
Plugin: plugin,
version: version,
}, err
}

return &Plugin{
Plugin: plugin,
version: version,
Expand Down
16 changes: 16 additions & 0 deletions docs/cnimultitenancy.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Microsoft Azure Container Networking
CNI Multitenacy binaries are meant only for 1st party customers for now.

Conflist Fields Description
---------------------------
multiTenancy - To indicate CNI to use multitenancy network setup using ovs bridge. Thefollowing fields will be processed
only if this fields is set to true

enableExactMatchForPodName - If this set to false, then CNI strips the last two hex fields added by container runtime to locate the pod.
For Eg: In kubernetes, if pod name is samplepod, then container runtime generates this as samplepod-3e4a-5e4a.
CNI would strip 3e4a-5e4a and keep it as samplepod to locate the pod in CNS.
If the field is set to true, CNI would take whatever container runtime provides.

enableSnatOnHost - If pod/container wants outbound connectivity, this field should be set to true. Enabling this field also enables
ip forwarding kernel setting in container host and adds iptable rule to allow forward traffic from snat bridge.

27 changes: 27 additions & 0 deletions network/epcommon/endpoint_common.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"github.com/Azure/azure-container-networking/iptables"
"github.com/Azure/azure-container-networking/log"
"github.com/Azure/azure-container-networking/netlink"
"github.com/Azure/azure-container-networking/platform"
)

/*RFC For Private Address Space: https://tools.ietf.org/html/rfc1918
Expand All @@ -26,6 +27,10 @@ RFC for Link Local Addresses: https://tools.ietf.org/html/rfc3927
connected to the same physical (or logical) link.
*/

const (
enableIPForwardCmd = "sysctl -w net.ipv4.ip_forward=1"
)

func getPrivateIPSpace() []string {
privateIPAddresses := []string{"10.0.0.0/8", "172.16.0.0/12", "192.168.0.0/16", "169.254.0.0/16"}
return privateIPAddresses
Expand Down Expand Up @@ -167,3 +172,25 @@ func BlockIPAddresses(bridgeName string, action string) error {

return nil
}

/**
This fucntion enables ip forwarding in VM and allow forwarding packets from the interface
**/
func EnableIPForwarding(ifName string) error {
// Enable ip forwading on linux vm.
// sysctl -w net.ipv4.ip_forward=1
cmd := fmt.Sprintf(enableIPForwardCmd)
_, err := platform.ExecuteCommand(cmd)
if err != nil {
log.Printf("[net] Enable ipforwarding failed with: %v", err)
return err
}

// Append a rule in forward chain to allow forwarding from bridge
if err := iptables.AppendIptableRule(iptables.Filter, iptables.Forward, "", iptables.Accept); err != nil {
log.Printf("[net] Appending forward chain rule: allow traffic coming from snatbridge failed with: %v", err)
return err
}

return nil
}
5 changes: 5 additions & 0 deletions network/ovs_endpoint_snatroute_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package network
import (
"fmt"

"github.com/Azure/azure-container-networking/network/epcommon"
"github.com/Azure/azure-container-networking/network/ovssnat"
)

Expand Down Expand Up @@ -43,6 +44,10 @@ func AddSnatEndpointRules(client *OVSEndpointClient) error {
return err
}

if err := epcommon.EnableIPForwarding(ovssnat.SnatBridgeName); err != nil {
return err
}

if client.allowInboundFromHostToNC {
if err := client.snatClient.AllowInboundFromHostToNC(); err != nil {
return err
Expand Down
100 changes: 100 additions & 0 deletions network/ovssnat/ovssnat_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package ovssnat

import (
"os"
"testing"

"github.com/Azure/azure-container-networking/netlink"
)

var anyInterface = "dummy"

func TestMain(m *testing.M) {
exitCode := m.Run()

// Create a dummy test network interface.

os.Exit(exitCode)
}

func TestAllowInboundFromHostToNC(t *testing.T) {
client := &OVSSnatClient{
snatBridgeIP: "169.254.0.1/16",
localIP: "169.254.0.4/16",
containerSnatVethName: anyInterface,
}

if err := netlink.AddLink(&netlink.DummyLink{
LinkInfo: netlink.LinkInfo{
Type: netlink.LINK_TYPE_DUMMY,
Name: anyInterface,
},
}); err != nil {
t.Errorf("Error adding dummy interface %v", err)
}

if err := netlink.AddLink(&netlink.DummyLink{
LinkInfo: netlink.LinkInfo{
Type: netlink.LINK_TYPE_DUMMY,
Name: SnatBridgeName,
},
}); err != nil {
t.Errorf("Error adding dummy interface %v", err)
}

if err := client.AllowInboundFromHostToNC(); err != nil {
t.Errorf("Error adding inbound rule: %v", err)
}

if err := client.AllowInboundFromHostToNC(); err != nil {
t.Errorf("Error adding existing inbound rule: %v", err)
}

if err := client.DeleteInboundFromHostToNC(); err != nil {
t.Errorf("Error removing inbound rule: %v", err)
}

netlink.DeleteLink(anyInterface)
netlink.DeleteLink(SnatBridgeName)
}

func TestAllowInboundFromNCToHost(t *testing.T) {
client := &OVSSnatClient{
snatBridgeIP: "169.254.0.1/16",
localIP: "169.254.0.4/16",
containerSnatVethName: anyInterface,
}

if err := netlink.AddLink(&netlink.DummyLink{
LinkInfo: netlink.LinkInfo{
Type: netlink.LINK_TYPE_DUMMY,
Name: anyInterface,
},
}); err != nil {
t.Errorf("Error adding dummy interface %v", err)
}

if err := netlink.AddLink(&netlink.DummyLink{
LinkInfo: netlink.LinkInfo{
Type: netlink.LINK_TYPE_DUMMY,
Name: SnatBridgeName,
},
}); err != nil {
t.Errorf("Error adding dummy interface %v", err)
}

if err := client.AllowInboundFromNCToHost(); err != nil {
t.Errorf("Error adding inbound rule: %v", err)
}

if err := client.AllowInboundFromNCToHost(); err != nil {
t.Errorf("Error adding existing inbound rule: %v", err)
}

if err := client.DeleteInboundFromNCToHost(); err != nil {
t.Errorf("Error removing inbound rule: %v", err)
}

netlink.DeleteLink(anyInterface)
netlink.DeleteLink(SnatBridgeName)
}

0 comments on commit b027258

Please sign in to comment.