From 94c8e62e8c7a452557c05cb23917e3b18f6099be Mon Sep 17 00:00:00 2001 From: Sotiris Nanopoulos Date: Tue, 21 Sep 2021 16:23:24 -0700 Subject: [PATCH] feat: Adds support for HNS L4WFPProxyPolicy Fixes #1002 Allow the cni plugin to marshall and apply L4WFPProxyPolicy to Windows endpoints. Tested on Kubernetes v1.19 with AKS-engine and docker/containerd runtime Signed-off-by: Sotiris Nanopoulos --- network/policy/policy.go | 1 + network/policy/policy_windows.go | 42 ++++++++++++++++++++++ network/policy/policy_windows_test.go | 50 +++++++++++++++++++++++++++ 3 files changed, 93 insertions(+) create mode 100644 network/policy/policy_windows_test.go diff --git a/network/policy/policy.go b/network/policy/policy.go index 4b645c866c..6a176c62c5 100644 --- a/network/policy/policy.go +++ b/network/policy/policy.go @@ -11,6 +11,7 @@ const ( RoutePolicy CNIPolicyType = "ROUTE" PortMappingPolicy CNIPolicyType = "NAT" ACLPolicy CNIPolicyType = "ACL" + L4WFPProxyPolicy CNIPolicyType = "L4WFPPROXY" ) type CNIPolicyType string diff --git a/network/policy/policy_windows.go b/network/policy/policy_windows.go index ca425dce63..4fe2830dec 100644 --- a/network/policy/policy_windows.go +++ b/network/policy/policy_windows.go @@ -37,6 +37,16 @@ type KVPairRoute struct { NeedEncap bool `json:"NeedEncap"` } +type KVPairL4WfpProxyPolicy struct { + Type CNIPolicyType `json:"Type"` + OutboundProxyPort string `json:"OutboundProxyPort"` + InboundProxyPort string `json:"InboundProxyPort"` + UserSID string `json:"UserSID"` + FilterTuple json.RawMessage `json:"FilterTuple"` + InboundExceptions json.RawMessage `json:"InboundExceptions"` + OutboundExceptions json.RawMessage `json:"OutboundExceptions"` +} + var ValidWinVerForDnsNat bool // SerializePolicies serializes policies to json. @@ -206,6 +216,14 @@ func GetPolicyType(policy Policy) CNIPolicyType { } } + // Check if the type is L4WFPProxy + var l4WfpProxyPolicy KVPairL4WfpProxyPolicy + if err := json.Unmarshal(policy.Data, &l4WfpProxyPolicy); err == nil { + if l4WfpProxyPolicy.Type == L4WFPProxyPolicy { + return L4WFPProxyPolicy + } + } + // Check if the type if Port mapping / NAT var dataPortMapping hcn.EndpointPolicy if err := json.Unmarshal(policy.Data, &dataPortMapping); err == nil { @@ -386,6 +404,28 @@ func GetHcnACLPolicy(policy Policy) (hcn.EndpointPolicy, error) { return aclEndpolicySetting, nil } +// GetHcnL4WFPProxyPolicy returns L4WFPProxy policy. +func GetHcnL4WFPProxyPolicy(policy Policy) (hcn.EndpointPolicy, error) { + l4WfpEndpolicySetting := hcn.EndpointPolicy{ + Type: hcn.L4WFPPROXY, + } + + // Check beforehand, the input meets the expected format + // otherwise, endpoint creation will fail later on. + var l4WfpProxyPolicySetting hcn.L4WfpProxyPolicySetting + if err := json.Unmarshal(policy.Data, &l4WfpProxyPolicySetting); err != nil { + return l4WfpEndpolicySetting, err + } + + l4WfpProxyPolicySettingBytes, err := json.Marshal(l4WfpProxyPolicySetting) + if err != nil { + return l4WfpEndpolicySetting, err + } + + l4WfpEndpolicySetting.Settings = l4WfpProxyPolicySettingBytes + return l4WfpEndpolicySetting, nil +} + // GetHcnEndpointPolicies returns array of all endpoint policies. func GetHcnEndpointPolicies(policyType CNIPolicyType, policies []Policy, epInfoData map[string]interface{}, enableSnatForDns, enableMultiTenancy bool) ([]hcn.EndpointPolicy, error) { var ( @@ -408,6 +448,8 @@ func GetHcnEndpointPolicies(policyType CNIPolicyType, policies []Policy, epInfoD endpointPolicy, err = GetHcnPortMappingPolicy(policy) case ACLPolicy: endpointPolicy, err = GetHcnACLPolicy(policy) + case L4WFPProxyPolicy: + endpointPolicy, err = GetHcnL4WFPProxyPolicy(policy) default: // return error as we should be able to parse all the policies specified return hcnEndPointPolicies, fmt.Errorf("Failed to set Policy: Type: %s, Data: %s", policy.Type, policy.Data) diff --git a/network/policy/policy_windows_test.go b/network/policy/policy_windows_test.go new file mode 100644 index 0000000000..95bbf06a94 --- /dev/null +++ b/network/policy/policy_windows_test.go @@ -0,0 +1,50 @@ +// Copyright 2021 Microsoft. All rights reserved. +// MIT License + +package policy + +import ( + "testing" + + . "github.com/onsi/ginkgo" + . "github.com/onsi/gomega" +) + +func TestEndpoint(t *testing.T) { + RegisterFailHandler(Fail) + RunSpecs(t, "Endpoint Suite") +} + +var _ = Describe("Windows Policies", func() { + Describe("Test GetHcnL4WFPProxyPolicy", func() { + It("Should raise error for invalid json", func() { + policy := Policy{ + Type: L4WFPProxyPolicy, + Data: []byte(`invalid json`), + } + + _, err := GetHcnL4WFPProxyPolicy(policy) + Expect(err).NotTo(BeNil()) + }) + + It("Should marshall the policy correctly", func() { + policy := Policy{ + Type: L4WFPProxyPolicy, + Data: []byte(`{ + "Type": "L4WFPPROXY", + "OutboundProxyPort": "15001", + "InboundProxyPort": "15003", + "UserSID": "S-1-5-32-556", + "FilterTuple": { + "Protocols": "6" + }}`), + } + + expected_policy := `{"InboundProxyPort":"15003","OutboundProxyPort":"15001","FilterTuple":{"Protocols":"6"},"UserSID":"S-1-5-32-556","InboundExceptions":{},"OutboundExceptions":{}}` + + generatedPolicy, err := GetHcnL4WFPProxyPolicy(policy) + Expect(err).To(BeNil()) + Expect(string(generatedPolicy.Settings)).To(Equal(expected_policy)) + }) + }) +})