1
16
17
18 package rbac
19
20 import (
21 "bytes"
22 "context"
23 "fmt"
24
25 "k8s.io/klog/v2"
26
27 rbacv1 "k8s.io/api/rbac/v1"
28 "k8s.io/apimachinery/pkg/labels"
29 utilerrors "k8s.io/apimachinery/pkg/util/errors"
30 "k8s.io/apiserver/pkg/authentication/user"
31 "k8s.io/apiserver/pkg/authorization/authorizer"
32 rbaclisters "k8s.io/client-go/listers/rbac/v1"
33 rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
34 rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
35 )
36
37 type RequestToRuleMapper interface {
38
39
40
41
42 RulesFor(subject user.Info, namespace string) ([]rbacv1.PolicyRule, error)
43
44
45
46
47 VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
48 }
49
50 type RBACAuthorizer struct {
51 authorizationRuleResolver RequestToRuleMapper
52 }
53
54
55 type authorizingVisitor struct {
56 requestAttributes authorizer.Attributes
57
58 allowed bool
59 reason string
60 errors []error
61 }
62
63 func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool {
64 if rule != nil && RuleAllows(v.requestAttributes, rule) {
65 v.allowed = true
66 v.reason = fmt.Sprintf("RBAC: allowed by %s", source.String())
67 return false
68 }
69 if err != nil {
70 v.errors = append(v.errors, err)
71 }
72 return true
73 }
74
75 func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
76 ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
77
78 r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
79 if ruleCheckingVisitor.allowed {
80 return authorizer.DecisionAllow, ruleCheckingVisitor.reason, nil
81 }
82
83
84
85 if klogV := klog.V(5); klogV.Enabled() {
86 var operation string
87 if requestAttributes.IsResourceRequest() {
88 b := &bytes.Buffer{}
89 b.WriteString(`"`)
90 b.WriteString(requestAttributes.GetVerb())
91 b.WriteString(`" resource "`)
92 b.WriteString(requestAttributes.GetResource())
93 if len(requestAttributes.GetAPIGroup()) > 0 {
94 b.WriteString(`.`)
95 b.WriteString(requestAttributes.GetAPIGroup())
96 }
97 if len(requestAttributes.GetSubresource()) > 0 {
98 b.WriteString(`/`)
99 b.WriteString(requestAttributes.GetSubresource())
100 }
101 b.WriteString(`"`)
102 if len(requestAttributes.GetName()) > 0 {
103 b.WriteString(` named "`)
104 b.WriteString(requestAttributes.GetName())
105 b.WriteString(`"`)
106 }
107 operation = b.String()
108 } else {
109 operation = fmt.Sprintf("%q nonResourceURL %q", requestAttributes.GetVerb(), requestAttributes.GetPath())
110 }
111
112 var scope string
113 if ns := requestAttributes.GetNamespace(); len(ns) > 0 {
114 scope = fmt.Sprintf("in namespace %q", ns)
115 } else {
116 scope = "cluster-wide"
117 }
118
119 klogV.Infof("RBAC: no rules authorize user %q with groups %q to %s %s", requestAttributes.GetUser().GetName(), requestAttributes.GetUser().GetGroups(), operation, scope)
120 }
121
122 reason := ""
123 if len(ruleCheckingVisitor.errors) > 0 {
124 reason = fmt.Sprintf("RBAC: %v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
125 }
126 return authorizer.DecisionNoOpinion, reason, nil
127 }
128
129 func (r *RBACAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
130 var (
131 resourceRules []authorizer.ResourceRuleInfo
132 nonResourceRules []authorizer.NonResourceRuleInfo
133 )
134
135 policyRules, err := r.authorizationRuleResolver.RulesFor(user, namespace)
136 for _, policyRule := range policyRules {
137 if len(policyRule.Resources) > 0 {
138 r := authorizer.DefaultResourceRuleInfo{
139 Verbs: policyRule.Verbs,
140 APIGroups: policyRule.APIGroups,
141 Resources: policyRule.Resources,
142 ResourceNames: policyRule.ResourceNames,
143 }
144 var resourceRule authorizer.ResourceRuleInfo = &r
145 resourceRules = append(resourceRules, resourceRule)
146 }
147 if len(policyRule.NonResourceURLs) > 0 {
148 r := authorizer.DefaultNonResourceRuleInfo{
149 Verbs: policyRule.Verbs,
150 NonResourceURLs: policyRule.NonResourceURLs,
151 }
152 var nonResourceRule authorizer.NonResourceRuleInfo = &r
153 nonResourceRules = append(nonResourceRules, nonResourceRule)
154 }
155 }
156 return resourceRules, nonResourceRules, false, err
157 }
158
159 func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
160 authorizer := &RBACAuthorizer{
161 authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
162 roles, roleBindings, clusterRoles, clusterRoleBindings,
163 ),
164 }
165 return authorizer
166 }
167
168 func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbacv1.PolicyRule) bool {
169 for i := range rules {
170 if RuleAllows(requestAttributes, &rules[i]) {
171 return true
172 }
173 }
174
175 return false
176 }
177
178 func RuleAllows(requestAttributes authorizer.Attributes, rule *rbacv1.PolicyRule) bool {
179 if requestAttributes.IsResourceRequest() {
180 combinedResource := requestAttributes.GetResource()
181 if len(requestAttributes.GetSubresource()) > 0 {
182 combinedResource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
183 }
184
185 return rbacv1helpers.VerbMatches(rule, requestAttributes.GetVerb()) &&
186 rbacv1helpers.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
187 rbacv1helpers.ResourceMatches(rule, combinedResource, requestAttributes.GetSubresource()) &&
188 rbacv1helpers.ResourceNameMatches(rule, requestAttributes.GetName())
189 }
190
191 return rbacv1helpers.VerbMatches(rule, requestAttributes.GetVerb()) &&
192 rbacv1helpers.NonResourceURLMatches(rule, requestAttributes.GetPath())
193 }
194
195 type RoleGetter struct {
196 Lister rbaclisters.RoleLister
197 }
198
199 func (g *RoleGetter) GetRole(namespace, name string) (*rbacv1.Role, error) {
200 return g.Lister.Roles(namespace).Get(name)
201 }
202
203 type RoleBindingLister struct {
204 Lister rbaclisters.RoleBindingLister
205 }
206
207 func (l *RoleBindingLister) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
208 return l.Lister.RoleBindings(namespace).List(labels.Everything())
209 }
210
211 type ClusterRoleGetter struct {
212 Lister rbaclisters.ClusterRoleLister
213 }
214
215 func (g *ClusterRoleGetter) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
216 return g.Lister.Get(name)
217 }
218
219 type ClusterRoleBindingLister struct {
220 Lister rbaclisters.ClusterRoleBindingLister
221 }
222
223 func (l *ClusterRoleBindingLister) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
224 return l.Lister.List(labels.Everything())
225 }
226
View as plain text