Skip to content

Commit

Permalink
test with named port
Browse files Browse the repository at this point in the history
  • Loading branch information
shireenf-ibm committed Jan 26, 2025
1 parent 9d9bc9f commit eb8eba2
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 3 deletions.
12 changes: 12 additions & 0 deletions pkg/netpol/connlist/connlist_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1701,6 +1701,18 @@ var goodPathTests = []struct {
exposureAnalysis: true,
outputFormats: ValidFormats,
},
{
// AdminNetworkPolicy : exposes the hello-world/workload-a to entire-cluster on namedPort on both ingress and egress
// NetworkPolicy denies all on hello-world/workload-a (so is exposed only to the named-ports from ANP)
// Note that: A rule with NamedPort of ANP does not specify the protocol; protocol is determined by the destination's configuration
// On the ingress exposure output, since the dst is hello-world/workload-a itself, the namedPort is converted
// according to the pod's configuration
// but on egress exposure, we see that the potential is to the namedPort (protocol may be any)
// In the connlist output - we see how the named-port is determined by the dest's configuration
testDirName: "exposure_test_with_anp_11_with_named_port",
outputFormats: []string{output.DefaultFormat},
exposureAnalysis: true,
},
}

func runParsedResourcesConnlistTests(t *testing.T, testList []examples.ParsedResourcesTest) {
Expand Down
6 changes: 5 additions & 1 deletion pkg/netpol/eval/internal/k8s/adminnetpol.go
Original file line number Diff line number Diff line change
Expand Up @@ -448,8 +448,12 @@ func ruleConnections(ports *[]apisv1a.AdminNetworkPolicyPort, dst Peer) (*common
portSet.AddPort(intstr.FromInt32(anpPort.PortNumber.Port))
case anpPort.NamedPort != nil:
if dst == nil || isPeerRepresentative(dst) {
// if dst is nil or representative: named port is added to the conns set as is
// if dst is nil or representative: named port is added to the conns without conversion.
// the protocol of a named port of an ANP rule is depending on the pod's configuration.
// since, we have no indication of a "representative-peer" configuration, this namedPort is added as a potential
// exposure without protocol ("").
portSet.AddPort(intstr.FromString(*anpPort.NamedPort))
res.AddConnection("", portSet)
continue
}
if dst.PeerType() == IPBlockType {
Expand Down
16 changes: 14 additions & 2 deletions pkg/netpol/eval/internal/k8s/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import (
corev1 "k8s.io/api/core/v1"
v1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/types"
"k8s.io/apimachinery/pkg/util/intstr"

"github.com/np-guard/netpol-analyzer/pkg/manifests/parser"
"github.com/np-guard/netpol-analyzer/pkg/netpol/internal/common"
Expand Down Expand Up @@ -320,9 +321,20 @@ func (pod *Pod) checkAndConvertNamedPortsInConnection(conns *common.ConnectionSe
// the named ports with pod's port numbers if possible
for protocol, namedPorts := range connNamedPorts {
for _, namedPort := range namedPorts {
// get the matching protocol and port-number from the pod-configuration
podProtocol, portNum := pod.ConvertPodNamedPort(namedPort)
if podProtocol == string(protocol) && portNum != common.NoPort { // matching port and protocol
connsCopy.ReplaceNamedPortWithMatchingPortNum(protocol, namedPort, portNum)
if podProtocol != "" && portNum != common.NoPort { // there is a matching containerPort in the pod configuration
switch protocol { // the original protocol in the given conns may be either empty or not
case "": // if empty - means inferred from an ANP rule
// in this case we need to add the matching connection (pods' protocol+number) to the connsCopy
newPort := common.MakePortSet(false)
newPort.AddPort(intstr.FromInt32(portNum))
connsCopy.AddConnection(corev1.Protocol(podProtocol), newPort)
// and remove the entry with "" protocol from connsCopy
delete(connsCopy.AllowedProtocols, protocol)
default: // protocol is defined, replace named-port of the given protocol with its matching number
connsCopy.ReplaceNamedPortWithMatchingPortNum(protocol, namedPort, portNum)
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
0.0.0.0-255.255.255.255 => hello-world/workload-b[Deployment] : All Connections
hello-world/workload-a[Deployment] => hello-world/workload-b[Deployment] : TCP 8050
hello-world/workload-b[Deployment] => 0.0.0.0-255.255.255.255 : All Connections
hello-world/workload-b[Deployment] => hello-world/workload-a[Deployment] : UDP 8050

Exposure Analysis Result:
Egress Exposure:
hello-world/workload-a[Deployment] => entire-cluster : local-port
hello-world/workload-b[Deployment] => 0.0.0.0-255.255.255.255 : All Connections
hello-world/workload-b[Deployment] => entire-cluster : All Connections

Ingress Exposure:
hello-world/workload-a[Deployment] <= entire-cluster : UDP 8050
hello-world/workload-b[Deployment] <= 0.0.0.0-255.255.255.255 : All Connections
hello-world/workload-b[Deployment] <= entire-cluster : All Connections

Workloads not protected by network policies:
hello-world/workload-b[Deployment] is not protected on Egress
hello-world/workload-b[Deployment] is not protected on Ingress
55 changes: 55 additions & 0 deletions tests/exposure_test_with_anp_11_with_named_port/deployments.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
---
apiVersion: v1
kind: Namespace
metadata:
name: hello-world
spec: {}
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: workload-a
namespace: hello-world
labels:
app: a-app
spec:
selector:
matchLabels:
app: a-app
template:
metadata:
labels:
app: a-app
spec:
containers:
- name: hello-world
image: quay.io/shfa/hello-world:latest
ports:
- containerPort: 8000 # containerport1
- name: local-port
protocol: UDP
containerPort: 8050 # containerport2
- containerPort: 8090 # containerport3
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: workload-b
namespace: hello-world
labels:
app: b-app
spec:
selector:
matchLabels:
app: b-app
template:
metadata:
labels:
app: b-app
spec:
containers:
- name: hello-world
image: quay.io/shfa/hello-world:latest
ports:
- name: local-port
containerPort: 8050
41 changes: 41 additions & 0 deletions tests/exposure_test_with_anp_11_with_named_port/policies.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
apiVersion: policy.networking.k8s.io/v1alpha1
kind: AdminNetworkPolicy
metadata:
name: exposure-deny-peer-allow-entire-cluster-all-conns
spec:
priority: 10
subject:
pods:
namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: hello-world
podSelector:
matchLabels:
app: a-app
egress:
- name: "allow-all-to-entire-cluster-on-local-port"
action: "Allow"
to:
- namespaces: {}
ports:
- namedPort: local-port
ingress:
- name: "allow-all-from-entire-cluster-on-local-port"
action: "Allow"
from:
- namespaces: {}
ports:
- namedPort: local-port
---
kind: NetworkPolicy
apiVersion: networking.k8s.io/v1
metadata:
name: deny-all-app-a
namespace: hello-world
spec:
podSelector:
matchLabels:
app: a-app
policyTypes:
- Ingress
- Egress

0 comments on commit eb8eba2

Please sign in to comment.