Skip to content
58 changes: 58 additions & 0 deletions cns/NetworkContainerContract.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@ package cns

import (
"encoding/json"
"fmt"
"strings"
)

// Container Network Service DNC Contract
Expand Down Expand Up @@ -63,6 +65,14 @@ type CreateNetworkContainerRequest struct {
Routes []Route
AllowHostToNCCommunication bool
AllowNCToHostCommunication bool
EndpointPolicies []NetworkContainerRequestPolicies
}

// NetworkContainerRequestPolicies - specifies policies associated with create network request
type NetworkContainerRequestPolicies struct {
Type string
EndpointType string
Settings json.RawMessage
}

// ConfigureContainerNetworkingRequest - specifies request to attach/detach container to network.
Expand Down Expand Up @@ -220,3 +230,51 @@ type UnpublishNetworkContainerResponse struct {
UnpublishStatusCode int
UnpublishResponseBody []byte
}

// ValidAclPolicySetting - Used to validate ACL policy
type ValidAclPolicySetting struct {
Protocols string `json:","`
Action string `json:","`
Direction string `json:","`
LocalAddresses string `json:","`
RemoteAddresses string `json:","`
LocalPorts string `json:","`
RemotePorts string `json:","`
RuleType string `json:","`
Priority uint16 `json:","`
}

// Validate - Validates network container request policies
func (networkContainerRequestPolicy *NetworkContainerRequestPolicies) Validate() error {
// validate ACL policy
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As one of my comments said can we enforce the validation on apipa endpoint? Check if the provided acl is on apipa endpoint type, if not fail the validation because we don;t have support for acls on cust subnet endpoint. When we add that we should remove the enforced apipa endpoint validation you'll add here. Let me know if it makes sense / you want to discuss this further.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, restricted this API only to APIPA in latest commit.

if networkContainerRequestPolicy != nil {
if strings.EqualFold(networkContainerRequestPolicy.Type, "ACLPolicy") && strings.EqualFold(networkContainerRequestPolicy.EndpointType, "APIPA") {
var requestedAclPolicy ValidAclPolicySetting
if err := json.Unmarshal(networkContainerRequestPolicy.Settings, &requestedAclPolicy); err != nil {
return fmt.Errorf("ACL policy failed to pass validation with error: %+v ", err)
}
//Deny request if ACL Action is empty
if len(strings.TrimSpace(string(requestedAclPolicy.Action))) == 0 {
return fmt.Errorf("Action field cannot be empty in ACL Policy")
}
//Deny request if ACL Action is not Allow or Deny
if !strings.EqualFold(requestedAclPolicy.Action, "Allow") && !strings.EqualFold(requestedAclPolicy.Action, "Deny") {
return fmt.Errorf("Only Allow or Deny is supported in Action field")
}
//Deny request if ACL Direction is empty
if len(strings.TrimSpace(string(requestedAclPolicy.Direction))) == 0 {
return fmt.Errorf("Direction field cannot be empty in ACL Policy")
}
//Deny request if ACL direction is not In or Out
if !strings.EqualFold(requestedAclPolicy.Direction, "In") && !strings.EqualFold(requestedAclPolicy.Direction, "Out") {
return fmt.Errorf("Only In or Out is supported in Direction field")
}
if requestedAclPolicy.Priority == 0 {
return fmt.Errorf("Priority field cannot be empty in ACL Policy")
}
} else {
return fmt.Errorf("Only ACL Policies on APIPA endpoint supported")
}
}
return nil
}
3 changes: 2 additions & 1 deletion cns/hnsclient/hnsclient_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,8 @@ func CreateHostNCApipaEndpoint(
networkContainerID string,
localIPConfiguration cns.IPConfiguration,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool) (string, error) {
allowHostToNCCommunication bool,
ncPolicies []cns.NetworkContainerRequestPolicies) (string, error) {
return "", nil
}

Expand Down
46 changes: 41 additions & 5 deletions cns/hnsclient/hnsclient_windows.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,12 @@ const (

// aclPriority200 indicates the ACL priority of 200
aclPriority200 = 200

// aclPolicyType indicates a ACL policy
aclPolicyType = "ACLPolicy"

//signals a APIPA endpoint type
apipaEndpointType = "APIPA"
)

