feat: kubesphere 4.0 (#6115)

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

* feat: kubesphere 4.0

Signed-off-by: ci-bot <ci-bot@kubesphere.io>

---------

Signed-off-by: ci-bot <ci-bot@kubesphere.io>
Co-authored-by: ks-ci-bot <ks-ci-bot@example.com>
Co-authored-by: joyceliu <joyceliu@yunify.com>
This commit is contained in:
KubeSphere CI Bot
2024-09-06 11:05:52 +08:00
committed by GitHub
parent b5015ec7b9
commit 447a51f08b
8557 changed files with 546695 additions and 1146174 deletions

View File

@@ -0,0 +1,84 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
)
type ClusterRoleRuleOwner struct {
ClusterRole *iamv1beta1.ClusterRole
}
func (c ClusterRoleRuleOwner) GetRuleOwnerScope() string {
return iamv1beta1.ScopeCluster
}
func (c ClusterRoleRuleOwner) GetObject() runtime.Object {
return c.ClusterRole
}
func (c ClusterRoleRuleOwner) GetNamespace() string {
return c.ClusterRole.Namespace
}
func (c ClusterRoleRuleOwner) GetName() string {
return c.ClusterRole.Name
}
func (c ClusterRoleRuleOwner) GetLabels() map[string]string {
return c.ClusterRole.Labels
}
func (c ClusterRoleRuleOwner) SetLabels(label map[string]string) {
c.ClusterRole.Labels = label
}
func (c ClusterRoleRuleOwner) GetAnnotations() map[string]string {
return c.ClusterRole.Annotations
}
func (c ClusterRoleRuleOwner) SetAnnotations(annotation map[string]string) {
c.ClusterRole.Annotations = annotation
}
func (c ClusterRoleRuleOwner) GetRules() []rbacv1.PolicyRule {
return c.ClusterRole.Rules
}
func (c ClusterRoleRuleOwner) SetRules(rules []rbacv1.PolicyRule) {
c.ClusterRole.Rules = rules
}
func (c ClusterRoleRuleOwner) GetAggregationRule() *iamv1beta1.AggregationRoleTemplates {
return c.ClusterRole.AggregationRoleTemplates
}
func (c ClusterRoleRuleOwner) SetAggregationRule(aggregationRoleTemplates *iamv1beta1.AggregationRoleTemplates) {
c.ClusterRole.AggregationRoleTemplates = aggregationRoleTemplates
}
func (c ClusterRoleRuleOwner) GetRegoPolicy() string {
if c.ClusterRole.ObjectMeta.Annotations != nil {
return c.ClusterRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation]
}
return ""
}
func (c ClusterRoleRuleOwner) SetRegoPolicy(rego string) {
if c.ClusterRole.ObjectMeta.Annotations == nil {
c.ClusterRole.ObjectMeta.Annotations = make(map[string]string)
}
c.ClusterRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation] = rego
}
func (c ClusterRoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return ClusterRoleRuleOwner{ClusterRole: c.ClusterRole.DeepCopy()}
}
var _ RuleOwner = ClusterRoleRuleOwner{}

View File

