1
0
mirror of https://github.com/rancher/steve.git synced 2025-08-13 12:05:22 +00:00

Calculate AccessSets once per request instead of per resource (#647)

This commit is contained in:
Alejandro Ruiz 2025-05-30 16:32:56 +02:00 committed by GitHub
parent 55a1b940a0
commit 06fe9c3ef4
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 40 additions and 15 deletions

View File

@ -8,6 +8,8 @@ import (
"k8s.io/apimachinery/pkg/runtime/schema" "k8s.io/apimachinery/pkg/runtime/schema"
) )
const accessSetAttribute = "accessSet"
type AccessControl struct { type AccessControl struct {
apiserver.SchemaBasedAccess apiserver.SchemaBasedAccess
} }
@ -25,8 +27,8 @@ func (a *AccessControl) CanDo(apiOp *types.APIRequest, resource, verb, namespace
} }
} }
group, resource := kv.Split(resource, "/") group, resource := kv.Split(resource, "/")
accessSet := apiOp.Schemas.Attributes["accessSet"].(*AccessSet) accessSet := AccessSetFromAPIRequest(apiOp)
if accessSet.Grants(verb, schema.GroupResource{ if accessSet != nil && accessSet.Grants(verb, schema.GroupResource{
Group: group, Group: group,
Resource: resource, Resource: resource,
}, namespace, name) { }, namespace, name) {
@ -44,3 +46,23 @@ func (a *AccessControl) CanWatch(apiOp *types.APIRequest, schema *types.APISchem
} }
return a.SchemaBasedAccess.CanWatch(apiOp, schema) return a.SchemaBasedAccess.CanWatch(apiOp, schema)
} }
// SetAccessSetAttribute stores the provided accessSet using a predefined attribute
func SetAccessSetAttribute(schemas *types.APISchemas, accessSet *AccessSet) {
if schemas.Attributes == nil {
schemas.Attributes = map[string]interface{}{}
}
schemas.Attributes[accessSetAttribute] = accessSet
}
// AccessSetFromAPIRequest retrieves an AccessSet from the APIRequest Schemas attributes, if defined.
// This attribute must have been previously set by using SetAccessSetAttribute
func AccessSetFromAPIRequest(req *types.APIRequest) *AccessSet {
if req == nil || req.Schemas == nil {
return nil
}
if v, ok := req.Schemas.Attributes[accessSetAttribute]; ok {
return v.(*AccessSet)
}
return nil
}

View File

@ -181,27 +181,29 @@ func (p *policyRuleIndex) getRoleBindings(subjectName string) []*rbacv1.RoleBind
// getRoleRefs gathers rules from roles granted to a given subject through RoleBindings and ClusterRoleBindings // getRoleRefs gathers rules from roles granted to a given subject through RoleBindings and ClusterRoleBindings
func (p *policyRuleIndex) getRoleRefs(subjectName string) subjectGrants { func (p *policyRuleIndex) getRoleRefs(subjectName string) subjectGrants {
var clusterRoleBindings []roleRef crbs := p.getClusterRoleBindings(subjectName)
for _, crb := range p.getClusterRoleBindings(subjectName) { clusterRoleBindings := make([]roleRef, len(crbs))
for x, crb := range crbs {
rules, resourceVersion := p.getRules(All, crb.RoleRef) rules, resourceVersion := p.getRules(All, crb.RoleRef)
clusterRoleBindings = append(clusterRoleBindings, roleRef{ clusterRoleBindings[x] = roleRef{
roleName: crb.RoleRef.Name, roleName: crb.RoleRef.Name,
resourceVersion: resourceVersion, resourceVersion: resourceVersion,
rules: rules, rules: rules,
kind: clusterRoleKind, kind: clusterRoleKind,
}) }
} }
var roleBindings []roleRef rbs := p.getRoleBindings(subjectName)
for _, rb := range p.getRoleBindings(subjectName) { roleBindings := make([]roleRef, len(rbs))
for x, rb := range rbs {
rules, resourceVersion := p.getRules(rb.Namespace, rb.RoleRef) rules, resourceVersion := p.getRules(rb.Namespace, rb.RoleRef)
roleBindings = append(roleBindings, roleRef{ roleBindings[x] = roleRef{
roleName: rb.RoleRef.Name, roleName: rb.RoleRef.Name,
namespace: rb.Namespace, namespace: rb.Namespace,
resourceVersion: resourceVersion, resourceVersion: resourceVersion,
rules: rules, rules: rules,
kind: roleKind, kind: roleKind,
}) }
} }
return subjectGrants{ return subjectGrants{

View File

@ -102,10 +102,13 @@ func formatter(summarycache common.SummaryCache, asl accesscontrol.AccessSetLook
if !ok { if !ok {
return return
} }
accessSet := asl.AccessFor(userInfo) accessSet := accesscontrol.AccessSetFromAPIRequest(request)
if accessSet == nil {
accessSet = asl.AccessFor(userInfo)
if accessSet == nil { if accessSet == nil {
return return
} }
}
hasUpdate := accessSet.Grants("update", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name()) hasUpdate := accessSet.Grants("update", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())
hasDelete := accessSet.Grants("delete", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name()) hasDelete := accessSet.Grants("delete", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())
hasPatch := accessSet.Grants("patch", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name()) hasPatch := accessSet.Grants("patch", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())

View File

@ -171,9 +171,7 @@ func (c *Collection) schemasForSubject(access *accesscontrol.AccessSet) (*types.
} }
} }
result.Attributes = map[string]interface{}{ accesscontrol.SetAccessSetAttribute(result, access)
"accessSet": access,
}
return result, nil return result, nil
} }