var (
Expand Down Expand Up @@ -347,7 +353,8 @@ func configureAclSettingHostNCApipaEndpoint(
networkContainerApipaIP string,
hostApipaIP string,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool) ([]hcn.EndpointPolicy, error) {
allowHostToNCCommunication bool,
ncRequestedPolicies []cns.NetworkContainerRequestPolicies) ([]hcn.EndpointPolicy, error) {
var (
err error
endpointPolicies []hcn.EndpointPolicy
Expand Down Expand Up @@ -426,8 +433,33 @@ func configureAclSettingHostNCApipaEndpoint(
return nil, err
}
}

}

if ncRequestedPolicies != nil {
// Iterate thru the requested endpoint policies where policy type is ACL, endpoint type is APIPA
// include the raw json message in the endpoint policies
for _, requestedPolicy := range ncRequestedPolicies {
if strings.EqualFold(requestedPolicy.Type, aclPolicyType) && strings.EqualFold(requestedPolicy.EndpointType, apipaEndpointType) {
var requestedAclPolicy hcn.AclPolicySetting
if err = json.Unmarshal(requestedPolicy.Settings, &requestedAclPolicy); err != nil {
return nil, fmt.Errorf("Failed to Unmarshal requested ACL policy: %+v with error: %S", requestedPolicy.Settings, err)
}
//Using {NetworkContainerIP} as a placeholder to signal using Network Container IP
if strings.EqualFold(requestedAclPolicy.LocalAddresses, "{NetworkContainerIP}") {
requestedAclPolicy.LocalAddresses = networkContainerApipaIP
}
//Using {HostApipaIP} as a placeholder to signal using Host Apipa IP
if strings.EqualFold(requestedAclPolicy.RemoteAddresses, "{HostApipaIP}") {
requestedAclPolicy.RemoteAddresses = hostApipaIP
}
logger.Printf("ACL Policy requested in NcGoalState %+v", requestedAclPolicy)
if err = addAclToEndpointPolicy(requestedAclPolicy, &endpointPolicies); err != nil {
return nil, err
}
}
}
}
return endpointPolicies, nil
}

Expand All @@ -436,7 +468,8 @@ func configureHostNCApipaEndpoint(
networkID string,
localIPConfiguration cns.IPConfiguration,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool) (*hcn.HostComputeEndpoint, error) {
allowHostToNCCommunication bool,
ncPolicies []cns.NetworkContainerRequestPolicies) (*hcn.HostComputeEndpoint, error) {
endpoint := &hcn.HostComputeEndpoint{
Name: endpointName,
HostComputeNetwork: networkID,
Expand All @@ -455,7 +488,8 @@ func configureHostNCApipaEndpoint(
networkContainerApipaIP,
hostApipaIP,
allowNCToHostCommunication,
allowHostToNCCommunication)
allowHostToNCCommunication,
ncPolicies)

if err != nil {
logger.Errorf("[Azure CNS] Failed to configure ACL for HostNCApipaEndpoint. Error: %v", err)
Expand Down Expand Up @@ -490,7 +524,8 @@ func CreateHostNCApipaEndpoint(
networkContainerID string,
localIPConfiguration cns.IPConfiguration,
allowNCToHostCommunication bool,
allowHostToNCCommunication bool) (string, error) {
allowHostToNCCommunication bool,
ncPolicies []cns.NetworkContainerRequestPolicies) (string, error) {
var (
network *hcn.HostComputeNetwork
endpoint *hcn.HostComputeEndpoint
Expand Down Expand Up @@ -528,7 +563,8 @@ func CreateHostNCApipaEndpoint(
network.Id,
localIPConfiguration,
allowNCToHostCommunication,
allowHostToNCCommunication); err != nil {
allowHostToNCCommunication,
ncPolicies); err != nil {
logger.Errorf("[Azure CNS] Failed to configure HostNCApipaEndpoint: %s. Error: %v", endpointName, err)
return "", err
}
Expand Down
3 changes: 2 additions & 1 deletion cns/restserver/restserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1697,7 +1697,8 @@ func (service *HTTPRestService) createHostNCApipaEndpoint(w http.ResponseWriter,
req.NetworkContainerID,
networkContainerDetails.CreateNetworkContainerRequest.LocalIPConfiguration,
networkContainerDetails.CreateNetworkContainerRequest.AllowNCToHostCommunication,
networkContainerDetails.CreateNetworkContainerRequest.AllowHostToNCCommunication); err != nil {
networkContainerDetails.CreateNetworkContainerRequest.AllowHostToNCCommunication,
networkContainerDetails.CreateNetworkContainerRequest.EndpointPolicies); err != nil {
returnMessage = fmt.Sprintf("CreateHostNCApipaEndpoint failed with error: %v", err)
returnCode = UnexpectedError
}
Expand Down