@@ -0,0 +1,84 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
)
type GlobalRoleRuleOwner struct {
GlobalRole *iamv1beta1.GlobalRole
}
func (g GlobalRoleRuleOwner) GetRuleOwnerScope() string {
return iamv1beta1.ScopeGlobal
}
func (g GlobalRoleRuleOwner) GetObject() runtime.Object {
return g.GlobalRole
}
func (g GlobalRoleRuleOwner) GetNamespace() string {
return ""
}
func (g GlobalRoleRuleOwner) GetName() string {
return g.GlobalRole.Name
}
func (g GlobalRoleRuleOwner) GetLabels() map[string]string {
return g.GlobalRole.Labels
}
func (g GlobalRoleRuleOwner) SetLabels(m map[string]string) {
g.GlobalRole.Labels = m
}
func (g GlobalRoleRuleOwner) GetAnnotations() map[string]string {
return g.GlobalRole.Annotations
}
func (g GlobalRoleRuleOwner) SetAnnotations(m map[string]string) {
g.GlobalRole.Annotations = m
}
func (g GlobalRoleRuleOwner) GetRules() []rbacv1.PolicyRule {
return g.GlobalRole.Rules
}
func (g GlobalRoleRuleOwner) SetRules(rules []rbacv1.PolicyRule) {
g.GlobalRole.Rules = rules
}
func (g GlobalRoleRuleOwner) GetAggregationRule() *iamv1beta1.AggregationRoleTemplates {
return g.GlobalRole.AggregationRoleTemplates
}
func (g GlobalRoleRuleOwner) SetAggregationRule(aggregationRoleTemplates *iamv1beta1.AggregationRoleTemplates) {
g.GlobalRole.AggregationRoleTemplates = aggregationRoleTemplates
}
func (g GlobalRoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return GlobalRoleRuleOwner{GlobalRole: g.GlobalRole.DeepCopy()}
}
func (g GlobalRoleRuleOwner) GetRegoPolicy() string {
if g.GlobalRole.ObjectMeta.Annotations != nil {
return g.GlobalRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation]
}
return ""
}
func (g GlobalRoleRuleOwner) SetRegoPolicy(rego string) {
if g.GlobalRole.ObjectMeta.Annotations == nil {
g.GlobalRole.ObjectMeta.Annotations = make(map[string]string)
}
g.GlobalRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation] = rego
}
var _ RuleOwner = GlobalRoleRuleOwner{}

View File

