Skip to content

Commit a8b203d

Browse files
authored
Merge pull request #240 from huntergregory/fix-211
[Policy Assistant] fix: npv1 deny-all simulation
2 parents a5e3d29 + 62767e2 commit a8b203d

File tree

6 files changed

+109
-9
lines changed

6 files changed

+109
-9
lines changed

cmd/policy-assistant/pkg/matcher/builder.go

+8
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ func BuildTarget(netpol *networkingv1.NetworkPolicy) (*Target, *Target) {
8181
}
8282

8383
func BuildIngressMatcher(policyNamespace string, ingresses []networkingv1.NetworkPolicyIngressRule) []PeerMatcher {
84+
if len(ingresses) == 0 {
85+
return []PeerMatcher{&NoMatcher{}}
86+
}
87+
8488
var matchers []PeerMatcher
8589
for _, ingress := range ingresses {
8690
matchers = append(matchers, BuildPeerMatcher(policyNamespace, ingress.Ports, ingress.From)...)
@@ -89,6 +93,10 @@ func BuildIngressMatcher(policyNamespace string, ingresses []networkingv1.Networ
8993
}
9094

9195
func BuildEgressMatcher(policyNamespace string, egresses []networkingv1.NetworkPolicyEgressRule) []PeerMatcher {
96+
if len(egresses) == 0 {
97+
return []PeerMatcher{&NoMatcher{}}
98+
}
99+
92100
var matchers []PeerMatcher
93101
for _, egress := range egresses {
94102
matchers = append(matchers, BuildPeerMatcher(policyNamespace, egress.Ports, egress.To)...)

cmd/policy-assistant/pkg/matcher/explain.go

+11-8
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,12 @@ package matcher
22

33
import (
44
"fmt"
5+
"strings"
6+
57
"github.com/mattfenwick/collections/pkg/json"
68
"github.com/mattfenwick/collections/pkg/slice"
79
"golang.org/x/exp/slices"
810
v1 "k8s.io/api/core/v1"
9-
"strings"
1011

1112
"github.com/mattfenwick/cyclonus/pkg/kube"
1213
"github.com/olekukonko/tablewriter"
@@ -80,23 +81,25 @@ func (s *SliceBuilder) TargetsTableLines(targets []*Target, isIngress bool) {
8081
rules := strings.Join(sourceRulesStrings, "\n")
8182
s.Prefix = []string{ruleType, target.TargetString(), rules}
8283

83-
if len(target.Peers) == 0 {
84-
s.Append("no pods, no ips", "NPv1: All peers allowed", "no ports, no protocols")
85-
continue
84+
if len(target.Peers) == 1 {
85+
if _, ok := target.Peers[0].(*NoMatcher); ok {
86+
s.Append("no peers", "NPv1:\n Allow any peers", "none")
87+
continue
88+
}
8689
}
8790

8891
peers := groupAnbAndBanp(target.Peers)
8992
for _, p := range slice.SortOn(func(p PeerMatcher) string { return json.MustMarshalToString(p) }, peers) {
9093
switch t := p.(type) {
9194
case *AllPeersMatcher:
92-
s.Append("all pods, all ips", "NPv1: All peers allowed", "all ports, all protocols")
95+
s.Append("all pods, all ips", "NPv1:\n Allow any peers", "all ports, all protocols")
9396
case *PortsForAllPeersMatcher:
9497
pps := PortMatcherTableLines(t.Port, NetworkPolicyV1)
95-
s.Append("all pods, all ips", "NPv1: All peers allowed", strings.Join(pps, "\n"))
98+
s.Append("all pods, all ips", "NPv1:\n Allow any peers", strings.Join(pps, "\n"))
9699
case *IPPeerMatcher:
97100
s.IPPeerMatcherTableLines(t)
98101
case *PodPeerMatcher:
99-
s.Append(resolveSubject(t), "NPv1: All peers allowed", strings.Join(PortMatcherTableLines(t.Port, NewV1Effect(true).PolicyKind), "\n"))
102+
s.Append(resolveSubject(t), "NPv1:\n Allow any peers", strings.Join(PortMatcherTableLines(t.Port, NewV1Effect(true).PolicyKind), "\n"))
100103
case *peerProtocolGroup:
101104
s.peerProtocolGroupTableLines(t)
102105
default:
@@ -110,7 +113,7 @@ func (s *SliceBuilder) TargetsTableLines(targets []*Target, isIngress bool) {
110113
func (s *SliceBuilder) IPPeerMatcherTableLines(ip *IPPeerMatcher) {
111114
peer := ip.IPBlock.CIDR + "\n" + fmt.Sprintf("except %+v", ip.IPBlock.Except)
112115
pps := PortMatcherTableLines(ip.Port, NetworkPolicyV1)
113-
s.Append(peer, "NPv1: All peers allowed", strings.Join(pps, "\n"))
116+
s.Append(peer, "NPv1:\n Allow any peers", strings.Join(pps, "\n"))
114117
}
115118

116119
func (s *SliceBuilder) peerProtocolGroupTableLines(t *peerProtocolGroup) {

cmd/policy-assistant/pkg/matcher/peermatcher.go

+9-1
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,9 @@ These are the original PeerMatcher implementations made for v1 NetPol:
1818
- PortsForAllPeersMatcher
1919
- IPPeerMatcher
2020
- PodPeerMatcher
21+
- NoMatcher
2122
22-
All PeerMatcher implementations (except AllPeersMatcher) use a PortMatcher.
23+
All PeerMatcher implementations (except AllPeersMatcher and NoMatcher) use a PortMatcher.
2324
If the traffic doesn't match the port matcher, then Matches() will be false.
2425
2526
Now we also have PeerMatcherAdmin, a wrapper for PodPeerMatcher to model ANP and BANP.
@@ -29,6 +30,13 @@ type PeerMatcher interface {
2930
Matches(subject, peer *TrafficPeer, portInt int, portName string, protocol v1.Protocol) bool
3031
}
3132

33+
// NoMatcher matches no traffic.
34+
type NoMatcher struct{}
35+
36+
func (p *NoMatcher) Matches(subject, peer *TrafficPeer, portInt int, portName string, protocol v1.Protocol) bool {
37+
return false
38+
}
39+
3240
// AllPeerMatcher matches all pod to pod traffic.
3341
type AllPeersMatcher struct{}
3442

cmd/policy-assistant/pkg/matcher/simplifier.go

+18
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,22 @@ func SimplifyV1(matchers []PeerMatcher) []PeerMatcher {
3333
}
3434
}
3535

36+
if len(v1Matchers) == 0 {
37+
return nil
38+
}
39+
40+
onlyNoMatchers := true
41+
for _, matcher := range v1Matchers {
42+
if _, ok := matcher.(*NoMatcher); !ok {
43+
onlyNoMatchers = false
44+
break
45+
}
46+
}
47+
48+
if onlyNoMatchers {
49+
return []PeerMatcher{&NoMatcher{}}
50+
}
51+
3652
matchesAll := false
3753
var portsForAllPeersMatchers []*PortsForAllPeersMatcher
3854
var ips []*IPPeerMatcher
@@ -47,6 +63,8 @@ func SimplifyV1(matchers []PeerMatcher) []PeerMatcher {
4763
ips = append(ips, a)
4864
case *PodPeerMatcher:
4965
pods = append(pods, a)
66+
case *NoMatcher:
67+
// nothing to do
5068
default:
5169
panic(errors.Errorf("invalid matcher type %T", matcher))
5270
}

cmd/policy-assistant/pkg/matcher/simplifier_tests.go

+43
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,49 @@ func RunSimplifierTests() {
109109
}
110110
Expect(Simplify([]PeerMatcher{dns, somePod})).To(Equal([]PeerMatcher{dns, somePod}))
111111
})
112+
113+
It("should simplify no matchers to one no matcher", func() {
114+
no1 := &NoMatcher{}
115+
no2 := &NoMatcher{}
116+
117+
Expect(Simplify([]PeerMatcher{no1, no2})).To(Equal([]PeerMatcher{&NoMatcher{}}))
118+
})
119+
120+
It("ignore no matchers amongst others", func() {
121+
no1 := &NoMatcher{}
122+
123+
Expect(Simplify([]PeerMatcher{no1, all, allOnTCP80, ip, allPodsAllPorts, allPodsTCP103})).To(Equal([]PeerMatcher{all}))
124+
})
125+
126+
It("don't simplify (b)anp", func() {
127+
anpDenyAll := &PeerMatcherAdmin{
128+
PodPeerMatcher: &PodPeerMatcher{
129+
Namespace: &AllNamespaceMatcher{},
130+
Pod: &AllPodMatcher{},
131+
Port: &AllPortMatcher{},
132+
},
133+
effectFromMatch: Effect{
134+
PolicyKind: AdminNetworkPolicy,
135+
Priority: 5,
136+
Verdict: Deny,
137+
},
138+
Name: "anp",
139+
}
140+
banpAllowAll := &PeerMatcherAdmin{
141+
PodPeerMatcher: &PodPeerMatcher{
142+
Namespace: &AllNamespaceMatcher{},
143+
Pod: &AllPodMatcher{},
144+
Port: &AllPortMatcher{},
145+
},
146+
effectFromMatch: Effect{
147+
PolicyKind: BaselineAdminNetworkPolicy,
148+
Verdict: Allow,
149+
},
150+
Name: "banp",
151+
}
152+
Expect(Simplify([]PeerMatcher{all, allOnTCP80, ip, allPodsAllPorts, banpAllowAll, allPodsTCP103, anpDenyAll})).To(Equal([]PeerMatcher{banpAllowAll, anpDenyAll, all}))
153+
154+
})
112155
})
113156

114157
Describe("Port Simplifier", func() {

cmd/policy-assistant/test/integration/integration_test.go

+20
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,26 @@ type flow struct {
5757

5858
func TestNetPolV1Connectivity(t *testing.T) {
5959
tests := []connectivityTest{
60+
{
61+
name: "deny all",
62+
defaultIngressBehavior: probe.ConnectivityBlocked,
63+
defaultEgressBehavior: probe.ConnectivityAllowed,
64+
args: args{
65+
resources: getResources(t, []string{"x"}, []string{"a", "b"}, []int{80}, []v1.Protocol{v1.ProtocolTCP}),
66+
netpols: []*networkingv1.NetworkPolicy{
67+
{
68+
ObjectMeta: metav1.ObjectMeta{
69+
Namespace: "x",
70+
Name: "base",
71+
},
72+
Spec: networkingv1.NetworkPolicySpec{
73+
PodSelector: metav1.LabelSelector{},
74+
PolicyTypes: []networkingv1.PolicyType{networkingv1.PolicyTypeIngress},
75+
},
76+
},
77+
},
78+
},
79+
},
6080
{
6181
name: "ingress port allowed",
6282
defaultIngressBehavior: probe.ConnectivityAllowed,

0 commit comments

Comments
 (0)