Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 35 additions & 10 deletions pkg/policyendpoints/manager.go
Original file line number Diff line number Diff line change
Expand Up @@ -180,23 +180,48 @@ func (m *policyEndpointsManager) processPolicyEndpoints(pes []policyinfo.PolicyE
return newPEs
}

// the controller should consolidate the ingress and egress endpoints and put entries to one CIDR if they belong to a same CIDR
// the controller should consolidate the ingress and egress endpoints
func combineRulesEndpoints(ingressEndpoints []policyinfo.EndpointInfo) []policyinfo.EndpointInfo {
var result []policyinfo.EndpointInfo
combinedMap := make(map[string]policyinfo.EndpointInfo)

for _, iep := range ingressEndpoints {
if _, ok := combinedMap[string(iep.CIDR)]; ok {
tempIEP := combinedMap[string(iep.CIDR)]
tempIEP.Ports = append(combinedMap[string(iep.CIDR)].Ports, iep.Ports...)
tempIEP.Except = append(combinedMap[string(iep.CIDR)].Except, iep.Except...)
combinedMap[string(iep.CIDR)] = tempIEP
cidrKey := string(iep.CIDR)
if existing, ok := combinedMap[cidrKey]; ok {
// Only combine if exception lists are identical to preserve rule intent
if exceptionsEqual(existing.Except, iep.Except) {
existing.Ports = append(existing.Ports, iep.Ports...)
combinedMap[cidrKey] = existing
} else {
// Different exceptions - keep both separate to preserve intent
result = append(result, existing)
delete(combinedMap, cidrKey)
result = append(result, iep)
}
} else {
combinedMap[string(iep.CIDR)] = iep
combinedMap[cidrKey] = iep
}
}
if len(combinedMap) > 0 {
return maps.Values(combinedMap)

// Add remaining combined endpoints
for _, ep := range combinedMap {
result = append(result, ep)
}
return nil

return result
}

// exceptionsEqual checks if two exception lists are identical
func exceptionsEqual(a, b []policyinfo.NetworkAddress) bool {
if len(a) != len(b) {
return false
}
for i, addr := range a {
if addr != b[i] {
return false
}
}
return true
}

func (m *policyEndpointsManager) newPolicyEndpoint(policy *networking.NetworkPolicy,
Expand Down
33 changes: 33 additions & 0 deletions pkg/policyendpoints/manager_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -553,3 +553,36 @@ func Test_processPolicyEndpoints(t *testing.T) {
assert.Equal(t, 3, len(pes[0].Spec.Ingress[0].Ports))
assert.Equal(t, 2, len(pes[0].Spec.Egress[0].Ports))
}

func TestCombineRulesEndpoints_MultipleEgressRules(t *testing.T) {
protocolUDP := corev1.ProtocolUDP
port53 := int32(53)

// This test demonstrates the bug where combineRulesEndpoints incorrectly
// merged contradictory egress rules with the same CIDR,
// see https://github.com/aws/amazon-network-policy-controller-k8s/issues/146
endpoints := []policyinfo.EndpointInfo{
{
// First rule: allow traffic to internet, except private ranges
CIDR: "0.0.0.0/0",
Except: []policyinfo.NetworkAddress{
"10.0.0.0/8",
"172.16.0.0/12",
"192.168.0.0/16",
},
Ports: []policyinfo.Port{},
},
{
// Second rule: allow DNS traffic to any destination (including private ranges)
CIDR: "0.0.0.0/0",
Except: []policyinfo.NetworkAddress{}, // No exceptions = allow to anywhere
Ports: []policyinfo.Port{
{Protocol: &protocolUDP, Port: &port53},
},
},
}

combined := combineRulesEndpoints(endpoints)

assert.Len(t, combined, 2, "Should keep contradictory rules separate, not combine them")
}
Loading