diff --git a/cni/network/invoker_cns.go b/cni/network/invoker_cns.go index 02e0ce7351..928096b361 100644 --- a/cni/network/invoker_cns.go +++ b/cni/network/invoker_cns.go @@ -15,6 +15,7 @@ import ( "github.com/Azure/azure-container-networking/iptables" "github.com/Azure/azure-container-networking/network" "github.com/Azure/azure-container-networking/network/networkutils" + "github.com/Azure/azure-container-networking/network/policy" cniSkel "github.com/containernetworking/cni/pkg/skel" "github.com/pkg/errors" "go.uber.org/zap" @@ -55,6 +56,7 @@ type IPResultInfo struct { skipDefaultRoutes bool routes []cns.Route pnpID string + endpointPolicies []policy.Policy } func (i IPResultInfo) MarshalLogObject(encoder zapcore.ObjectEncoder) error { @@ -159,6 +161,7 @@ func (invoker *CNSIPAMInvoker) Add(addConfig IPAMAddConfig) (IPAMAddResult, erro skipDefaultRoutes: response.PodIPInfo[i].SkipDefaultRoutes, routes: response.PodIPInfo[i].Routes, pnpID: response.PodIPInfo[i].PnPID, + endpointPolicies: response.PodIPInfo[i].EndpointPolicies, } logger.Info("Received info for pod", @@ -444,6 +447,7 @@ func configureDefaultAddResult(info *IPResultInfo, addConfig *IPAMAddConfig, add Gw: ncgw, }) } + // if we have multiple infra ip result infos, we effectively append routes and ip configs to that same interface info each time // the host subnet prefix (in ipv4 or ipv6) will always refer to the same interface regardless of which ip result info we look at addResult.interfaceInfo[key] = network.InterfaceInfo{ @@ -452,6 +456,7 @@ func configureDefaultAddResult(info *IPResultInfo, addConfig *IPAMAddConfig, add IPConfigs: ipConfigs, Routes: resRoute, HostSubnetPrefix: *hostIPNet, + EndpointPolicies: info.endpointPolicies, } } diff --git a/cni/network/invoker_cns_test.go b/cni/network/invoker_cns_test.go index c2d4963151..b8b6d9be98 100644 --- a/cni/network/invoker_cns_test.go +++ b/cni/network/invoker_cns_test.go @@ -12,6 +12,7 @@ import ( "github.com/Azure/azure-container-networking/cns" "github.com/Azure/azure-container-networking/iptables" "github.com/Azure/azure-container-networking/network" + "github.com/Azure/azure-container-networking/network/policy" cniSkel "github.com/containernetworking/cni/pkg/skel" "github.com/stretchr/testify/require" ) @@ -521,14 +522,38 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { hostSubnetPrefix *net.IPNet options map[string]interface{} } + valueOut := []byte(`{ + "Type": "ACL", + "Action": "Block", + "Direction": "Out", + "Priority": 10000 + }`) + valueIn := []byte(`{ + "Type": "ACL", + "Action": "Block", + "Direction": "In", + "Priority": 10000 + }`) + + expectedEndpointPolicies := []policy.Policy{ + { + Type: policy.EndpointPolicy, + Data: valueOut, + }, + { + Type: policy.EndpointPolicy, + Data: valueIn, + }, + } tests := []struct { - name string - fields fields - args args - wantDefaultResult network.InterfaceInfo - wantMultitenantResult network.InterfaceInfo - wantErr bool + name string + fields fields + args args + wantDefaultDenyEndpoints bool + wantDefaultResult network.InterfaceInfo + wantMultitenantResult network.InterfaceInfo + wantErr bool }{ { name: "Test happy CNI add", @@ -559,7 +584,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { PrimaryIP: "10.0.0.1", Subnet: "10.0.0.0/24", }, - NICType: cns.InfraNIC, + NICType: cns.InfraNIC, + EndpointPolicies: expectedEndpointPolicies, }, }, Response: cns.Response{ @@ -588,6 +614,7 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { Gateway: net.ParseIP("10.0.0.1"), }, }, + EndpointPolicies: expectedEndpointPolicies, Routes: []network.RouteInfo{ { Dst: network.Ipv4DefaultRouteDstPrefix, @@ -597,7 +624,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { NICType: cns.InfraNIC, HostSubnetPrefix: *parseCIDR("10.0.0.0/24"), }, - wantErr: false, + wantDefaultDenyEndpoints: true, + wantErr: false, }, { name: "Test CNI add with pod ip info empty nictype", @@ -665,7 +693,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { NICType: cns.InfraNIC, HostSubnetPrefix: *parseCIDR("10.0.0.0/24"), }, - wantErr: false, + wantDefaultDenyEndpoints: false, + wantErr: false, }, { name: "Test happy CNI add for both ipv4 and ipv6", @@ -696,7 +725,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { PrimaryIP: "10.0.0.1", Subnet: "10.0.0.0/24", }, - NICType: cns.InfraNIC, + NICType: cns.InfraNIC, + EndpointPolicies: expectedEndpointPolicies, }, { PodIPConfig: cns.IPSubnet{ @@ -716,7 +746,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { PrimaryIP: "fe80::1234:5678:9abc", Subnet: "fd11:1234::/112", }, - NICType: cns.InfraNIC, + NICType: cns.InfraNIC, + EndpointPolicies: expectedEndpointPolicies, }, }, Response: cns.Response{ @@ -749,6 +780,7 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { Gateway: net.ParseIP("fe80::1234:5678:9abc"), }, }, + EndpointPolicies: expectedEndpointPolicies, Routes: []network.RouteInfo{ { Dst: network.Ipv4DefaultRouteDstPrefix, @@ -762,7 +794,8 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { NICType: cns.InfraNIC, HostSubnetPrefix: *parseCIDR("fd11:1234::/112"), }, - wantErr: false, + wantDefaultDenyEndpoints: true, + wantErr: false, }, { name: "fail to request IP addresses from cns", @@ -773,12 +806,24 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { require: require, requestIPs: requestIPsHandler{ ipconfigArgument: getTestIPConfigsRequest(), - result: nil, - err: errors.New("failed error from CNS"), //nolint "error for ut" + result: &cns.IPConfigsResponse{ + PodIPInfo: []cns.PodIpInfo{ + { + EndpointPolicies: expectedEndpointPolicies, + }, + }, + Response: cns.Response{ + ReturnCode: 0, + Message: "", + }, + }, + err: errors.New("failed error from CNS"), //nolint "error for ut" + }, }, }, - wantErr: true, + wantDefaultDenyEndpoints: false, + wantErr: true, }, } for _, tt := range tests { @@ -794,6 +839,7 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { } ipamAddResult, err := invoker.Add(IPAMAddConfig{nwCfg: tt.args.nwCfg, args: tt.args.args, options: tt.args.options}) if tt.wantErr { + require.Equalf([]policy.Policy(nil), ipamAddResult.interfaceInfo[string(cns.InfraNIC)].EndpointPolicies, "There was an error requesting IP addresses from cns") require.Error(err) } else { require.NoError(err) @@ -809,6 +855,11 @@ func TestCNSIPAMInvoker_Add(t *testing.T) { } if ifInfo.NICType == cns.InfraNIC { require.Equalf(tt.wantDefaultResult, ifInfo, "incorrect default response") + if tt.wantDefaultDenyEndpoints { + require.Equalf(expectedEndpointPolicies, ifInfo.EndpointPolicies, "Correct default deny ACL") + } else { + require.Equalf([]policy.Policy(nil), ifInfo.EndpointPolicies, "Correct default deny ACL") + } } } }) diff --git a/cni/network/network.go b/cni/network/network.go index 6b0635e1c7..b25d3de5de 100644 --- a/cni/network/network.go +++ b/cni/network/network.go @@ -833,6 +833,10 @@ func (plugin *NetPlugin) createEpInfo(opt *createEpInfoOpt) (*network.EndpointIn // create endpoint policies by appending to network policies // the value passed into NetworkPolicies should be unaffected since we reassign here opt.policies = append(opt.policies, endpointPolicies...) + + // appends endpoint policies specific to this interface + opt.policies = append(opt.policies, opt.ifInfo.EndpointPolicies...) + endpointInfo.EndpointPolicies = opt.policies // add even more endpoint policies epPolicies, err := getPoliciesFromRuntimeCfg(opt.nwCfg, opt.ipamAddResult.ipv6Enabled) // not specific to delegated or infra diff --git a/cni/network/network_windows_test.go b/cni/network/network_windows_test.go index 9da54a4ca4..ae640f6825 100644 --- a/cni/network/network_windows_test.go +++ b/cni/network/network_windows_test.go @@ -878,6 +878,12 @@ func GetTestCNSResponseSecondaryWindows(macAddress string) map[string]network.In SkipDefaultRoutes: true, NICType: cns.InfraNIC, HostSubnetPrefix: *getCIDRNotationForAddress("20.224.0.0/16"), + EndpointPolicies: []policy.Policy{ + { + Type: policy.EndpointPolicy, + Data: GetRawACLPolicy(), + }, + }, }, macAddress: { MacAddress: parsedMAC, @@ -895,6 +901,12 @@ func GetTestCNSResponseSecondaryWindows(macAddress string) map[string]network.In }, }, NICType: cns.NodeNetworkInterfaceFrontendNIC, + EndpointPolicies: []policy.Policy{ + { + Type: policy.EndpointPolicy, + Data: GetRawOutBoundNATPolicy(), + }, + }, }, } } @@ -1226,6 +1238,12 @@ func TestPluginWindowsAdd(t *testing.T) { Gateway: net.ParseIP("10.244.2.1"), }, }, + EndpointPolicies: []policy.Policy{ + { + Type: policy.EndpointPolicy, + Data: GetRawACLPolicy(), + }, + }, }, epIDRegex: `.*`, }, @@ -1269,6 +1287,12 @@ func TestPluginWindowsAdd(t *testing.T) { Gateway: net.ParseIP("10.241.0.1"), }, }, + EndpointPolicies: []policy.Policy{ + { + Type: policy.EndpointPolicy, + Data: GetRawOutBoundNATPolicy(), + }, + }, }, epIDRegex: `.*`, }, @@ -1326,6 +1350,8 @@ func TestPluginWindowsAdd(t *testing.T) { epInfo1.EndpointPolicies[0] = policy.Policy{ Type: policy.ACLPolicy, } + require.Len(t, epInfo1.EndpointPolicies, 1) + require.Len(t, epInfo2.EndpointPolicies, 1) require.NotEqual(t, epInfo1.EndpointPolicies, epInfo2.EndpointPolicies) } // ensure the network policy slices are separate entities when in separate endpoint infos diff --git a/network/endpoint.go b/network/endpoint.go index d06448d389..fab75d3186 100644 --- a/network/endpoint.go +++ b/network/endpoint.go @@ -138,6 +138,7 @@ type InterfaceInfo struct { HostSubnetPrefix net.IPNet // Move this field from ipamAddResult NCResponse *cns.GetNetworkContainerResponse PnPID string + EndpointPolicies []policy.Policy } type IPConfig struct {