@@ -0,0 +1,305 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
"context"
"github.com/go-logr/logr"
"github.com/open-policy-agent/opa/ast"
corev1 "k8s.io/api/core/v1"
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/api/errors"
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/labels"
"k8s.io/apimachinery/pkg/types"
"k8s.io/client-go/tools/record"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
"sigs.k8s.io/controller-runtime/pkg/client"
"kubesphere.io/kubesphere/pkg/utils/sliceutil"
)
const defaultRegoFileName = "authz.rego"
const (
AggregateRoleTemplateFailed = "AggregateRoleTemplateFailed"
MessageResourceSynced = "Aggregating roleTemplates successfully"
)
type Helper struct {
client.Client
}
func NewHelper(c client.Client) *Helper {
return &Helper{c}
}
func (h *Helper) aggregateRoleTemplateRule(roleTemplates []iamv1beta1.RoleTemplate) ([]rbacv1.PolicyRule, []string, error) {
rules := []rbacv1.PolicyRule{}
newTemplateNames := []string{}
for _, rt := range roleTemplates {
newTemplateNames = append(newTemplateNames, rt.Name)
for _, rule := range rt.Spec.Rules {
if !ruleExists(rules, rule) {
rules = append(rules, rule)
}
}
}
return rules, newTemplateNames, nil
}
func (h *Helper) aggregateRoleTemplateRegoPolicy(roleTemplates []iamv1beta1.RoleTemplate) (string, error) {
mergedPolicy := &ast.Module{
Rules: make([]*ast.Rule, 0),
}
for _, rt := range roleTemplates {
rawPolicy := rt.Annotations[iamv1beta1.RegoOverrideAnnotation]
if rawPolicy == "" {
continue
}
module, err := ast.ParseModule(defaultRegoFileName, rawPolicy)
if err != nil {
return "", err
}
if mergedPolicy.Package == nil {
mergedPolicy.Package = module.Package
}
if module != nil {
mergedPolicy.Rules = append(mergedPolicy.Rules, module.Rules...)
}
}
if len(mergedPolicy.Rules) == 0 {
return "", nil
}
seenRules := make(map[string]struct{})
uniqueMergedPolicy := &ast.Module{
Package: mergedPolicy.Package,
Rules: make([]*ast.Rule, 0),
}
for _, rule := range mergedPolicy.Rules {
ruleString := rule.String()
if _, seen := seenRules[ruleString]; !seen {
uniqueMergedPolicy.Rules = append(uniqueMergedPolicy.Rules, rule)
seenRules[ruleString] = struct{}{}
}
}
return uniqueMergedPolicy.String(), nil
}
func (h *Helper) getRoleTemplates(ctx context.Context, owner RuleOwner) ([]iamv1beta1.RoleTemplate, error) {
aggregationRule := owner.GetAggregationRule()
logger := logr.FromContextOrDiscard(ctx)
if aggregationRule.RoleSelector == nil {
roletemplates := []iamv1beta1.RoleTemplate{}
for _, templateName := range aggregationRule.TemplateNames {
roleTemplate := &iamv1beta1.RoleTemplate{}
if err := h.Get(ctx, types.NamespacedName{Name: templateName}, roleTemplate); err != nil {
if errors.IsNotFound(err) {
logger.V(4).Info("aggregation role template not found", "name", templateName, "role", owner.GetObject())
continue
}
return nil, err
}
roletemplates = append(roletemplates, *roleTemplate)
}
return roletemplates, nil
}
selector := aggregationRule.RoleSelector.DeepCopy()
roleTemplateList := &iamv1beta1.RoleTemplateList{}
// Ensure the roleTemplate can be aggregated at the specific role scope
selector.MatchLabels = labels.Merge(selector.MatchLabels, map[string]string{iamv1beta1.ScopeLabel: owner.GetRuleOwnerScope()})
asSelector, err := metav1.LabelSelectorAsSelector(selector)
if err != nil {
logger.Error(err, "failed to parse role selector", "scope", owner.GetRuleOwnerScope(), "name", owner.GetName())
return nil, err
}
if err = h.List(ctx, roleTemplateList, &client.ListOptions{LabelSelector: asSelector}); err != nil {
return nil, err
}
return roleTemplateList.Items, nil
}
func (h *Helper) AggregationRole(ctx context.Context, ruleOwner RuleOwner, recorder record.EventRecorder) error {
var needUpdate bool
if ruleOwner.GetAggregationRule() == nil {
return nil
}
templates, err := h.getRoleTemplates(ctx, ruleOwner)
if err != nil {
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeWarning, AggregateRoleTemplateFailed, err.Error())
return err
}
newPolicyRules, newTemplateNames, err := h.aggregateRoleTemplateRule(templates)
if err != nil {
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeWarning, AggregateRoleTemplateFailed, err.Error())
return err
}
cover, uncovered := Covers(ruleOwner.GetRules(), newPolicyRules)
aggregationRule := ruleOwner.GetAggregationRule()
templateNamesEqual := false
if aggregationRule != nil {
templateNamesEqual = sliceutil.Equal(aggregationRule.TemplateNames, newTemplateNames)
}
if !cover {
needUpdate = true
newRule := append(ruleOwner.GetRules(), uncovered...)
squashedRules := SquashRules(len(newRule), newRule)
ruleOwner.SetRules(squashedRules)
}
if !templateNamesEqual {
needUpdate = true
aggregationRule.TemplateNames = newTemplateNames
ruleOwner.SetAggregationRule(aggregationRule)
}
newRegoPolicy, err := h.aggregateRoleTemplateRegoPolicy(templates)
if err != nil {
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeWarning, AggregateRoleTemplateFailed, err.Error())
return err
}
policyCover, err := regoPolicyCover(ruleOwner.GetRegoPolicy(), newRegoPolicy)
if err != nil {
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeWarning, AggregateRoleTemplateFailed, err.Error())
return err
}
if !policyCover {
needUpdate = true
ruleOwner.SetRegoPolicy(newRegoPolicy)
}
if needUpdate {
if err = h.Update(ctx, ruleOwner.GetObject().(client.Object)); err != nil {
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeWarning, AggregateRoleTemplateFailed, err.Error())
return err
}
recorder.Event(ruleOwner.GetObject(), corev1.EventTypeNormal, "Synced", MessageResourceSynced)
}
return nil
}
func ruleExists(haystack []rbacv1.PolicyRule, needle rbacv1.PolicyRule) bool {
covers, _ := Covers(haystack, []rbacv1.PolicyRule{needle})
return covers
}
func regoPolicyCover(owner, servant string) (bool, error) {
if servant == "" {
return true, nil
}
if owner == "" && servant != "" {
return false, nil
}
ownerModule, err := ast.ParseModule(defaultRegoFileName, owner)
if err != nil {
return false, err
}
servantModule, err := ast.ParseModule(defaultRegoFileName, servant)
if err != nil {
return false, err
}
cover := ownerModule.Compare(servantModule) >= 0
return cover, nil
}
func SquashRules(deep int, rules []rbacv1.PolicyRule) []rbacv1.PolicyRule {
var resultRules []rbacv1.PolicyRule
for _, rule := range rules {
merged := false
if cover, _ := Covers(resultRules, []rbacv1.PolicyRule{rule}); cover {
continue
}
for i, rRule := range resultRules {
if (containRules(rRule.APIGroups, rule.APIGroups) && equalRules(rRule.Resources, rule.Resources)) ||
(containRules(rRule.APIGroups, rule.APIGroups) && equalRules(rRule.Verbs, rule.Verbs)) {
merged = true
resultRules[i] = mergeRules(rRule, rule)
break
}
}
if !merged {
resultRules = append(resultRules, rule)
}
}
if len(resultRules) == deep {
return resultRules
}
return SquashRules(len(resultRules), resultRules)
}
func mergeRules(base, rule rbacv1.PolicyRule) rbacv1.PolicyRule {
if !sliceutil.HasString(base.APIGroups, "*") {
base.APIGroups = merge(base.APIGroups, rule.APIGroups)
}
if !sliceutil.HasString(base.Resources, "*") {
base.Resources = merge(base.Resources, rule.Resources)
}
if !sliceutil.HasString(base.Verbs, "*") {
base.Verbs = merge(base.Verbs, rule.Verbs)
}
return base
}
func merge(base, rule []string) []string {
for _, r := range rule {
if !sliceutil.HasString(base, r) {
base = append(base, r)
}
}
return base
}
func containRules(base, rule []string) bool {
if sliceutil.HasString(base, "*") {
return true
}
for _, b := range base {
if !sliceutil.HasString(rule, b) {
return false
}
}
return true
}
func equalRules(base, rule []string) bool {
if len(base) != len(rule) {
return false
}
baseMap := make(map[string]int)
for _, item := range base {
baseMap[item]++
}
for _, item := range rule {
count, exists := baseMap[item]
if !exists || count == 0 {
return false
}
baseMap[item]--
}
return true
}

