Fix incorrect message on describe netpol

When I describe network policies, it often tells me that pods are
isolated for egress connectivity because the policy that applies to them
has no egress rules. However, this would only lead to isolation if there
is an explicitly set egress policy type. Otherwise, the policy allows
egress traffic. The same applies if you have explicitly set an egress
type only, describe will incorrectly report isolated ingress traffic.

This PR fixes this by inferring the applicable direction for the policy
based on the PolicyTypes, and then if a policy doesn't apply eg to
egress, we print 'Not affecting egress traffic'
This commit is contained in:
Jack Kleeman 2019-10-22 17:43:03 +01:00
parent bef8d426f2
commit 7753bfa3a4
2 changed files with 284 additions and 4 deletions

View File

@ -3745,13 +3745,38 @@ func describeNetworkPolicySpec(nps networkingv1.NetworkPolicySpec, w PrefixWrite
} else {
w.Write(LEVEL_2, "%s\n", metav1.FormatLabelSelector(&nps.PodSelector))
}
w.Write(LEVEL_1, "Allowing ingress traffic:\n")
printNetworkPolicySpecIngressFrom(nps.Ingress, " ", w)
w.Write(LEVEL_1, "Allowing egress traffic:\n")
printNetworkPolicySpecEgressTo(nps.Egress, " ", w)
ingressEnabled, egressEnabled := getPolicyType(nps)
if ingressEnabled {
w.Write(LEVEL_1, "Allowing ingress traffic:\n")
printNetworkPolicySpecIngressFrom(nps.Ingress, " ", w)
} else {
w.Write(LEVEL_1, "Not affecting ingress traffic\n")
}
if egressEnabled {
w.Write(LEVEL_1, "Allowing egress traffic:\n")
printNetworkPolicySpecEgressTo(nps.Egress, " ", w)
} else {
w.Write(LEVEL_1, "Not affecting egress traffic\n")
}
w.Write(LEVEL_1, "Policy Types: %v\n", policyTypesToString(nps.PolicyTypes))
}
func getPolicyType(nps networkingv1.NetworkPolicySpec) (bool, bool) {
var ingress, egress bool
for _, pt := range nps.PolicyTypes {
switch pt {
case networkingv1.PolicyTypeIngress:
ingress = true
case networkingv1.PolicyTypeEgress:
egress = true
}
}
return ingress, egress
}
func printNetworkPolicySpecIngressFrom(npirs []networkingv1.NetworkPolicyIngressRule, initialIndent string, w PrefixWriter) {
if len(npirs) == 0 {
w.Write(LEVEL_0, "%s%s\n", initialIndent, "<none> (Selected pods are isolated for ingress connectivity)")

View File

@ -3142,6 +3142,261 @@ Spec:
}
}
func TestDescribeIngressNetworkPolicies(t *testing.T) {
expectedTime, err := time.Parse("2006-01-02 15:04:05 Z0700 MST", "2017-06-04 21:45:56 -0700 PDT")
if err != nil {
t.Errorf("unable to parse time %q error: %s", "2017-06-04 21:45:56 -0700 PDT", err)
}
expectedOut := `Name: network-policy-1
Namespace: default
Created on: 2017-06-04 21:45:56 -0700 PDT
Labels: <none>
Annotations: <none>
Spec:
PodSelector: foo in (bar1,bar2),foo2 notin (bar1,bar2),id1=app1,id2=app2
Allowing ingress traffic:
To Port: 80/TCP
To Port: 82/TCP
From:
NamespaceSelector: id=ns1,id2=ns2
PodSelector: id=pod1,id2=pod2
From:
PodSelector: id=app2,id2=app3
From:
NamespaceSelector: id=app2,id2=app3
From:
NamespaceSelector: foo in (bar1,bar2),id=app2,id2=app3
From:
IPBlock:
CIDR: 192.168.0.0/16
Except: 192.168.3.0/24, 192.168.4.0/24
----------
To Port: <any> (traffic allowed to all ports)
From: <any> (traffic not restricted by source)
Not affecting egress traffic
Policy Types: Ingress
`
port80 := intstr.FromInt(80)
port82 := intstr.FromInt(82)
protoTCP := corev1.ProtocolTCP
versionedFake := fake.NewSimpleClientset(&networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "network-policy-1",
Namespace: "default",
CreationTimestamp: metav1.NewTime(expectedTime),
},
Spec: networkingv1.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"id1": "app1",
"id2": "app2",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
{Key: "foo2", Operator: "NotIn", Values: []string{"bar1", "bar2"}},
},
},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{
Ports: []networkingv1.NetworkPolicyPort{
{Port: &port80},
{Port: &port82, Protocol: &protoTCP},
},
From: []networkingv1.NetworkPolicyPeer{
{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "pod1",
"id2": "pod2",
},
},
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "ns1",
"id2": "ns2",
},
},
},
{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
},
},
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
},
},
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
},
},
},
{
IPBlock: &networkingv1.IPBlock{
CIDR: "192.168.0.0/16",
Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
},
},
},
},
{},
},
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
},
})
d := NetworkPolicyDescriber{versionedFake}
out, err := d.Describe("default", "network-policy-1", describe.DescriberSettings{})
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if out != expectedOut {
t.Errorf("want:\n%s\ngot:\n%s", expectedOut, out)
}
}
func TestDescribeIsolatedEgressNetworkPolicies(t *testing.T) {
expectedTime, err := time.Parse("2006-01-02 15:04:05 Z0700 MST", "2017-06-04 21:45:56 -0700 PDT")
if err != nil {
t.Errorf("unable to parse time %q error: %s", "2017-06-04 21:45:56 -0700 PDT", err)
}
expectedOut := `Name: network-policy-1
Namespace: default
Created on: 2017-06-04 21:45:56 -0700 PDT
Labels: <none>
Annotations: <none>
Spec:
PodSelector: foo in (bar1,bar2),foo2 notin (bar1,bar2),id1=app1,id2=app2
Allowing ingress traffic:
To Port: 80/TCP
To Port: 82/TCP
From:
NamespaceSelector: id=ns1,id2=ns2
PodSelector: id=pod1,id2=pod2
From:
PodSelector: id=app2,id2=app3
From:
NamespaceSelector: id=app2,id2=app3
From:
NamespaceSelector: foo in (bar1,bar2),id=app2,id2=app3
From:
IPBlock:
CIDR: 192.168.0.0/16
Except: 192.168.3.0/24, 192.168.4.0/24
----------
To Port: <any> (traffic allowed to all ports)
From: <any> (traffic not restricted by source)
Allowing egress traffic:
<none> (Selected pods are isolated for egress connectivity)
Policy Types: Ingress, Egress
`
port80 := intstr.FromInt(80)
port82 := intstr.FromInt(82)
protoTCP := corev1.ProtocolTCP
versionedFake := fake.NewSimpleClientset(&networkingv1.NetworkPolicy{
ObjectMeta: metav1.ObjectMeta{
Name: "network-policy-1",
Namespace: "default",
CreationTimestamp: metav1.NewTime(expectedTime),
},
Spec: networkingv1.NetworkPolicySpec{
PodSelector: metav1.LabelSelector{
MatchLabels: map[string]string{
"id1": "app1",
"id2": "app2",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
{Key: "foo2", Operator: "NotIn", Values: []string{"bar1", "bar2"}},
},
},
Ingress: []networkingv1.NetworkPolicyIngressRule{
{
Ports: []networkingv1.NetworkPolicyPort{
{Port: &port80},
{Port: &port82, Protocol: &protoTCP},
},
From: []networkingv1.NetworkPolicyPeer{
{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "pod1",
"id2": "pod2",
},
},
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "ns1",
"id2": "ns2",
},
},
},
{
PodSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
},
},
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
},
},
{
NamespaceSelector: &metav1.LabelSelector{
MatchLabels: map[string]string{
"id": "app2",
"id2": "app3",
},
MatchExpressions: []metav1.LabelSelectorRequirement{
{Key: "foo", Operator: "In", Values: []string{"bar1", "bar2"}},
},
},
},
{
IPBlock: &networkingv1.IPBlock{
CIDR: "192.168.0.0/16",
Except: []string{"192.168.3.0/24", "192.168.4.0/24"},
},
},
},
},
{},
},
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress, networkingv1.PolicyTypeEgress},
},
})
d := NetworkPolicyDescriber{versionedFake}
out, err := d.Describe("default", "network-policy-1", describe.DescriberSettings{})
if err != nil {
t.Errorf("unexpected error: %s", err)
}
if out != expectedOut {
t.Errorf("want:\n%s\ngot:\n%s", expectedOut, out)
}
}
func TestDescribeServiceAccount(t *testing.T) {
fake := fake.NewSimpleClientset(&corev1.ServiceAccount{
ObjectMeta: metav1.ObjectMeta{