1
0
mirror of https://github.com/rancher/steve.git synced 2025-08-01 23:03:28 +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"
)
const accessSetAttribute = "accessSet"
type AccessControl struct {
apiserver.SchemaBasedAccess
}
@ -25,8 +27,8 @@ func (a *AccessControl) CanDo(apiOp *types.APIRequest, resource, verb, namespace
}
}
group, resource := kv.Split(resource, "/")
accessSet := apiOp.Schemas.Attributes["accessSet"].(*AccessSet)
if accessSet.Grants(verb, schema.GroupResource{
accessSet := AccessSetFromAPIRequest(apiOp)
if accessSet != nil && accessSet.Grants(verb, schema.GroupResource{
Group: group,
Resource: resource,
}, namespace, name) {
@ -44,3 +46,23 @@ func (a *AccessControl) CanWatch(apiOp *types.APIRequest, schema *types.APISchem
}
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
func (p *policyRuleIndex) getRoleRefs(subjectName string) subjectGrants {
var clusterRoleBindings []roleRef
for _, crb := range p.getClusterRoleBindings(subjectName) {
crbs := p.getClusterRoleBindings(subjectName)
clusterRoleBindings := make([]roleRef, len(crbs))
for x, crb := range crbs {
rules, resourceVersion := p.getRules(All, crb.RoleRef)
clusterRoleBindings = append(clusterRoleBindings, roleRef{
clusterRoleBindings[x] = roleRef{
roleName: crb.RoleRef.Name,
resourceVersion: resourceVersion,
rules: rules,
kind: clusterRoleKind,
})
}
}
var roleBindings []roleRef
for _, rb := range p.getRoleBindings(subjectName) {
rbs := p.getRoleBindings(subjectName)
roleBindings := make([]roleRef, len(rbs))
for x, rb := range rbs {
rules, resourceVersion := p.getRules(rb.Namespace, rb.RoleRef)
roleBindings = append(roleBindings, roleRef{
roleBindings[x] = roleRef{
roleName: rb.RoleRef.Name,
namespace: rb.Namespace,
resourceVersion: resourceVersion,
rules: rules,
kind: roleKind,
})
}
}
return subjectGrants{

View File

@ -102,9 +102,12 @@ func formatter(summarycache common.SummaryCache, asl accesscontrol.AccessSetLook
if !ok {
return
}
accessSet := asl.AccessFor(userInfo)
accessSet := accesscontrol.AccessSetFromAPIRequest(request)
if accessSet == nil {
return
accessSet = asl.AccessFor(userInfo)
if accessSet == nil {
return
}
}
hasUpdate := accessSet.Grants("update", gvr.GroupResource(), resource.APIObject.Namespace(), resource.APIObject.Name())
hasDelete := accessSet.Grants("delete", 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{}{
"accessSet": access,
}
accesscontrol.SetAccessSetAttribute(result, access)
return result, nil
}