New NetworkPolicy tests: Part 2, all truth table validation scenario definitions

Co-authored-by: Matt Fenwick <mfenwick100@gmail.com>
Co-authored-by: Jay Vyas <jvyas@vmware.com>
Co-authored-by: Abhishek Raut <rauta@vmware.com>
This commit is contained in:
jay vyas 2020-12-14 16:47:07 -05:00
parent 65632b8677
commit debbe9dce9

View File

@ -20,7 +20,9 @@ import (
"context"
"encoding/json"
"fmt"
"time"
"k8s.io/apimachinery/pkg/util/intstr"
"k8s.io/apimachinery/pkg/util/wait"
v1 "k8s.io/api/core/v1"
@ -28,6 +30,7 @@ import (
"k8s.io/kubernetes/test/e2e/network"
"github.com/onsi/ginkgo"
utilnet "k8s.io/utils/net"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/kubernetes/test/e2e/framework"
@ -191,6 +194,661 @@ var _ = network.SIGDescribe("Netpol [LinuxOnly]", func() {
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy to allow traffic from pods within server namespace based on PodSelector [Feature:NetworkPolicy]", func() {
allowedPods := metav1.LabelSelector{
MatchLabels: map[string]string{
"pod": "b",
},
}
policy := GetAllowIngressByPod("x-a-allows-x-b", map[string]string{"pod": "a"}, &allowedPods)
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsX, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy to allow traffic only from a different namespace, based on NamespaceSelector [Feature:NetworkPolicy]", func() {
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedLabels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
policy := GetAllowIngressByNamespace("allow-client-a-via-ns-selector", map[string]string{"pod": "a"}, allowedLabels)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
// disallow all traffic from the x or z namespaces
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachability.ExpectPeer(&Peer{Namespace: nsZ}, &Peer{Namespace: nsX, Pod: "a"}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on PodSelector with MatchExpressions[Feature:NetworkPolicy]", func() {
allowedPods := metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "pod",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"b"},
}},
}
policy := GetAllowIngressByPod("x-a-allows-x-b", map[string]string{"pod": "a"}, &allowedPods)
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsX, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on NamespaceSelector with MatchExpressions[Feature:NetworkPolicy]", func() {
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "ns",
Operator: metav1.LabelSelectorOpIn,
Values: []string{nsY},
}},
}
policy := GetAllowIngressByNamespace("allow-ns-y-match-selector", map[string]string{"pod": "a"}, allowedNamespaces)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
// disallow all traffic from the x or z namespaces
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachability.ExpectPeer(&Peer{Namespace: nsZ}, &Peer{Namespace: nsX, Pod: "a"}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on PodSelector or NamespaceSelector [Feature:NetworkPolicy]", func() {
nsX, _, _, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "ns",
Operator: metav1.LabelSelectorOpNotIn,
Values: []string{nsX},
}},
}
podBAllowlisting := &metav1.LabelSelector{
MatchLabels: map[string]string{
"pod": "b",
},
}
policy := GetAllowIngressByNamespaceOrPod("allow-ns-y-match-selector", map[string]string{"pod": "a"}, allowedNamespaces, podBAllowlisting)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.Expect(NewPodString(nsX, "a"), NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsX, "c"), NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "ns",
Operator: metav1.LabelSelectorOpNotIn,
Values: []string{nsX},
}},
}
allowedPod := &metav1.LabelSelector{
MatchLabels: map[string]string{
"pod": "b",
},
}
policy := GetAllowIngressByNamespaceAndPod("allow-ns-y-podselector-and-nsselector", map[string]string{"pod": "a"}, allowedNamespaces, allowedPod)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsY, "b"), NewPodString(nsX, "a"), true)
reachability.Expect(NewPodString(nsZ, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on Multiple PodSelectors and NamespaceSelectors [Feature:NetworkPolicy]", func() {
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "ns",
Operator: metav1.LabelSelectorOpNotIn,
Values: []string{nsX},
}},
}
allowedPod := &metav1.LabelSelector{
MatchExpressions: []metav1.LabelSelectorRequirement{{
Key: "pod",
Operator: metav1.LabelSelectorOpIn,
Values: []string{"b", "c"},
}},
}
policy := GetAllowIngressByNamespaceAndPod("allow-ns-y-z-pod-b-c", map[string]string{"pod": "a"}, allowedNamespaces, allowedPod)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachability.Expect(NewPodString(nsY, "a"), NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsZ, "a"), NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy to allow traffic only from a pod in a different namespace based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
nsX, nsY, _, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
allowedPods := &metav1.LabelSelector{
MatchLabels: map[string]string{
"pod": "a",
},
}
policy := GetAllowIngressByNamespaceAndPod("allow-ns-y-pod-a-via-namespace-pod-selector", map[string]string{"pod": "a"}, allowedNamespaces, allowedPods)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsY, "a"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce policy based on Ports [Feature:NetworkPolicy]", func() {
ginkgo.By("Creating a network allowPort81Policy which only allows allow listed namespaces (y) to connect on exactly one port (81)")
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedLabels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
allowPort81Policy := GetAllowIngressByNamespaceAndPort("allow-client-a-via-ns-selector", map[string]string{"pod": "a"}, allowedLabels, &intstr.IntOrString{IntVal: 81})
CreatePolicy(k8s, allowPort81Policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachability.ExpectPeer(&Peer{Namespace: nsY}, &Peer{Namespace: nsX, Pod: "a"}, true)
reachability.ExpectPeer(&Peer{Namespace: nsZ}, &Peer{Namespace: nsX, Pod: "a"}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce multiple, stacked policies with overlapping podSelectors [Feature:NetworkPolicy]", func() {
ginkgo.By("Creating a network allowPort81Policy which only allows allow listed namespaces (y) to connect on exactly one port (81)")
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedLabels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
allowPort81Policy := GetAllowIngressByNamespaceAndPort("allow-client-a-via-ns-selector", map[string]string{"pod": "a"}, allowedLabels, &intstr.IntOrString{IntVal: 81})
CreatePolicy(k8s, allowPort81Policy, nsX)
reachabilityALLOW := NewReachability(model.AllPods(), true)
reachabilityALLOW.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachabilityALLOW.ExpectPeer(&Peer{Namespace: nsY}, &Peer{Namespace: nsX, Pod: "a"}, true)
reachabilityALLOW.ExpectPeer(&Peer{Namespace: nsZ}, &Peer{Namespace: nsX, Pod: "a"}, false)
ginkgo.By("Verifying traffic on port 81.")
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityALLOW})
reachabilityDENY := NewReachability(model.AllPods(), true)
reachabilityDENY.ExpectAllIngress(NewPodString(nsX, "a"), false)
ginkgo.By("Verifying traffic on port 80.")
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityDENY})
allowPort80Policy := GetAllowIngressByNamespaceAndPort("allow-client-a-via-ns-selector-80", map[string]string{"pod": "a"}, allowedLabels, &intstr.IntOrString{IntVal: 80})
CreatePolicy(k8s, allowPort80Policy, nsX)
ginkgo.By("Verifying that we can add a policy to unblock port 80")
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityALLOW})
})
ginkgo.It("should support allow-all policy [Feature:NetworkPolicy]", func() {
ginkgo.By("Creating a network policy which allows all traffic.")
policy := GetAllowIngress("allow-all")
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
ginkgo.By("Testing pods can connect to both ports when an 'allow-all' policy is present.")
reachability := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should allow ingress access on one named port [Feature:NetworkPolicy]", func() {
policy := GetAllowIngressByPort("allow-all", &intstr.IntOrString{Type: intstr.String, StrVal: "serve-81-tcp"})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
ginkgo.By("Blocking all ports other then 81 in the entire namespace")
reachabilityPort81 := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort81})
// disallow all traffic to the x namespace
reachabilityPort80 := NewReachability(model.AllPods(), true)
reachabilityPort80.ExpectPeer(&Peer{}, &Peer{Namespace: nsX}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort80})
})
ginkgo.It("should allow ingress access from namespace on one named port [Feature:NetworkPolicy]", func() {
nsX, nsY, nsZ, model, k8s := getK8SModel(f)
allowedLabels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
policy := GetAllowIngressByNamespaceAndPort("allow-client-a-via-ns-selector-80", map[string]string{"pod": "a"}, allowedLabels, &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80-tcp"})
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
// disallow all traffic from the x or z namespaces
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{Namespace: nsX, Pod: "a"}, false)
reachability.ExpectPeer(&Peer{Namespace: nsZ}, &Peer{Namespace: nsX, Pod: "a"}, false)
ginkgo.By("Verify that port 80 is allowed for namespace y")
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
ginkgo.By("Verify that port 81 is blocked for all namespaces including y")
reachabilityFAIL := NewReachability(model.AllPods(), true)
reachabilityFAIL.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityFAIL})
})
ginkgo.It("should allow egress access on one named port [Feature:NetworkPolicy]", func() {
ginkgo.By("validating egress from port 81 to port 80")
policy := GetAllowEgressByPort("allow-egress", &intstr.IntOrString{Type: intstr.String, StrVal: "serve-80-tcp"})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachabilityPort80 := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort80})
// meanwhile no traffic over 81 should work, since our egress policy is on 80
reachabilityPort81 := NewReachability(model.AllPods(), true)
reachabilityPort81.ExpectPeer(&Peer{Namespace: nsX}, &Peer{}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort81})
})
ginkgo.It("should enforce updated policy [Feature:NetworkPolicy]", func() {
ginkgo.By("Using the simplest possible mutation: start with allow all, then switch to deny all")
// part 1) allow all
policy := GetAllowIngress("allow-all-mutate-to-deny-all")
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
// part 2) update the policy to deny all
policy.Spec.Ingress = []networkingv1.NetworkPolicyIngressRule{}
UpdatePolicy(k8s, policy, nsX)
reachabilityDeny := NewReachability(model.AllPods(), true)
reachabilityDeny.ExpectPeer(&Peer{}, &Peer{Namespace: nsX}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityDeny})
})
ginkgo.It("should allow ingress access from updated namespace [Feature:NetworkPolicy]", func() {
nsX, nsY, _, model, k8s := getK8SModel(f)
defer ResetNamespaceLabels(k8s, nsY)
allowedLabels := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns2": "updated",
},
}
policy := GetAllowIngressByNamespace("allow-client-a-via-ns-selector", map[string]string{"pod": "a"}, allowedLabels)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
// add a new label, we'll remove it after this test is completed
updatedLabels := map[string]string{
"ns": nsY,
"ns2": "updated",
}
UpdateNamespaceLabels(k8s, nsY, updatedLabels)
// anything from namespace 'y' should be able to get to x/a
reachabilityWithLabel := NewReachability(model.AllPods(), true)
reachabilityWithLabel.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachabilityWithLabel.ExpectPeer(&Peer{Namespace: nsY}, &Peer{}, true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityWithLabel})
})
ginkgo.It("should allow ingress access from updated pod [Feature:NetworkPolicy]", func() {
nsX, _, _, model, k8s := getK8SModel(f)
podXB, err := model.FindPod(nsX, "b")
framework.ExpectNoError(err, "find pod x/b")
defer ResetPodLabels(k8s, podXB)
// add a new label, we'll remove it after this test is done
matchLabels := map[string]string{"pod": "b", "pod2": "updated"}
allowedLabels := &metav1.LabelSelector{MatchLabels: matchLabels}
policy := GetAllowIngressByPod("allow-client-a-via-pod-selector", map[string]string{"pod": "a"}, allowedLabels)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
// now update label in x namespace and pod b
AddPodLabels(k8s, podXB, matchLabels)
ginkgo.By("x/b is able to reach x/a when label is updated")
reachabilityWithLabel := NewReachability(model.AllPods(), true)
reachabilityWithLabel.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachabilityWithLabel.Expect(NewPodString(nsX, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityWithLabel})
})
ginkgo.It("should deny ingress access to updated pod [Feature:NetworkPolicy]", func() {
nsX, _, _, model, k8s := getK8SModel(f)
podXA, err := model.FindPod(nsX, "a")
framework.ExpectNoError(err, "find pod x/a")
defer ResetPodLabels(k8s, podXA)
policy := GetDenyIngressForTarget(metav1.LabelSelector{MatchLabels: map[string]string{"target": "isolated"}})
CreatePolicy(k8s, policy, nsX)
ginkgo.By("Verify that everything can reach x/a")
reachability := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
AddPodLabels(k8s, podXA, map[string]string{"target": "isolated"})
reachabilityIsolated := NewReachability(model.AllPods(), true)
reachabilityIsolated.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityIsolated})
})
ginkgo.It("should work with Ingress, Egress specified together [Feature:NetworkPolicy]", func() {
allowedPodLabels := &metav1.LabelSelector{MatchLabels: map[string]string{"pod": "b"}}
policy := GetAllowIngressByPod("allow-client-a-via-pod-selector", map[string]string{"pod": "a"}, allowedPodLabels)
// add an egress rule on to it...
protocolUDP := v1.ProtocolUDP
policy.Spec.Egress = []networkingv1.NetworkPolicyEgressRule{
{
Ports: []networkingv1.NetworkPolicyPort{
{
// dont use named ports
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 80},
},
{
Protocol: &protocolUDP,
Port: &intstr.IntOrString{Type: intstr.Int, IntVal: 53},
},
},
},
}
policy.Spec.PolicyTypes = []networkingv1.PolicyType{networkingv1.PolicyTypeEgress, networkingv1.PolicyTypeIngress}
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachabilityPort80 := NewReachability(model.AllPods(), true)
reachabilityPort80.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachabilityPort80.Expect(NewPodString(nsX, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort80})
ginkgo.By("validating that port 81 doesn't work")
// meanwhile no egress traffic on 81 should work, since our egress policy is on 80
reachabilityPort81 := NewReachability(model.AllPods(), true)
reachabilityPort81.ExpectAllIngress(NewPodString(nsX, "a"), false)
reachabilityPort81.ExpectAllEgress(NewPodString(nsX, "a"), false)
reachabilityPort81.Expect(NewPodString(nsX, "b"), NewPodString(nsX, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityPort81})
})
ginkgo.It("should enforce egress policy allowing traffic to a server in a different namespace based on PodSelector and NamespaceSelector [Feature:NetworkPolicy]", func() {
nsX, nsY, _, model, k8s := getK8SModel(f)
allowedNamespaces := &metav1.LabelSelector{
MatchLabels: map[string]string{
"ns": nsY,
},
}
allowedPods := &metav1.LabelSelector{
MatchLabels: map[string]string{
"pod": "a",
},
}
policy := GetAllowEgressByNamespaceAndPod("allow-to-ns-y-pod-a", map[string]string{"pod": "a"}, allowedNamespaces, allowedPods)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllEgress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsX, "a"), NewPodString(nsY, "a"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce multiple ingress policies with ingress allow-all policy taking precedence [Feature:NetworkPolicy]", func() {
nsX, _, _, model, k8s := getK8SModel(f)
policyAllowOnlyPort80 := GetAllowIngressByPort("allow-ingress-port-80", &intstr.IntOrString{Type: intstr.Int, IntVal: 80})
CreatePolicy(k8s, policyAllowOnlyPort80, nsX)
ginkgo.By("The policy targets port 80 -- so let's make sure traffic on port 81 is blocked")
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectPeer(&Peer{}, &Peer{Namespace: nsX}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
ginkgo.By("Allowing all ports")
policyAllowAll := GetAllowIngress("allow-ingress")
CreatePolicy(k8s, policyAllowAll, nsX)
reachabilityAll := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityAll})
})
ginkgo.It("should enforce multiple egress policies with egress allow-all policy taking precedence [Feature:NetworkPolicy]", func() {
policyAllowPort80 := GetAllowEgressByPort("allow-egress-port-80", &intstr.IntOrString{Type: intstr.Int, IntVal: 80})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policyAllowPort80, nsX)
ginkgo.By("Making sure ingress doesn't work other than port 80")
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
ginkgo.By("Allowing all ports")
policyAllowAll := GetAllowEgress()
CreatePolicy(k8s, policyAllowAll, nsX)
reachabilityAll := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachabilityAll})
})
ginkgo.It("should stop enforcing policies after they are deleted [Feature:NetworkPolicy]", func() {
ginkgo.By("Creating a network policy for the server which denies all traffic.")
// Deny all traffic into and out of "x".
policy := GetDenyAll("deny-all")
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
reachability := NewReachability(model.AllPods(), true)
// Expect all traffic into, and out of "x" to be False.
reachability.ExpectPeer(&Peer{Namespace: nsX}, &Peer{}, false)
reachability.ExpectPeer(&Peer{}, &Peer{Namespace: nsX}, false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
err := k8s.CleanNetworkPolicies(model.NamespaceNames)
time.Sleep(3 * time.Second) // TODO we can remove this eventually, its just a hack to keep CI stable.
framework.ExpectNoError(err, "unable to clean network policies")
// Now the policy is deleted, we expect all connectivity to work again.
reachabilityAll := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityAll})
})
// TODO, figure out how the next 3 tests should work with dual stack : do we need a different abstraction then just "podIP"?
ginkgo.It("should allow egress access to server in CIDR block [Feature:NetworkPolicy]", func() {
// Getting podServer's status to get podServer's IP, to create the CIDR
nsX, nsY, _, model, k8s := getK8SModel(f)
podList, err := f.ClientSet.CoreV1().Pods(nsY).List(context.TODO(), metav1.ListOptions{LabelSelector: "pod=b"})
framework.ExpectNoError(err, "Failing to list pods in namespace y")
pod := podList.Items[0]
hostMask := 32
if utilnet.IsIPv6String(pod.Status.PodIP) {
hostMask = 128
}
podServerCIDR := fmt.Sprintf("%s/%d", pod.Status.PodIP, hostMask)
policyAllowCIDR := GetAllowEgressByCIDR("a", podServerCIDR)
CreatePolicy(k8s, policyAllowCIDR, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllEgress(NewPodString(nsX, "a"), false)
reachability.Expect(NewPodString(nsX, "a"), NewPodString(nsY, "b"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should enforce except clause while egress access to server in CIDR block [Feature:NetworkPolicy]", func() {
// Getting podServer's status to get podServer's IP, to create the CIDR with except clause
nsX, _, _, model, k8s := getK8SModel(f)
podList, err := f.ClientSet.CoreV1().Pods(nsX).List(context.TODO(), metav1.ListOptions{LabelSelector: "pod=a"})
framework.ExpectNoError(err, "Failing to find pod x/a")
podA := podList.Items[0]
podServerAllowCIDR := fmt.Sprintf("%s/4", podA.Status.PodIP)
podList, err = f.ClientSet.CoreV1().Pods(nsX).List(context.TODO(), metav1.ListOptions{LabelSelector: "pod=b"})
framework.ExpectNoError(err, "Failing to find pod x/b")
podB := podList.Items[0]
hostMask := 32
if utilnet.IsIPv6String(podB.Status.PodIP) {
hostMask = 128
}
podServerExceptList := []string{fmt.Sprintf("%s/%d", podB.Status.PodIP, hostMask)}
policyAllowCIDR := GetAllowEgressByCIDRExcept("a", podServerAllowCIDR, podServerExceptList)
CreatePolicy(k8s, policyAllowCIDR, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.Expect(NewPodString(nsX, "a"), NewPodString(nsX, "b"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should ensure an IP overlapping both IPBlock.CIDR and IPBlock.Except is allowed [Feature:NetworkPolicy]", func() {
// Getting podServer's status to get podServer's IP, to create the CIDR with except clause
nsX, _, _, model, k8s := getK8SModel(f)
podList, err := f.ClientSet.CoreV1().Pods(nsX).List(context.TODO(), metav1.ListOptions{LabelSelector: "pod=a"})
framework.ExpectNoError(err, "Failing to find pod x/a")
podA := podList.Items[0]
podList, err = f.ClientSet.CoreV1().Pods(nsX).List(context.TODO(), metav1.ListOptions{LabelSelector: "pod=b"})
framework.ExpectNoError(err, "Failing to find pod x/b")
podB := podList.Items[0]
// Exclude podServer's IP with an Except clause
hostMask := 32
if utilnet.IsIPv6String(podB.Status.PodIP) {
hostMask = 128
}
podServerAllowCIDR := fmt.Sprintf("%s/4", podA.Status.PodIP)
podServerExceptList := []string{fmt.Sprintf("%s/%d", podB.Status.PodIP, hostMask)}
policyAllowCIDR := GetAllowEgressByCIDRExcept("a", podServerAllowCIDR, podServerExceptList)
CreatePolicy(k8s, policyAllowCIDR, nsX)
reachability := NewReachability(model.AllPods(), true)
reachability.Expect(NewPodString(nsX, "a"), NewPodString(nsX, "b"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachability})
podBIP := fmt.Sprintf("%s/%d", podB.Status.PodIP, hostMask)
//// Create NetworkPolicy which allows access to the podServer using podServer's IP in allow CIDR.
allowPolicy := GetAllowEgressByCIDR("a", podBIP)
// SHOULD THIS BE UPDATE OR CREATE JAY TESTING 10/31
UpdatePolicy(k8s, allowPolicy, nsX)
reachabilityAllow := NewReachability(model.AllPods(), true)
reachabilityAllow.ExpectAllEgress(NewPodString(nsX, "a"), false)
reachabilityAllow.Expect(NewPodString(nsX, "a"), NewPodString(nsX, "b"), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: reachabilityAllow})
})
ginkgo.It("should enforce policies to check ingress and egress policies can be controlled independently based on PodSelector [Feature:NetworkPolicy]", func() {
/*
Test steps:
1. Verify every pod in every namespace can talk to each other
- including a -> b and b -> a
2. Create a policy to allow egress a -> b (target = a)
3. Create a policy to *deny* ingress b -> a (target = a)
4. Verify a -> b allowed; b -> a blocked
*/
targetLabels := map[string]string{"pod": "a"}
ginkgo.By("Creating a network policy for pod-a which allows Egress traffic to pod-b.")
allowEgressPolicy := GetAllowEgressForTarget(metav1.LabelSelector{MatchLabels: targetLabels})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, allowEgressPolicy, nsX)
allowEgressReachability := NewReachability(model.AllPods(), true)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: allowEgressReachability})
ginkgo.By("Creating a network policy for pod-a that denies traffic from pod-b.")
denyAllIngressPolicy := GetDenyIngressForTarget(metav1.LabelSelector{MatchLabels: targetLabels})
CreatePolicy(k8s, denyAllIngressPolicy, nsX)
denyIngressToXReachability := NewReachability(model.AllPods(), true)
denyIngressToXReachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 80, Protocol: v1.ProtocolTCP, Reachability: denyIngressToXReachability})
})
ginkgo.It("should not allow access by TCP when a policy specifies only SCTP [Feature:NetworkPolicy] [Feature:SCTP]", func() {
policy := GetAllowIngressOnProtocolByPort("allow-only-sctp-ingress-on-port-81", v1.ProtocolSCTP, map[string]string{"pod": "a"}, &intstr.IntOrString{IntVal: 81})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
ginkgo.By("Creating a network policy for the server which allows traffic only via SCTP on port 81.")
// Probing with TCP, so all traffic should be dropped.
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
ginkgo.It("should not allow access by TCP when a policy specifies only UDP [Feature:NetworkPolicy] [Feature:UDP]", func() {
policy := GetAllowIngressOnProtocolByPort("allow-only-udp-ingress-on-port-81", v1.ProtocolUDP, map[string]string{"pod": "a"}, &intstr.IntOrString{IntVal: 81})
nsX, _, _, model, k8s := getK8SModel(f)
CreatePolicy(k8s, policy, nsX)
ginkgo.By("Creating a network policy for the server which allows traffic only via UDP on port 81.")
// Probing with TCP, so all traffic should be dropped.
reachability := NewReachability(model.AllPods(), true)
reachability.ExpectAllIngress(NewPodString(nsX, "a"), false)
ValidateOrFail(k8s, model, &TestCase{FromPort: 81, ToPort: 81, Protocol: v1.ProtocolTCP, Reachability: reachability})
})
})
})