Repository: zegl/kube-score (go)

Issue:
NetworkPolicy rule false positive when podSelector is empty
**Which version of kube-score are you using?**

> kube-score version: 1.8.0, commit: 5c3ed1b02ff59a510776a84b7ecadfb21e151e11, built: 2020-08-10T19:29:19Z

**What did you do?**

I defined a NetworkPolicy applicable to all pods in a namespace.

Per the NetworkPolicy documentation `An empty podSelector selects all pods in the namespace` - see under https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource. There's even an example in the docs at https://kubernetes.io/docs/concepts/services-networking/network-policies/#default-allow-all-ingress-traffic

The NetworkPolicy in question is:

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  namespace: default
  name: allow-all-ingress
spec:
  podSelector: {}
  ingress:
  - {}
  policyTypes:
  - Ingress
```

**What did you expect to see?**

I didn't expect any failures.

**What did you see instead?**

The `NetworkPolicy` check generates false positives when `podSelector: {}` like:

```
[CRITICAL] Pod NetworkPolicy
        · The pod does not have a matching network policy
            Create a NetworkPolicy that targets this pod
```

I can work around the problem by explicitly defining a match based on a label set on all the pods like this:

```
  podSelector:
    matchLabels:
      app.kubernetes.io/part-of: myapp
```

But I think the check should be fixed.

Pull request:
score/networkpolicy: handle empty podSelector properly in the pod-has-networkpolicy test
This is done by adopting the Kubernetes-provided metav1.LabelSelector, as is already used by the networkpolicy-targets-pod test.

```
RELNOTE: Support empty podSelectors in the "Pod has NetworkPolicy" test
```

This fixes #293 

Patch:
diff --git a/score/networkpolicy/networkpolicy.go b/score/networkpolicy/networkpolicy.go
index e70105c..a934e0b 100644
--- a/score/networkpolicy/networkpolicy.go
+++ b/score/networkpolicy/networkpolicy.go
@@ -30,10 +30,8 @@ func podHasNetworkPolicy(allNetpols []networkingv1.NetworkPolicy) func(spec core
 				continue
 			}
 
-			matchLabels := netPol.Spec.PodSelector.MatchLabels
-
-			for labelKey, labelVal := range matchLabels {
-				if podLabelVal, ok := podSpec.Labels[labelKey]; ok && podLabelVal == labelVal {
+			if selector, err := metav1.LabelSelectorAsSelector(&netPol.Spec.PodSelector); err == nil {
+				if selector.Matches(internal.MapLables(podSpec.Labels)) {
 
 					// Documentation of PolicyTypes
 					//


Test patch:
diff --git a/score/networkpolicy_test.go b/score/networkpolicy_test.go
index b4540d4..d161f68 100644
--- a/score/networkpolicy_test.go
+++ b/score/networkpolicy_test.go
@@ -76,3 +76,9 @@ func TestNetworkPolicyCronJobNamespaceNotMatchingSelector(t *testing.T) {
 	testExpectedScore(t, "networkpolicy-cronjob-not-matching-selector.yaml", "NetworkPolicy targets Pod", scorecard.GradeCritical)
 	testExpectedScore(t, "networkpolicy-cronjob-not-matching-selector.yaml", "Pod NetworkPolicy", scorecard.GradeCritical)
 }
+
+func TestNetworkPolicyEmptyPodSelector(t *testing.T) {
+	t.Parallel()
+	testExpectedScore(t, "networkpolicy-targets-all-pods.yaml", "NetworkPolicy targets Pod", scorecard.GradeAllOK)
+	testExpectedScore(t, "networkpolicy-targets-all-pods.yaml", "Pod NetworkPolicy", scorecard.GradeAllOK)
+}
diff --git a/score/testdata/networkpolicy-targets-all-pods.yaml b/score/testdata/networkpolicy-targets-all-pods.yaml
new file mode 100644
index 0000000..90ddf10
--- /dev/null
+++ b/score/testdata/networkpolicy-targets-all-pods.yaml
@@ -0,0 +1,26 @@
+apiVersion: networking.k8s.io/v1
+kind: NetworkPolicy
+metadata:
+  name: testapp-netpol
+  namespace: testspace
+spec:
+  podSelector: {}
+  ingress:
+    - {}
+  egress:
+    - {}
+  policyTypes:
+    - Ingress
+    - Egress
+---
+apiVersion: v1
+kind: Pod
+metadata:
+  name: pod-test-1
+  namespace: testspace
+  labels:
+    app: testapp
+spec:
+  containers:
+  - name: foobar
+    image: foo/bar:latest