View File

@@ -0,0 +1,240 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
"testing"
rbacv1 "k8s.io/api/rbac/v1"
"sigs.k8s.io/yaml"
)
func TestSquashRules(t *testing.T) {
var raw = `
- apiGroups:
- application.kubesphere.io
resources:
- apps
verbs:
- '*'
- apiGroups:
- application.kubesphere.io
resources:
- apps/versions
verbs:
- '*'
- apiGroups:
- application.kubesphere.io
resources:
- applications
verbs:
- '*'
- apiGroups:
- application.kubesphere.io
resources:
- attachments
verbs:
- '*'
- apiGroups:
- application.kubesphere.io
resources:
- repos
verbs:
- '*'
- apiGroups:
- application.kubesphere.io
resources:
- repos/events
verbs:
- '*'
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- get
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- list
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- watch
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- get
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- list
- apiGroups:
- '*'
resources:
- workspaces
verbs:
- watch
- apiGroups:
- '*'
resources:
- workspacemembers
verbs:
- get
- apiGroups:
- '*'
resources:
- workspacemembers
verbs:
- list
- apiGroups:
- '*'
resources:
- workspacemembers
verbs:
- watch
- apiGroups:
- '*'
resources:
- quotas
verbs:
- get
- apiGroups:
- '*'
resources:
- quotas
verbs:
- list
- apiGroups:
- '*'
resources:
- quotas
verbs:
- watch
- apiGroups:
- '*'
resources:
- abnormalworkloads
verbs:
- get
- apiGroups:
- '*'
resources:
- abnormalworkloads
verbs:
- list
- apiGroups:
- '*'
resources:
- abnormalworkloads
verbs:
- watch
- apiGroups:
- '*'
resources:
- pods
verbs:
- get
- apiGroups:
- '*'
resources:
- pods
verbs:
- list
- apiGroups:
- '*'
resources:
- pods
verbs:
- watch
- apiGroups:
- '*'
resources:
- namespaces
verbs:
- create
- apiGroups:
- '*'
resources:
- namespaces
verbs:
- watch
- apiGroups:
- '*'
resources:
- federatednamespaces
verbs:
- create
- apiGroups:
- '*'
resources:
- federatednamespaces
verbs:
- watch`
var expectedRaw = `- apiGroups:
- application.kubesphere.io
resources:
- apps
- apps/versions
- applications
- attachments
- repos
- repos/events
verbs:
- '*'
- apiGroups:
- '*'
resources:
- quotas
- workspacemembers
- workspaces
- abnormalworkloads
- pods
verbs:
- get
- list
- watch
- apiGroups:
- '*'
resources:
- namespaces
- federatednamespaces
verbs:
- create
- watch`
rules := []rbacv1.PolicyRule{}
err := yaml.Unmarshal([]byte(raw), &rules)
if err != nil {
t.Fatal(err)
}
squashRules := SquashRules(len(rules), rules)
expectedRules := []rbacv1.PolicyRule{}
err = yaml.Unmarshal([]byte(expectedRaw), &expectedRules)
if err != nil {
t.Fatal(err)
}
lefCovers, _ := Covers(expectedRules, squashRules)
rightCover, _ := Covers(squashRules, expectedRules)
if !lefCovers || !rightCover {
t.Errorf("failed")
}
}

