-
Notifications
You must be signed in to change notification settings - Fork 81
/
policy_rule_matcher.go
118 lines (103 loc) · 3.14 KB
/
policy_rule_matcher.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
package cmd
import (
rbac "k8s.io/api/rbac/v1"
"k8s.io/klog/v2"
)
// PolicyRuleMatcher wraps the Matches* methods.
//
// MatchesRole returns `true` if any PolicyRule defined by the given Role matches the specified Action, `false` otherwise.
//
// MatchesClusterRole returns `true` if any PolicyRule defined by the given ClusterRole matches the specified Action, `false` otherwise.
type PolicyRuleMatcher interface {
MatchesRole(role rbac.Role, action resolvedAction) bool
MatchesClusterRole(role rbac.ClusterRole, action resolvedAction) bool
}
type matcher struct {
}
// NewPolicyRuleMatcher constructs the default PolicyRuleMatcher.
func NewPolicyRuleMatcher() PolicyRuleMatcher {
return &matcher{}
}
func (m *matcher) MatchesRole(role rbac.Role, action resolvedAction) bool {
for _, rule := range role.Rules {
if !m.matches(rule, action) {
continue
}
klog.V(4).Infof("Role [%s] matches action filter? YES", role.Name)
return true
}
klog.V(4).Infof("Role [%s] matches action filter? NO", role.Name)
return false
}
func (m *matcher) MatchesClusterRole(role rbac.ClusterRole, action resolvedAction) bool {
for _, rule := range role.Rules {
if !m.matches(rule, action) {
continue
}
klog.V(4).Infof("ClusterRole [%s] matches action filter? YES", role.Name)
return true
}
klog.V(4).Infof("ClusterRole [%s] matches action filter? NO", role.Name)
return false
}
// matches returns `true` if the given PolicyRule matches the specified Action, `false` otherwise.
func (m *matcher) matches(rule rbac.PolicyRule, action resolvedAction) bool {
if action.NonResourceURL != "" {
return m.matchesVerb(rule, action.Verb) &&
m.matchesNonResourceURL(rule, action.NonResourceURL)
}
resource := action.gr.Resource
if action.SubResource != "" {
resource += "/" + action.SubResource
}
return m.matchesVerb(rule, action.Verb) &&
m.matchesResource(rule, resource) &&
m.matchesAPIGroup(rule, action.gr.Group) &&
m.matchesResourceName(rule, action.ResourceName)
}
func (m *matcher) matchesAPIGroup(rule rbac.PolicyRule, actionGroup string) bool {
for _, group := range rule.APIGroups {
if group == rbac.APIGroupAll || group == actionGroup {
return true
}
}
return false
}
func (m *matcher) matchesVerb(rule rbac.PolicyRule, actionVerb string) bool {
for _, verb := range rule.Verbs {
if verb == rbac.VerbAll || verb == actionVerb {
return true
}
}
return false
}
func (m *matcher) matchesResource(rule rbac.PolicyRule, actionResource string) bool {
for _, resource := range rule.Resources {
if resource == rbac.ResourceAll || resource == actionResource {
return true
}
}
return false
}
func (m *matcher) matchesResourceName(rule rbac.PolicyRule, actionResourceName string) bool {
if actionResourceName == "" && len(rule.ResourceNames) == 0 {
return true
}
if len(rule.ResourceNames) == 0 {
return true
}
for _, name := range rule.ResourceNames {
if name == actionResourceName {
return true
}
}
return false
}
func (m *matcher) matchesNonResourceURL(rule rbac.PolicyRule, actionNonResourceURL string) bool {
for _, URL := range rule.NonResourceURLs {
if URL == actionNonResourceURL {
return true
}
}
return false
}