summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorvincentgoat <linguohui1@huawei.com>2023-04-13 16:58:31 +0800
committervincentgoat <linguohui1@huawei.com>2023-05-29 21:28:21 +0800
commita2ac5d60e9a4405729af640c95eeeb35200d3c54 (patch)
tree68165401a4704a7f808659da5798d336dbd80d9f
parentudpate controller runtime vendor fake (diff)
downloadkubeedge-a2ac5d60e9a4405729af640c95eeeb35200d3c54.tar.gz
add vendor of K8s plugin auth
Signed-off-by: vincentgoat <linguohui1@huawei.com>
-rw-r--r--go.mod2
-rw-r--r--vendor/k8s.io/component-helpers/auth/rbac/validation/policy_comparator.go173
-rw-r--r--vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/internal_version_adapter.go39
-rw-r--r--vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go89
-rw-r--r--vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go368
-rw-r--r--vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/rbac.go225
-rw-r--r--vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/subject_locator.go123
-rw-r--r--vendor/modules.txt3
8 files changed, 1021 insertions, 1 deletions
diff --git a/go.mod b/go.mod
index a764770e5..6370a3251 100644
--- a/go.mod
+++ b/go.mod
@@ -58,6 +58,7 @@ require (
require (
github.com/pkg/errors v0.9.1
+ gopkg.in/square/go-jose.v2 v2.5.1
gopkg.in/yaml.v3 v3.0.1
)
@@ -246,7 +247,6 @@ require (
gopkg.in/gorp.v1 v1.7.2 // indirect
gopkg.in/inf.v0 v0.9.1 // indirect
gopkg.in/natefinch/lumberjack.v2 v2.0.0 // indirect
- gopkg.in/square/go-jose.v2 v2.5.1 // indirect
gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 // indirect
gopkg.in/tomb.v2 v2.0.0-20161208151619-d5d1b5820637 // indirect
gopkg.in/warnings.v0 v0.1.1 // indirect
diff --git a/vendor/k8s.io/component-helpers/auth/rbac/validation/policy_comparator.go b/vendor/k8s.io/component-helpers/auth/rbac/validation/policy_comparator.go
new file mode 100644
index 000000000..7a0268b5e
--- /dev/null
+++ b/vendor/k8s.io/component-helpers/auth/rbac/validation/policy_comparator.go
@@ -0,0 +1,173 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package validation
+
+import (
+ "strings"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+)
+
+// Covers determines whether or not the ownerRules cover the servantRules in terms of allowed actions.
+// It returns whether or not the ownerRules cover and a list of the rules that the ownerRules do not cover.
+func Covers(ownerRules, servantRules []rbacv1.PolicyRule) (bool, []rbacv1.PolicyRule) {
+ // 1. Break every servantRule into individual rule tuples: group, verb, resource, resourceName
+ // 2. Compare the mini-rules against each owner rule. Because the breakdown is down to the most atomic level, we're guaranteed that each mini-servant rule will be either fully covered or not covered by a single owner rule
+ // 3. Any left over mini-rules means that we are not covered and we have a nice list of them.
+ // TODO: it might be nice to collapse the list down into something more human readable
+
+ subrules := []rbacv1.PolicyRule{}
+ for _, servantRule := range servantRules {
+ subrules = append(subrules, BreakdownRule(servantRule)...)
+ }
+
+ uncoveredRules := []rbacv1.PolicyRule{}
+ for _, subrule := range subrules {
+ covered := false
+ for _, ownerRule := range ownerRules {
+ if ruleCovers(ownerRule, subrule) {
+ covered = true
+ break
+ }
+ }
+
+ if !covered {
+ uncoveredRules = append(uncoveredRules, subrule)
+ }
+ }
+
+ return (len(uncoveredRules) == 0), uncoveredRules
+}
+
+// BreadownRule takes a rule and builds an equivalent list of rules that each have at most one verb, one
+// resource, and one resource name
+func BreakdownRule(rule rbacv1.PolicyRule) []rbacv1.PolicyRule {
+ subrules := []rbacv1.PolicyRule{}
+ for _, group := range rule.APIGroups {
+ for _, resource := range rule.Resources {
+ for _, verb := range rule.Verbs {
+ if len(rule.ResourceNames) > 0 {
+ for _, resourceName := range rule.ResourceNames {
+ subrules = append(subrules, rbacv1.PolicyRule{APIGroups: []string{group}, Resources: []string{resource}, Verbs: []string{verb}, ResourceNames: []string{resourceName}})
+ }
+
+ } else {
+ subrules = append(subrules, rbacv1.PolicyRule{APIGroups: []string{group}, Resources: []string{resource}, Verbs: []string{verb}})
+ }
+
+ }
+ }
+ }
+
+ // Non-resource URLs are unique because they only combine with verbs.
+ for _, nonResourceURL := range rule.NonResourceURLs {
+ for _, verb := range rule.Verbs {
+ subrules = append(subrules, rbacv1.PolicyRule{NonResourceURLs: []string{nonResourceURL}, Verbs: []string{verb}})
+ }
+ }
+
+ return subrules
+}
+
+func has(set []string, ele string) bool {
+ for _, s := range set {
+ if s == ele {
+ return true
+ }
+ }
+ return false
+}
+
+func hasAll(set, contains []string) bool {
+ owning := make(map[string]struct{}, len(set))
+ for _, ele := range set {
+ owning[ele] = struct{}{}
+ }
+ for _, ele := range contains {
+ if _, ok := owning[ele]; !ok {
+ return false
+ }
+ }
+ return true
+}
+
+func resourceCoversAll(setResources, coversResources []string) bool {
+ // if we have a star or an exact match on all resources, then we match
+ if has(setResources, rbacv1.ResourceAll) || hasAll(setResources, coversResources) {
+ return true
+ }
+
+ for _, path := range coversResources {
+ // if we have an exact match, then we match.
+ if has(setResources, path) {
+ continue
+ }
+ // if we're not a subresource, then we definitely don't match. fail.
+ if !strings.Contains(path, "/") {
+ return false
+ }
+ tokens := strings.SplitN(path, "/", 2)
+ resourceToCheck := "*/" + tokens[1]
+ if !has(setResources, resourceToCheck) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func nonResourceURLsCoversAll(set, covers []string) bool {
+ for _, path := range covers {
+ covered := false
+ for _, owner := range set {
+ if nonResourceURLCovers(owner, path) {
+ covered = true
+ break
+ }
+ }
+ if !covered {
+ return false
+ }
+ }
+ return true
+}
+
+func nonResourceURLCovers(ownerPath, subPath string) bool {
+ if ownerPath == subPath {
+ return true
+ }
+ return strings.HasSuffix(ownerPath, "*") && strings.HasPrefix(subPath, strings.TrimRight(ownerPath, "*"))
+}
+
+// ruleCovers determines whether the ownerRule (which may have multiple verbs, resources, and resourceNames) covers
+// the subrule (which may only contain at most one verb, resource, and resourceName)
+func ruleCovers(ownerRule, subRule rbacv1.PolicyRule) bool {
+ verbMatches := has(ownerRule.Verbs, rbacv1.VerbAll) || hasAll(ownerRule.Verbs, subRule.Verbs)
+ groupMatches := has(ownerRule.APIGroups, rbacv1.APIGroupAll) || hasAll(ownerRule.APIGroups, subRule.APIGroups)
+ resourceMatches := resourceCoversAll(ownerRule.Resources, subRule.Resources)
+ nonResourceURLMatches := nonResourceURLsCoversAll(ownerRule.NonResourceURLs, subRule.NonResourceURLs)
+
+ resourceNameMatches := false
+
+ if len(subRule.ResourceNames) == 0 {
+ resourceNameMatches = (len(ownerRule.ResourceNames) == 0)
+ } else {
+ resourceNameMatches = (len(ownerRule.ResourceNames) == 0) || hasAll(ownerRule.ResourceNames, subRule.ResourceNames)
+ }
+
+ return verbMatches && groupMatches && resourceMatches && resourceNameMatches && nonResourceURLMatches
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/internal_version_adapter.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/internal_version_adapter.go
new file mode 100644
index 000000000..bfb57242d
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/internal_version_adapter.go
@@ -0,0 +1,39 @@
+/*
+Copyright 2018 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package validation
+
+import (
+ "context"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+ "k8s.io/kubernetes/pkg/apis/rbac"
+ rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
+)
+
+func ConfirmNoEscalationInternal(ctx context.Context, ruleResolver AuthorizationRuleResolver, inRules []rbac.PolicyRule) error {
+ rules := []rbacv1.PolicyRule{}
+ for i := range inRules {
+ v1Rule := rbacv1.PolicyRule{}
+ err := rbacv1helpers.Convert_rbac_PolicyRule_To_v1_PolicyRule(&inRules[i], &v1Rule, nil)
+ if err != nil {
+ return err
+ }
+ rules = append(rules, v1Rule)
+ }
+
+ return ConfirmNoEscalation(ctx, ruleResolver, rules)
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go
new file mode 100644
index 000000000..182657b1c
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/policy_compact.go
@@ -0,0 +1,89 @@
+/*
+Copyright 2017 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package validation
+
+import (
+ "reflect"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+)
+
+type simpleResource struct {
+ Group string
+ Resource string
+ ResourceNameExist bool
+ ResourceName string
+}
+
+// CompactRules combines rules that contain a single APIGroup/Resource, differ only by verb, and contain no other attributes.
+// this is a fast check, and works well with the decomposed "missing rules" list from a Covers check.
+func CompactRules(rules []rbacv1.PolicyRule) ([]rbacv1.PolicyRule, error) {
+ compacted := make([]rbacv1.PolicyRule, 0, len(rules))
+
+ simpleRules := map[simpleResource]*rbacv1.PolicyRule{}
+ for _, rule := range rules {
+ if resource, isSimple := isSimpleResourceRule(&rule); isSimple {
+ if existingRule, ok := simpleRules[resource]; ok {
+ // Add the new verbs to the existing simple resource rule
+ if existingRule.Verbs == nil {
+ existingRule.Verbs = []string{}
+ }
+ existingRule.Verbs = append(existingRule.Verbs, rule.Verbs...)
+ } else {
+ // Copy the rule to accumulate matching simple resource rules into
+ simpleRules[resource] = rule.DeepCopy()
+ }
+ } else {
+ compacted = append(compacted, rule)
+ }
+ }
+
+ // Once we've consolidated the simple resource rules, add them to the compacted list
+ for _, simpleRule := range simpleRules {
+ compacted = append(compacted, *simpleRule)
+ }
+
+ return compacted, nil
+}
+
+// isSimpleResourceRule returns true if the given rule contains verbs, a single resource, a single API group, at most one Resource Name, and no other values
+func isSimpleResourceRule(rule *rbacv1.PolicyRule) (simpleResource, bool) {
+ resource := simpleResource{}
+
+ // If we have "complex" rule attributes, return early without allocations or expensive comparisons
+ if len(rule.ResourceNames) > 1 || len(rule.NonResourceURLs) > 0 {
+ return resource, false
+ }
+ // If we have multiple api groups or resources, return early
+ if len(rule.APIGroups) != 1 || len(rule.Resources) != 1 {
+ return resource, false
+ }
+
+ // Test if this rule only contains APIGroups/Resources/Verbs/ResourceNames
+ simpleRule := &rbacv1.PolicyRule{APIGroups: rule.APIGroups, Resources: rule.Resources, Verbs: rule.Verbs, ResourceNames: rule.ResourceNames}
+ if !reflect.DeepEqual(simpleRule, rule) {
+ return resource, false
+ }
+
+ if len(rule.ResourceNames) == 0 {
+ resource = simpleResource{Group: rule.APIGroups[0], Resource: rule.Resources[0], ResourceNameExist: false}
+ } else {
+ resource = simpleResource{Group: rule.APIGroups[0], Resource: rule.Resources[0], ResourceNameExist: true, ResourceName: rule.ResourceNames[0]}
+ }
+
+ return resource, true
+}
diff --git a/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go
new file mode 100644
index 000000000..603f56afb
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/pkg/registry/rbac/validation/rule.go
@@ -0,0 +1,368 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package validation
+
+import (
+ "context"
+ "errors"
+ "fmt"
+ "strings"
+
+ "k8s.io/klog/v2"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/apimachinery/pkg/util/sets"
+ "k8s.io/apiserver/pkg/authentication/serviceaccount"
+ "k8s.io/apiserver/pkg/authentication/user"
+ genericapirequest "k8s.io/apiserver/pkg/endpoints/request"
+ "k8s.io/component-helpers/auth/rbac/validation"
+ rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
+)
+
+type AuthorizationRuleResolver interface {
+ // GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace
+ // of the role binding, the empty string if a cluster role binding.
+ GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
+
+ // RulesFor returns the list of rules that apply to a given user in a given namespace and error. If an error is returned, the slice of
+ // PolicyRules may not be complete, but it contains all retrievable rules. This is done because policy rules are purely additive and policy determinations
+ // can be made on the basis of those rules that are found.
+ RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error)
+
+ // VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace, and each error encountered resolving those rules.
+ // If visitor() returns false, visiting is short-circuited.
+ VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
+}
+
+// ConfirmNoEscalation determines if the roles for a given user in a given namespace encompass the provided role.
+func ConfirmNoEscalation(ctx context.Context, ruleResolver AuthorizationRuleResolver, rules []rbacv1.PolicyRule) error {
+ ruleResolutionErrors := []error{}
+
+ user, ok := genericapirequest.UserFrom(ctx)
+ if !ok {
+ return fmt.Errorf("no user on context")
+ }
+ namespace, _ := genericapirequest.NamespaceFrom(ctx)
+
+ ownerRules, err := ruleResolver.RulesFor(user, namespace)
+ if err != nil {
+ // As per AuthorizationRuleResolver contract, this may return a non fatal error with an incomplete list of policies. Log the error and continue.
+ klog.V(1).Infof("non-fatal error getting local rules for %v: %v", user, err)
+ ruleResolutionErrors = append(ruleResolutionErrors, err)
+ }
+
+ ownerRightsCover, missingRights := validation.Covers(ownerRules, rules)
+ if !ownerRightsCover {
+ compactMissingRights := missingRights
+ if compact, err := CompactRules(missingRights); err == nil {
+ compactMissingRights = compact
+ }
+
+ missingDescriptions := sets.NewString()
+ for _, missing := range compactMissingRights {
+ missingDescriptions.Insert(rbacv1helpers.CompactString(missing))
+ }
+
+ msg := fmt.Sprintf("user %q (groups=%q) is attempting to grant RBAC permissions not currently held:\n%s", user.GetName(), user.GetGroups(), strings.Join(missingDescriptions.List(), "\n"))
+ if len(ruleResolutionErrors) > 0 {
+ msg = msg + fmt.Sprintf("; resolution errors: %v", ruleResolutionErrors)
+ }
+
+ return errors.New(msg)
+ }
+ return nil
+}
+
+type DefaultRuleResolver struct {
+ roleGetter RoleGetter
+ roleBindingLister RoleBindingLister
+ clusterRoleGetter ClusterRoleGetter
+ clusterRoleBindingLister ClusterRoleBindingLister
+}
+
+func NewDefaultRuleResolver(roleGetter RoleGetter, roleBindingLister RoleBindingLister, clusterRoleGetter ClusterRoleGetter, clusterRoleBindingLister ClusterRoleBindingLister) *DefaultRuleResolver {
+ return &DefaultRuleResolver{roleGetter, roleBindingLister, clusterRoleGetter, clusterRoleBindingLister}
+}
+
+type RoleGetter interface {
+ GetRole(namespace, name string) (*rbacv1.Role, error)
+}
+
+type RoleBindingLister interface {
+ ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error)
+}
+
+type ClusterRoleGetter interface {
+ GetClusterRole(name string) (*rbacv1.ClusterRole, error)
+}
+
+type ClusterRoleBindingLister interface {
+ ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error)
+}
+
+func (r *DefaultRuleResolver) RulesFor(user user.Info, namespace string) ([]rbacv1.PolicyRule, error) {
+ visitor := &ruleAccumulator{}
+ r.VisitRulesFor(user, namespace, visitor.visit)
+ return visitor.rules, utilerrors.NewAggregate(visitor.errors)
+}
+
+type ruleAccumulator struct {
+ rules []rbacv1.PolicyRule
+ errors []error
+}
+
+func (r *ruleAccumulator) visit(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool {
+ if rule != nil {
+ r.rules = append(r.rules, *rule)
+ }
+ if err != nil {
+ r.errors = append(r.errors, err)
+ }
+ return true
+}
+
+func describeSubject(s *rbacv1.Subject, bindingNamespace string) string {
+ switch s.Kind {
+ case rbacv1.ServiceAccountKind:
+ if len(s.Namespace) > 0 {
+ return fmt.Sprintf("%s %q", s.Kind, s.Name+"/"+s.Namespace)
+ }
+ return fmt.Sprintf("%s %q", s.Kind, s.Name+"/"+bindingNamespace)
+ default:
+ return fmt.Sprintf("%s %q", s.Kind, s.Name)
+ }
+}
+
+type clusterRoleBindingDescriber struct {
+ binding *rbacv1.ClusterRoleBinding
+ subject *rbacv1.Subject
+}
+
+func (d *clusterRoleBindingDescriber) String() string {
+ return fmt.Sprintf("ClusterRoleBinding %q of %s %q to %s",
+ d.binding.Name,
+ d.binding.RoleRef.Kind,
+ d.binding.RoleRef.Name,
+ describeSubject(d.subject, ""),
+ )
+}
+
+type roleBindingDescriber struct {
+ binding *rbacv1.RoleBinding
+ subject *rbacv1.Subject
+}
+
+func (d *roleBindingDescriber) String() string {
+ return fmt.Sprintf("RoleBinding %q of %s %q to %s",
+ d.binding.Name+"/"+d.binding.Namespace,
+ d.binding.RoleRef.Kind,
+ d.binding.RoleRef.Name,
+ describeSubject(d.subject, d.binding.Namespace),
+ )
+}
+
+func (r *DefaultRuleResolver) VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool) {
+ if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
+ if !visitor(nil, nil, err) {
+ return
+ }
+ } else {
+ sourceDescriber := &clusterRoleBindingDescriber{}
+ for _, clusterRoleBinding := range clusterRoleBindings {
+ subjectIndex, applies := appliesTo(user, clusterRoleBinding.Subjects, "")
+ if !applies {
+ continue
+ }
+ rules, err := r.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
+ if err != nil {
+ if !visitor(nil, nil, err) {
+ return
+ }
+ continue
+ }
+ sourceDescriber.binding = clusterRoleBinding
+ sourceDescriber.subject = &clusterRoleBinding.Subjects[subjectIndex]
+ for i := range rules {
+ if !visitor(sourceDescriber, &rules[i], nil) {
+ return
+ }
+ }
+ }
+ }
+
+ if len(namespace) > 0 {
+ if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
+ if !visitor(nil, nil, err) {
+ return
+ }
+ } else {
+ sourceDescriber := &roleBindingDescriber{}
+ for _, roleBinding := range roleBindings {
+ subjectIndex, applies := appliesTo(user, roleBinding.Subjects, namespace)
+ if !applies {
+ continue
+ }
+ rules, err := r.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
+ if err != nil {
+ if !visitor(nil, nil, err) {
+ return
+ }
+ continue
+ }
+ sourceDescriber.binding = roleBinding
+ sourceDescriber.subject = &roleBinding.Subjects[subjectIndex]
+ for i := range rules {
+ if !visitor(sourceDescriber, &rules[i], nil) {
+ return
+ }
+ }
+ }
+ }
+ }
+}
+
+// GetRoleReferenceRules attempts to resolve the RoleBinding or ClusterRoleBinding.
+func (r *DefaultRuleResolver) GetRoleReferenceRules(roleRef rbacv1.RoleRef, bindingNamespace string) ([]rbacv1.PolicyRule, error) {
+ switch roleRef.Kind {
+ case "Role":
+ role, err := r.roleGetter.GetRole(bindingNamespace, roleRef.Name)
+ if err != nil {
+ return nil, err
+ }
+ return role.Rules, nil
+
+ case "ClusterRole":
+ clusterRole, err := r.clusterRoleGetter.GetClusterRole(roleRef.Name)
+ if err != nil {
+ return nil, err
+ }
+ return clusterRole.Rules, nil
+
+ default:
+ return nil, fmt.Errorf("unsupported role reference kind: %q", roleRef.Kind)
+ }
+}
+
+// appliesTo returns whether any of the bindingSubjects applies to the specified subject,
+// and if true, the index of the first subject that applies
+func appliesTo(user user.Info, bindingSubjects []rbacv1.Subject, namespace string) (int, bool) {
+ for i, bindingSubject := range bindingSubjects {
+ if appliesToUser(user, bindingSubject, namespace) {
+ return i, true
+ }
+ }
+ return 0, false
+}
+
+func has(set []string, ele string) bool {
+ for _, s := range set {
+ if s == ele {
+ return true
+ }
+ }
+ return false
+}
+
+func appliesToUser(user user.Info, subject rbacv1.Subject, namespace string) bool {
+ switch subject.Kind {
+ case rbacv1.UserKind:
+ return user.GetName() == subject.Name
+
+ case rbacv1.GroupKind:
+ return has(user.GetGroups(), subject.Name)
+
+ case rbacv1.ServiceAccountKind:
+ // default the namespace to namespace we're working in if its available. This allows rolebindings that reference
+ // SAs in th local namespace to avoid having to qualify them.
+ saNamespace := namespace
+ if len(subject.Namespace) > 0 {
+ saNamespace = subject.Namespace
+ }
+ if len(saNamespace) == 0 {
+ return false
+ }
+ // use a more efficient comparison for RBAC checking
+ return serviceaccount.MatchesUsername(saNamespace, subject.Name, user.GetName())
+ default:
+ return false
+ }
+}
+
+// NewTestRuleResolver returns a rule resolver from lists of role objects.
+func NewTestRuleResolver(roles []*rbacv1.Role, roleBindings []*rbacv1.RoleBinding, clusterRoles []*rbacv1.ClusterRole, clusterRoleBindings []*rbacv1.ClusterRoleBinding) (AuthorizationRuleResolver, *StaticRoles) {
+ r := StaticRoles{
+ roles: roles,
+ roleBindings: roleBindings,
+ clusterRoles: clusterRoles,
+ clusterRoleBindings: clusterRoleBindings,
+ }
+ return newMockRuleResolver(&r), &r
+}
+
+func newMockRuleResolver(r *StaticRoles) AuthorizationRuleResolver {
+ return NewDefaultRuleResolver(r, r, r, r)
+}
+
+// StaticRoles is a rule resolver that resolves from lists of role objects.
+type StaticRoles struct {
+ roles []*rbacv1.Role
+ roleBindings []*rbacv1.RoleBinding
+ clusterRoles []*rbacv1.ClusterRole
+ clusterRoleBindings []*rbacv1.ClusterRoleBinding
+}
+
+func (r *StaticRoles) GetRole(namespace, name string) (*rbacv1.Role, error) {
+ if len(namespace) == 0 {
+ return nil, errors.New("must provide namespace when getting role")
+ }
+ for _, role := range r.roles {
+ if role.Namespace == namespace && role.Name == name {
+ return role, nil
+ }
+ }
+ return nil, errors.New("role not found")
+}
+
+func (r *StaticRoles) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
+ for _, clusterRole := range r.clusterRoles {
+ if clusterRole.Name == name {
+ return clusterRole, nil
+ }
+ }
+ return nil, errors.New("clusterrole not found")
+}
+
+func (r *StaticRoles) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
+ if len(namespace) == 0 {
+ return nil, errors.New("must provide namespace when listing role bindings")
+ }
+
+ roleBindingList := []*rbacv1.RoleBinding{}
+ for _, roleBinding := range r.roleBindings {
+ if roleBinding.Namespace != namespace {
+ continue
+ }
+ // TODO(ericchiang): need to implement label selectors?
+ roleBindingList = append(roleBindingList, roleBinding)
+ }
+ return roleBindingList, nil
+}
+
+func (r *StaticRoles) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
+ return r.clusterRoleBindings, nil
+}
diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/rbac.go b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/rbac.go
new file mode 100644
index 000000000..4f25d1372
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/rbac.go
@@ -0,0 +1,225 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package rbac implements the authorizer.Authorizer interface using roles base access control.
+package rbac
+
+import (
+ "bytes"
+ "context"
+ "fmt"
+
+ "k8s.io/klog/v2"
+
+ rbacv1 "k8s.io/api/rbac/v1"
+ "k8s.io/apimachinery/pkg/labels"
+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/apiserver/pkg/authentication/user"
+ "k8s.io/apiserver/pkg/authorization/authorizer"
+ rbaclisters "k8s.io/client-go/listers/rbac/v1"
+ rbacv1helpers "k8s.io/kubernetes/pkg/apis/rbac/v1"
+ rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
+)
+
+type RequestToRuleMapper interface {
+ // RulesFor returns all known PolicyRules and any errors that happened while locating those rules.
+ // Any rule returned is still valid, since rules are deny by default. If you can pass with the rules
+ // supplied, you do not have to fail the request. If you cannot, you should indicate the error along
+ // with your denial.
+ RulesFor(subject user.Info, namespace string) ([]rbacv1.PolicyRule, error)
+
+ // VisitRulesFor invokes visitor() with each rule that applies to a given user in a given namespace,
+ // and each error encountered resolving those rules. Rule may be nil if err is non-nil.
+ // If visitor() returns false, visiting is short-circuited.
+ VisitRulesFor(user user.Info, namespace string, visitor func(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool)
+}
+
+type RBACAuthorizer struct {
+ authorizationRuleResolver RequestToRuleMapper
+}
+
+// authorizingVisitor short-circuits once allowed, and collects any resolution errors encountered
+type authorizingVisitor struct {
+ requestAttributes authorizer.Attributes
+
+ allowed bool
+ reason string
+ errors []error
+}
+
+func (v *authorizingVisitor) visit(source fmt.Stringer, rule *rbacv1.PolicyRule, err error) bool {
+ if rule != nil && RuleAllows(v.requestAttributes, rule) {
+ v.allowed = true
+ v.reason = fmt.Sprintf("RBAC: allowed by %s", source.String())
+ return false
+ }
+ if err != nil {
+ v.errors = append(v.errors, err)
+ }
+ return true
+}
+
+func (r *RBACAuthorizer) Authorize(ctx context.Context, requestAttributes authorizer.Attributes) (authorizer.Decision, string, error) {
+ ruleCheckingVisitor := &authorizingVisitor{requestAttributes: requestAttributes}
+
+ r.authorizationRuleResolver.VisitRulesFor(requestAttributes.GetUser(), requestAttributes.GetNamespace(), ruleCheckingVisitor.visit)
+ if ruleCheckingVisitor.allowed {
+ return authorizer.DecisionAllow, ruleCheckingVisitor.reason, nil
+ }
+
+ // Build a detailed log of the denial.
+ // Make the whole block conditional so we don't do a lot of string-building we won't use.
+ if klog.V(5).Enabled() {
+ var operation string
+ if requestAttributes.IsResourceRequest() {
+ b := &bytes.Buffer{}
+ b.WriteString(`"`)
+ b.WriteString(requestAttributes.GetVerb())
+ b.WriteString(`" resource "`)
+ b.WriteString(requestAttributes.GetResource())
+ if len(requestAttributes.GetAPIGroup()) > 0 {
+ b.WriteString(`.`)
+ b.WriteString(requestAttributes.GetAPIGroup())
+ }
+ if len(requestAttributes.GetSubresource()) > 0 {
+ b.WriteString(`/`)
+ b.WriteString(requestAttributes.GetSubresource())
+ }
+ b.WriteString(`"`)
+ if len(requestAttributes.GetName()) > 0 {
+ b.WriteString(` named "`)
+ b.WriteString(requestAttributes.GetName())
+ b.WriteString(`"`)
+ }
+ operation = b.String()
+ } else {
+ operation = fmt.Sprintf("%q nonResourceURL %q", requestAttributes.GetVerb(), requestAttributes.GetPath())
+ }
+
+ var scope string
+ if ns := requestAttributes.GetNamespace(); len(ns) > 0 {
+ scope = fmt.Sprintf("in namespace %q", ns)
+ } else {
+ scope = "cluster-wide"
+ }
+
+ klog.Infof("RBAC: no rules authorize user %q with groups %q to %s %s", requestAttributes.GetUser().GetName(), requestAttributes.GetUser().GetGroups(), operation, scope)
+ }
+
+ reason := ""
+ if len(ruleCheckingVisitor.errors) > 0 {
+ reason = fmt.Sprintf("RBAC: %v", utilerrors.NewAggregate(ruleCheckingVisitor.errors))
+ }
+ return authorizer.DecisionNoOpinion, reason, nil
+}
+
+func (r *RBACAuthorizer) RulesFor(user user.Info, namespace string) ([]authorizer.ResourceRuleInfo, []authorizer.NonResourceRuleInfo, bool, error) {
+ var (
+ resourceRules []authorizer.ResourceRuleInfo
+ nonResourceRules []authorizer.NonResourceRuleInfo
+ )
+
+ policyRules, err := r.authorizationRuleResolver.RulesFor(user, namespace)
+ for _, policyRule := range policyRules {
+ if len(policyRule.Resources) > 0 {
+ r := authorizer.DefaultResourceRuleInfo{
+ Verbs: policyRule.Verbs,
+ APIGroups: policyRule.APIGroups,
+ Resources: policyRule.Resources,
+ ResourceNames: policyRule.ResourceNames,
+ }
+ var resourceRule authorizer.ResourceRuleInfo = &r
+ resourceRules = append(resourceRules, resourceRule)
+ }
+ if len(policyRule.NonResourceURLs) > 0 {
+ r := authorizer.DefaultNonResourceRuleInfo{
+ Verbs: policyRule.Verbs,
+ NonResourceURLs: policyRule.NonResourceURLs,
+ }
+ var nonResourceRule authorizer.NonResourceRuleInfo = &r
+ nonResourceRules = append(nonResourceRules, nonResourceRule)
+ }
+ }
+ return resourceRules, nonResourceRules, false, err
+}
+
+func New(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister) *RBACAuthorizer {
+ authorizer := &RBACAuthorizer{
+ authorizationRuleResolver: rbacregistryvalidation.NewDefaultRuleResolver(
+ roles, roleBindings, clusterRoles, clusterRoleBindings,
+ ),
+ }
+ return authorizer
+}
+
+func RulesAllow(requestAttributes authorizer.Attributes, rules ...rbacv1.PolicyRule) bool {
+ for i := range rules {
+ if RuleAllows(requestAttributes, &rules[i]) {
+ return true
+ }
+ }
+
+ return false
+}
+
+func RuleAllows(requestAttributes authorizer.Attributes, rule *rbacv1.PolicyRule) bool {
+ if requestAttributes.IsResourceRequest() {
+ combinedResource := requestAttributes.GetResource()
+ if len(requestAttributes.GetSubresource()) > 0 {
+ combinedResource = requestAttributes.GetResource() + "/" + requestAttributes.GetSubresource()
+ }
+
+ return rbacv1helpers.VerbMatches(rule, requestAttributes.GetVerb()) &&
+ rbacv1helpers.APIGroupMatches(rule, requestAttributes.GetAPIGroup()) &&
+ rbacv1helpers.ResourceMatches(rule, combinedResource, requestAttributes.GetSubresource()) &&
+ rbacv1helpers.ResourceNameMatches(rule, requestAttributes.GetName())
+ }
+
+ return rbacv1helpers.VerbMatches(rule, requestAttributes.GetVerb()) &&
+ rbacv1helpers.NonResourceURLMatches(rule, requestAttributes.GetPath())
+}
+
+type RoleGetter struct {
+ Lister rbaclisters.RoleLister
+}
+
+func (g *RoleGetter) GetRole(namespace, name string) (*rbacv1.Role, error) {
+ return g.Lister.Roles(namespace).Get(name)
+}
+
+type RoleBindingLister struct {
+ Lister rbaclisters.RoleBindingLister
+}
+
+func (l *RoleBindingLister) ListRoleBindings(namespace string) ([]*rbacv1.RoleBinding, error) {
+ return l.Lister.RoleBindings(namespace).List(labels.Everything())
+}
+
+type ClusterRoleGetter struct {
+ Lister rbaclisters.ClusterRoleLister
+}
+
+func (g *ClusterRoleGetter) GetClusterRole(name string) (*rbacv1.ClusterRole, error) {
+ return g.Lister.Get(name)
+}
+
+type ClusterRoleBindingLister struct {
+ Lister rbaclisters.ClusterRoleBindingLister
+}
+
+func (l *ClusterRoleBindingLister) ListClusterRoleBindings() ([]*rbacv1.ClusterRoleBinding, error) {
+ return l.Lister.List(labels.Everything())
+}
diff --git a/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/subject_locator.go b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/subject_locator.go
new file mode 100644
index 000000000..cdd327e5b
--- /dev/null
+++ b/vendor/k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac/subject_locator.go
@@ -0,0 +1,123 @@
+/*
+Copyright 2016 The Kubernetes Authors.
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+// Package rbac implements the authorizer.Authorizer interface using roles base access control.
+package rbac
+
+import (
+ rbacv1 "k8s.io/api/rbac/v1"
+ utilerrors "k8s.io/apimachinery/pkg/util/errors"
+ "k8s.io/apiserver/pkg/authentication/user"
+ "k8s.io/apiserver/pkg/authorization/authorizer"
+ rbacregistryvalidation "k8s.io/kubernetes/pkg/registry/rbac/validation"
+)
+
+type RoleToRuleMapper interface {
+ // GetRoleReferenceRules attempts to resolve the role reference of a RoleBinding or ClusterRoleBinding. The passed namespace should be the namespace
+ // of the role binding, the empty string if a cluster role binding.
+ GetRoleReferenceRules(roleRef rbacv1.RoleRef, namespace string) ([]rbacv1.PolicyRule, error)
+}
+
+type SubjectLocator interface {
+ AllowedSubjects(attributes authorizer.Attributes) ([]rbacv1.Subject, error)
+}
+
+var _ = SubjectLocator(&SubjectAccessEvaluator{})
+
+type SubjectAccessEvaluator struct {
+ superUser string
+
+ roleBindingLister rbacregistryvalidation.RoleBindingLister
+ clusterRoleBindingLister rbacregistryvalidation.ClusterRoleBindingLister
+ roleToRuleMapper RoleToRuleMapper
+}
+
+func NewSubjectAccessEvaluator(roles rbacregistryvalidation.RoleGetter, roleBindings rbacregistryvalidation.RoleBindingLister, clusterRoles rbacregistryvalidation.ClusterRoleGetter, clusterRoleBindings rbacregistryvalidation.ClusterRoleBindingLister, superUser string) *SubjectAccessEvaluator {
+ subjectLocator := &SubjectAccessEvaluator{
+ superUser: superUser,
+ roleBindingLister: roleBindings,
+ clusterRoleBindingLister: clusterRoleBindings,
+ roleToRuleMapper: rbacregistryvalidation.NewDefaultRuleResolver(
+ roles, roleBindings, clusterRoles, clusterRoleBindings,
+ ),
+ }
+ return subjectLocator
+}
+
+// AllowedSubjects returns the subjects that can perform an action and any errors encountered while computing the list.
+// It is possible to have both subjects and errors returned if some rolebindings couldn't be resolved, but others could be.
+func (r *SubjectAccessEvaluator) AllowedSubjects(requestAttributes authorizer.Attributes) ([]rbacv1.Subject, error) {
+ subjects := []rbacv1.Subject{{Kind: rbacv1.GroupKind, APIGroup: rbacv1.GroupName, Name: user.SystemPrivilegedGroup}}
+ if len(r.superUser) > 0 {
+ subjects = append(subjects, rbacv1.Subject{Kind: rbacv1.UserKind, APIGroup: rbacv1.GroupName, Name: r.superUser})
+ }
+ errorlist := []error{}
+
+ if clusterRoleBindings, err := r.clusterRoleBindingLister.ListClusterRoleBindings(); err != nil {
+ errorlist = append(errorlist, err)
+
+ } else {
+ for _, clusterRoleBinding := range clusterRoleBindings {
+ rules, err := r.roleToRuleMapper.GetRoleReferenceRules(clusterRoleBinding.RoleRef, "")
+ if err != nil {
+ // if we have an error, just keep track of it and keep processing. Since rules are additive,
+ // missing a reference is bad, but we can continue with other rolebindings and still have a list
+ // that does not contain any invalid values
+ errorlist = append(errorlist, err)
+ }
+ if RulesAllow(requestAttributes, rules...) {
+ subjects = append(subjects, clusterRoleBinding.Subjects...)
+ }
+ }
+ }
+
+ if namespace := requestAttributes.GetNamespace(); len(namespace) > 0 {
+ if roleBindings, err := r.roleBindingLister.ListRoleBindings(namespace); err != nil {
+ errorlist = append(errorlist, err)
+
+ } else {
+ for _, roleBinding := range roleBindings {
+ rules, err := r.roleToRuleMapper.GetRoleReferenceRules(roleBinding.RoleRef, namespace)
+ if err != nil {
+ // if we have an error, just keep track of it and keep processing. Since rules are additive,
+ // missing a reference is bad, but we can continue with other rolebindings and still have a list
+ // that does not contain any invalid values
+ errorlist = append(errorlist, err)
+ }
+ if RulesAllow(requestAttributes, rules...) {
+ subjects = append(subjects, roleBinding.Subjects...)
+ }
+ }
+ }
+ }
+
+ dedupedSubjects := []rbacv1.Subject{}
+ for _, subject := range subjects {
+ found := false
+ for _, curr := range dedupedSubjects {
+ if curr == subject {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ dedupedSubjects = append(dedupedSubjects, subject)
+ }
+ }
+
+ return subjects, utilerrors.NewAggregate(errorlist)
+}
diff --git a/vendor/modules.txt b/vendor/modules.txt
index c9efbeb0e..ab6d0cb47 100644
--- a/vendor/modules.txt
+++ b/vendor/modules.txt
@@ -1989,6 +1989,7 @@ k8s.io/component-base/version/verflag
# k8s.io/component-helpers v0.0.0 => github.com/kubeedge/kubernetes/staging/src/k8s.io/component-helpers v1.23.15-kubeedge1
## explicit; go 1.16
k8s.io/component-helpers/apimachinery/lease
+k8s.io/component-helpers/auth/rbac/validation
k8s.io/component-helpers/node/util
k8s.io/component-helpers/node/util/sysctl
k8s.io/component-helpers/scheduling/corev1
@@ -2320,6 +2321,7 @@ k8s.io/kubernetes/pkg/proxy/metaproxier
k8s.io/kubernetes/pkg/proxy/metrics
k8s.io/kubernetes/pkg/proxy/util
k8s.io/kubernetes/pkg/proxy/util/iptables
+k8s.io/kubernetes/pkg/registry/rbac/validation
k8s.io/kubernetes/pkg/scheduler/apis/config
k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta2
k8s.io/kubernetes/pkg/scheduler/apis/config/v1beta3
@@ -2389,6 +2391,7 @@ k8s.io/kubernetes/pkg/volume/util/volumepathhandler
k8s.io/kubernetes/pkg/volume/validation
k8s.io/kubernetes/pkg/windows/service
k8s.io/kubernetes/plugin/pkg/admission/serviceaccount
+k8s.io/kubernetes/plugin/pkg/auth/authorizer/rbac
k8s.io/kubernetes/test/e2e/apps
k8s.io/kubernetes/test/e2e/auth
k8s.io/kubernetes/test/e2e/common