From 70edd1250e3e415a2b6ff83d56fa1bc70a38aa14 Mon Sep 17 00:00:00 2001 From: Vikas Bhardwaj Date: Thu, 14 Jan 2021 10:30:34 -0800 Subject: [PATCH] Changes for tier acl policy Signed-off-by: Vikas Bhardwaj --- hcn/hcn.go | 9 ++ hcn/hcnendpoint_test.go | 54 +++++++++ hcn/hcnglobals.go | 3 + hcn/hcnpolicy.go | 23 ++++ hcn/hcnsupport.go | 2 + hcn/hcnsupport_test.go | 11 ++ hcn/hcnutils_test.go | 258 ++++++++++++++++++++++++++++++++++++++++ hcn/hnsv1_test.go | 1 + 8 files changed, 361 insertions(+) diff --git a/hcn/hcn.go b/hcn/hcn.go index 2760152f12..82fddee9f7 100644 --- a/hcn/hcn.go +++ b/hcn/hcn.go @@ -240,6 +240,15 @@ func VxlanPortSupported() error { return platformDoesNotSupportError("VXLAN port configuration") } +// TierAclPolicySupported returns an error if the HCN version does not support configuring the TierAcl. +func TierAclPolicySupported() error { + supported := GetSupportedFeatures() + if supported.TierAcl { + return nil + } + return platformDoesNotSupportError("TierAcl") +} + // RequestType are the different operations performed to settings. // Used to update the settings of Endpoint/Namespace objects. type RequestType string diff --git a/hcn/hcnendpoint_test.go b/hcn/hcnendpoint_test.go index 8f800c66fb..3086a4499b 100644 --- a/hcn/hcnendpoint_test.go +++ b/hcn/hcnendpoint_test.go @@ -309,3 +309,57 @@ func TestModifyEndpointSettings(t *testing.T) { t.Fatal(err) } } + +func TestApplyTierAclPolicyOnEndpoint(t *testing.T) { + network, err := HcnCreateTestL2BridgeNetwork() + if err != nil { + t.Fatal(err) + } + defer func() { + err = network.Delete() + if err != nil { + fmt.Printf("Failed deleting from defer routine network: %s-%s \n", network.Id, network.Name) + t.Fatal(err) + } + }() + + endpoint, err := HcnCreateTestEndpoint(network) + if err != nil { + t.Fatal(err) + } + defer func() { + err = endpoint.Delete() + if err != nil { + fmt.Printf("Failed deleting from defer routine endpoint: %s-%s \n", endpoint.Id, endpoint.Name) + t.Fatal(err) + } + }() + + endpointPolicyList, err := HcnCreateTierAcls() + if err != nil { + t.Fatal(err) + } + + jsonString, err := json.Marshal(*endpointPolicyList) + if err != nil { + t.Fatal(err) + } + + fmt.Printf("TierAcls JSON:\n%s \n", jsonString) + err = endpoint.ApplyPolicy(RequestTypeUpdate, *endpointPolicyList) + if err != nil { + t.Fatal(err) + } + + foundEndpoint, err := GetEndpointByName(endpoint.Name) + if err != nil { + t.Fatal(err) + } else { + fmt.Printf("Found endpoint: %s-%s \n", foundEndpoint.Id, foundEndpoint.Name) + } + + if len(foundEndpoint.Policies) == 0 { + t.Fatal("No Endpoint Policies found") + } + +} diff --git a/hcn/hcnglobals.go b/hcn/hcnglobals.go index a2195f57fc..42f1c17cd2 100644 --- a/hcn/hcnglobals.go +++ b/hcn/hcnglobals.go @@ -74,6 +74,9 @@ var ( //HNS 13.2 allows for L4WfpProxy Policy support L4WfpProxyPolicyVersion = VersionRanges{VersionRange{MinVersion: Version{Major: 13, Minor: 2}, MaxVersion: Version{Major: math.MaxInt32, Minor: math.MaxInt32}}} + + //HNS 14.0 allows for TierAcl Policy support + TierAclPolicyVersion = VersionRanges{VersionRange{MinVersion: Version{Major: 14, Minor: 0}, MaxVersion: Version{Major: math.MaxInt32, Minor: math.MaxInt32}}} ) // GetGlobals returns the global properties of the HCN Service. diff --git a/hcn/hcnpolicy.go b/hcn/hcnpolicy.go index c032d79490..a832ad1e07 100644 --- a/hcn/hcnpolicy.go +++ b/hcn/hcnpolicy.go @@ -23,6 +23,7 @@ const ( // Endpoint and Network have InterfaceConstraint and ProviderAddress NetworkProviderAddress EndpointPolicyType = "ProviderAddress" NetworkInterfaceConstraint EndpointPolicyType = "InterfaceConstraint" + TierAcl EndpointPolicyType = "TierAcl" ) // EndpointPolicy is a collection of Policy settings for an Endpoint. @@ -100,6 +101,8 @@ const ( ActionTypeAllow ActionType = "Allow" // Block traffic ActionTypeBlock ActionType = "Block" + // Pass traffic + ActionTypePass ActionType = "Pass" // In is traffic coming to the Endpoint DirectionTypeIn DirectionType = "In" @@ -289,3 +292,23 @@ type L4ProxyPolicySetting struct { Destination string OutboundNAT bool `json:",omitempty"` } + +// TierAclRule represents an ACL within TierAclPolicySetting +type TierAclRule struct { + Id string `json:",omitempty"` + Protocols string `json:",omitempty"` + TierAclRuleAction ActionType `json:","` + LocalAddresses string `json:",omitempty"` + RemoteAddresses string `json:",omitempty"` + LocalPorts string `json:",omitempty"` + RemotePorts string `json:",omitempty"` + Priority uint16 `json:",omitempty"` +} + +// TierAclPolicySetting represents a Tier containing ACLs +type TierAclPolicySetting struct { + Name string `json:","` + Direction DirectionType `json:","` + Order uint16 `json:""` + TierAclRules []TierAclRule `json:",omitempty"` +} diff --git a/hcn/hcnsupport.go b/hcn/hcnsupport.go index 1096aebde5..1d9fe762e9 100644 --- a/hcn/hcnsupport.go +++ b/hcn/hcnsupport.go @@ -19,6 +19,7 @@ type SupportedFeatures struct { VxlanPort bool `json:"VxlanPort"` L4Proxy bool `json:"L4Proxy"` // network policy that applies VFP rules to all endpoints on the network to redirect traffic L4WfpProxy bool `json:"L4WfpProxy"` // endpoint policy that applies WFP filters to redirect traffic to/from that endpoint + TierAcl bool `json:"TierAcl"` } // AclFeatures are the supported ACL possibilities. @@ -69,6 +70,7 @@ func GetSupportedFeatures() SupportedFeatures { features.VxlanPort = isFeatureSupported(globals.Version, VxlanPortVersion) features.L4Proxy = isFeatureSupported(globals.Version, L4ProxyPolicyVersion) features.L4WfpProxy = isFeatureSupported(globals.Version, L4WfpProxyPolicyVersion) + features.TierAcl = isFeatureSupported(globals.Version, TierAclPolicyVersion) return features } diff --git a/hcn/hcnsupport_test.go b/hcn/hcnsupport_test.go index 1d6f90dea2..412634af6e 100644 --- a/hcn/hcnsupport_test.go +++ b/hcn/hcnsupport_test.go @@ -149,6 +149,17 @@ func TestL4WfpProxyPolicySupport(t *testing.T) { } } +func TestTierAclPolicySupport(t *testing.T) { + supportedFeatures := GetSupportedFeatures() + err := TierAclPolicySupported() + if supportedFeatures.TierAcl && err != nil { + t.Fatal(err) + } + if !supportedFeatures.TierAcl && err == nil { + t.Fatal(err) + } +} + func TestIsFeatureSupported(t *testing.T) { // HNSVersion1803 testing (single range tests) if isFeatureSupported(Version{Major: 0, Minor: 0}, HNSVersion1803) { diff --git a/hcn/hcnutils_test.go b/hcn/hcnutils_test.go index c27b98c8fa..215a213531 100644 --- a/hcn/hcnutils_test.go +++ b/hcn/hcnutils_test.go @@ -335,3 +335,261 @@ func HcnCreateTestSdnRoute(endpoint *HostComputeEndpoint) (*HostComputeRoute, er return route.Create() } + +func HcnCreateTestL2BridgeNetwork() (*HostComputeNetwork, error) { + cleanup(BridgeTestNetworkName) + subnet := GetDefaultSubnet() + network := &HostComputeNetwork{ + Type: "L2Bridge", + Name: BridgeTestNetworkName, + MacPool: MacPool{ + Ranges: []MacRange{ + { + StartMacAddress: "00-15-5D-52-C0-00", + EndMacAddress: "00-15-5D-52-CF-FF", + }, + }, + }, + Ipams: []Ipam{ + { + Type: "Static", + Subnets: []Subnet{ + *subnet, + }, + }, + }, + Flags: EnableNonPersistent, + SchemaVersion: SchemaVersion{ + Major: 2, + Minor: 0, + }, + } + + return network.Create() + +} + +func HcnCreateTierAcls() (*PolicyEndpointRequest, error) { + + policy := make([]EndpointPolicy, 6) + + tiers := make([]TierAclPolicySetting, 6) + + //inbound rules + tiers[0] = TierAclPolicySetting{ + Name: "TierIn1", + Direction: DirectionTypeIn, + Order: 1001, + } + + tiers[0].TierAclRules = make([]TierAclRule, 2) + + tiers[0].TierAclRules[0] = TierAclRule{ + Id: "TierIn1Rule1", + Protocols: "6", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "192.168.100.0/24,10.0.0.21", + RemoteAddresses: "192.168.100.0/24,10.0.0.22", + LocalPorts: "80", + RemotePorts: "80", + Priority: 2001, + } + + tiers[0].TierAclRules[1] = TierAclRule{ + Id: "TierIn1Rule2", + TierAclRuleAction: ActionTypeBlock, + Priority: 2100, + } + + policy[0].Type = TierAcl + rawJSON, err := json.Marshal(tiers[0]) + if err != nil { + return nil, err + } + + policy[0].Settings = rawJSON + + tiers[1] = TierAclPolicySetting{ + Name: "TierIn2", + Direction: DirectionTypeIn, + Order: 1002, + } + + tiers[1].TierAclRules = make([]TierAclRule, 3) + + tiers[1].TierAclRules[0] = TierAclRule{ + Id: "TierIn2Rule1", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "192.168.100.0/24", + RemoteAddresses: "192.168.100.0/24", + Priority: 3000, + } + + tiers[1].TierAclRules[1] = TierAclRule{ + Id: "TierIn2Rule2", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "10.0.0.21", + RemoteAddresses: "10.0.0.21", + Priority: 3010, + } + + tiers[1].TierAclRules[2] = TierAclRule{ + Id: "TierIn2Rule3", + TierAclRuleAction: ActionTypeBlock, + Priority: 3100, + } + + policy[1].Type = TierAcl + rawJSON, err = json.Marshal(tiers[1]) + if err != nil { + return nil, err + } + + policy[1].Settings = rawJSON + + + tiers[2] = TierAclPolicySetting{ + Name: "TierIn3", + Direction: DirectionTypeIn, + Order: 1013, + } + + tiers[2].TierAclRules = make([]TierAclRule, 2) + + tiers[2].TierAclRules[0] = TierAclRule{ + Id: "TierIn3Rule1", + Protocols: "17", + TierAclRuleAction: ActionTypeAllow, + LocalPorts: "8080", + RemotePorts: "8080", + Priority: 3000, + } + + tiers[2].TierAclRules[1] = TierAclRule{ + Id: "TierIn3Rule2", + TierAclRuleAction: ActionTypeBlock, + Priority: 3010, + } + + policy[2].Type = TierAcl + rawJSON, err = json.Marshal(tiers[2]) + if err != nil { + return nil, err + } + + policy[2].Settings = rawJSON + + //outbound rules + tiers[3] = TierAclPolicySetting{ + Name: "TierOut1", + Direction: DirectionTypeOut, + Order: 1001, + } + + tiers[3].TierAclRules = make([]TierAclRule, 2) + + tiers[3].TierAclRules[0] = TierAclRule{ + Id: "TierOut1Rule1", + Protocols: "6", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "192.168.100.0/24,10.0.0.21", + RemoteAddresses: "192.168.100.0/24,10.0.0.22", + LocalPorts: "81", + RemotePorts: "81", + Priority: 2000, + } + + tiers[3].TierAclRules[1] = TierAclRule{ + Id: "TierOut1Rule2", + TierAclRuleAction: ActionTypeBlock, + Priority: 2100, + } + + policy[3].Type = TierAcl + rawJSON, err = json.Marshal(tiers[3]) + if err != nil { + return nil, err + } + + policy[3].Settings = rawJSON + + + tiers[4] = TierAclPolicySetting{ + Name: "TierOut2", + Direction: DirectionTypeOut, + Order: 1002, + } + + tiers[4].TierAclRules = make([]TierAclRule, 3) + + tiers[4].TierAclRules[0] = TierAclRule{ + Id: "TierOut2Rule1", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "192.168.100.0/24", + RemoteAddresses: "192.168.100.0/24", + Priority: 3000, + } + + tiers[4].TierAclRules[1] = TierAclRule{ + Id: "TierOut2Rule2", + Protocols: "6", + TierAclRuleAction: ActionTypePass, + LocalAddresses: "10.0.0.21", + RemoteAddresses: "10.0.0.21", + LocalPorts: "8082", + RemotePorts: "8082", + Priority: 3010, + } + + tiers[4].TierAclRules[2] = TierAclRule{ + Id: "TierOut2Rule3", + TierAclRuleAction: ActionTypeBlock, + Priority: 3100, + } + + policy[4].Type = TierAcl + rawJSON, err = json.Marshal(tiers[4]) + if err != nil { + return nil, err + } + + policy[4].Settings = rawJSON + + + tiers[5] = TierAclPolicySetting{ + Name: "TierOut3", + Direction: DirectionTypeOut, + Order: 1013, + } + + tiers[5].TierAclRules = make([]TierAclRule, 2) + + tiers[5].TierAclRules[0] = TierAclRule{ + Id: "TierOut3Rule1", + Protocols: "6", + TierAclRuleAction: ActionTypeAllow, + LocalPorts: "90", + RemotePorts: "90", + Priority: 3000, + } + + tiers[5].TierAclRules[1] = TierAclRule{ + Id: "TierOut3Rule2", + TierAclRuleAction: ActionTypeBlock, + Priority: 3010, + } + + policy[5].Type = TierAcl + rawJSON, err = json.Marshal(tiers[5]) + if err != nil { + return nil, err + } + + policy[5].Settings = rawJSON + + endpointRequest := PolicyEndpointRequest{ + Policies: policy, + } + + return &endpointRequest, nil +} diff --git a/hcn/hnsv1_test.go b/hcn/hnsv1_test.go index e5a867474c..4190883c00 100644 --- a/hcn/hnsv1_test.go +++ b/hcn/hnsv1_test.go @@ -13,6 +13,7 @@ const ( NatTestNetworkName string = "GoTestNat" NatTestEndpointName string = "GoTestNatEndpoint" OverlayTestNetworkName string = "GoTestOverlay" + BridgeTestNetworkName string = "GoTestL2Bridge" ) func TestMain(m *testing.M) {