View File

@@ -0,0 +1,30 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
)
type RuleOwner interface {
GetObject() runtime.Object
GetNamespace() string
GetName() string
GetLabels() map[string]string
SetLabels(map[string]string)
GetAnnotations() map[string]string
SetAnnotations(map[string]string)
GetRules() []rbacv1.PolicyRule
SetRules([]rbacv1.PolicyRule)
GetRegoPolicy() string
SetRegoPolicy(string)
GetAggregationRule() *iamv1beta1.AggregationRoleTemplates
SetAggregationRule(*iamv1beta1.AggregationRoleTemplates)
DeepCopyRuleOwner() RuleOwner
GetRuleOwnerScope() string
}

View File

@@ -0,0 +1,163 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
// This file is copied from K8s library .
// https://k8s.io/component-helpers/auth/rbac/validation/policy_comparator.go
package rbac
import (
"strings"
rbacv1 "k8s.io/api/rbac/v1"
)
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
var rules []rbacv1.PolicyRule
for _, servantRule := range servantRules {
rules = append(rules, BreakdownRule(servantRule)...)
}
var uncoveredRules []rbacv1.PolicyRule
for _, rule := range rules {
covered := false
for _, ownerRule := range ownerRules {
if ruleCovers(ownerRule, rule) {
covered = true
break
}
}
if !covered {
uncoveredRules = append(uncoveredRules, rule)
}
}
return len(uncoveredRules) == 0, uncoveredRules
}
// BreakdownRule 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 {
var rules []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 {
rules = append(rules, rbacv1.PolicyRule{APIGroups: []string{group}, Resources: []string{resource}, Verbs: []string{verb}, ResourceNames: []string{resourceName}})
}
} else {
rules = append(rules, 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 {
rules = append(rules, rbacv1.PolicyRule{NonResourceURLs: []string{nonResourceURL}, Verbs: []string{verb}})
}
}
return rules
}
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
}

View File

@@ -0,0 +1,84 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
)
type RoleRuleOwner struct {
Role *iamv1beta1.Role
}
func (r RoleRuleOwner) GetRuleOwnerScope() string {
return iamv1beta1.ScopeNamespace
}
func (r RoleRuleOwner) GetObject() runtime.Object {
return r.Role
}
func (r RoleRuleOwner) GetNamespace() string {
return r.Role.Namespace
}
func (r RoleRuleOwner) GetName() string {
return r.Role.Name
}
func (r RoleRuleOwner) GetLabels() map[string]string {
return r.Role.Labels
}
func (r RoleRuleOwner) SetLabels(m map[string]string) {
r.Role.Labels = m
}
func (r RoleRuleOwner) GetAnnotations() map[string]string {
return r.Role.Annotations
}
func (r RoleRuleOwner) SetAnnotations(m map[string]string) {
r.Role.Annotations = m
}
func (r RoleRuleOwner) GetRules() []rbacv1.PolicyRule {
return r.Role.Rules
}
func (r RoleRuleOwner) SetRules(rules []rbacv1.PolicyRule) {
r.Role.Rules = rules
}
func (r RoleRuleOwner) GetAggregationRule() *iamv1beta1.AggregationRoleTemplates {
return r.Role.AggregationRoleTemplates
}
func (r RoleRuleOwner) SetAggregationRule(i *iamv1beta1.AggregationRoleTemplates) {
r.Role.AggregationRoleTemplates = i
}
func (r RoleRuleOwner) GetRegoPolicy() string {
if r.Role.ObjectMeta.Annotations != nil {
return r.Role.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation]
}
return ""
}
func (r RoleRuleOwner) SetRegoPolicy(rego string) {
if r.Role.ObjectMeta.Annotations == nil {
r.Role.ObjectMeta.Annotations = make(map[string]string)
}
r.Role.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation] = rego
}
func (r RoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return RoleRuleOwner{Role: r.Role.DeepCopy()}
}
var _ RuleOwner = RoleRuleOwner{}

View File

@@ -0,0 +1,84 @@
/*
* Please refer to the LICENSE file in the root directory of the project.
* https://github.com/kubesphere/kubesphere/blob/master/LICENSE
*/
package rbac
import (
rbacv1 "k8s.io/api/rbac/v1"
"k8s.io/apimachinery/pkg/runtime"
iamv1beta1 "kubesphere.io/api/iam/v1beta1"
)
type WorkspaceRoleRuleOwner struct {
WorkspaceRole *iamv1beta1.WorkspaceRole
}
func (w WorkspaceRoleRuleOwner) GetRuleOwnerScope() string {
return iamv1beta1.ScopeWorkspace
}
func (w WorkspaceRoleRuleOwner) GetObject() runtime.Object {
return w.WorkspaceRole
}
func (w WorkspaceRoleRuleOwner) GetNamespace() string {
return ""
}
func (w WorkspaceRoleRuleOwner) GetName() string {
return w.WorkspaceRole.Name
}
func (w WorkspaceRoleRuleOwner) GetLabels() map[string]string {
return w.WorkspaceRole.Labels
}
func (w WorkspaceRoleRuleOwner) SetLabels(m map[string]string) {
w.WorkspaceRole.Labels = m
}
func (w WorkspaceRoleRuleOwner) GetAnnotations() map[string]string {
return w.WorkspaceRole.Annotations
}
func (w WorkspaceRoleRuleOwner) SetAnnotations(m map[string]string) {
w.WorkspaceRole.Annotations = m
}
func (w WorkspaceRoleRuleOwner) GetRules() []rbacv1.PolicyRule {
return w.WorkspaceRole.Rules
}
func (w WorkspaceRoleRuleOwner) SetRules(rules []rbacv1.PolicyRule) {
w.WorkspaceRole.Rules = rules
}
func (w WorkspaceRoleRuleOwner) GetAggregationRule() *iamv1beta1.AggregationRoleTemplates {
return w.WorkspaceRole.AggregationRoleTemplates
}
func (w WorkspaceRoleRuleOwner) SetAggregationRule(i *iamv1beta1.AggregationRoleTemplates) {
w.WorkspaceRole.AggregationRoleTemplates = i
}
func (w WorkspaceRoleRuleOwner) GetRegoPolicy() string {
if w.WorkspaceRole.ObjectMeta.Annotations != nil {
return w.WorkspaceRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation]
}
return ""
}
func (w WorkspaceRoleRuleOwner) SetRegoPolicy(rego string) {
if w.WorkspaceRole.ObjectMeta.Annotations == nil {
w.WorkspaceRole.ObjectMeta.Annotations = make(map[string]string)
}
w.WorkspaceRole.ObjectMeta.Annotations[iamv1beta1.RegoOverrideAnnotation] = rego
}
func (w WorkspaceRoleRuleOwner) DeepCopyRuleOwner() RuleOwner {
return WorkspaceRoleRuleOwner{WorkspaceRole: w.WorkspaceRole.DeepCopy()}
}
var _ RuleOwner = WorkspaceRoleRuleOwner{}