feat: Implement permission trie for RBAC authorization optimization#57
feat: Implement permission trie for RBAC authorization optimization#57husenkuresh1 wants to merge 16 commits intomasterfrom
Conversation
…g and enhance error logging
…roxy into feat/enhance-rbac
Add test cases for authorizer and permission trie
c8978df to
e36060a
Compare
| type PermissionTrie struct { | ||
| subjectNodes map[string]*SubjectNode | ||
| mu sync.RWMutex | ||
| } |
There was a problem hiding this comment.
I do not understand how this is a Trie. Can you please explain what happens here? Thanks.
There was a problem hiding this comment.
The PermissionTrie acts as a high-speed index for RBAC rules. Understood it as a hierarchical lookup tree where each level represents a different dimension of a Kubernetes permission. It uses the core principle of a trie: a path through the structure represents a key. In this case, the "key" is the combination of Subject, Cluster, Namespace, APIGroup, and Resource. This avoids re-evaluating a long list of rules for every single API request.
How It Works
Storing Permissions
When an RBAC rule is loaded, we create a path in the tree to represent it. Let's say we add a permission for user "bob" to "delete" "pods" in the "dev" namespace on cluster "production":
- Subject Level: Find/create the node for User: "bob".
- Cluster Level: Find/create the node for Cluster: "production".
- Namespace Level: Find/create the node for Namespace: "dev".
- API Group Level: Find/create the node for API group "" (the core API).
- Resource Level: Find/create the final node for Resource: "pods".
- Store Verb: At this final node, we update a bitmask to add the delete permission.
Checking Permissions
When checking if user "bob" can "delete" a pod in the "dev" namespace:
- Traversal: The code rapidly traverses the tree following the request's attributes: User: "bob" -> Cluster: "production" -> Namespace: "dev" -> API Group: "" -> Resource: "pods".
- Check: At the final node, it checks if the delete verb is present in the permission bitmask. In this case, it is. ✅ Access Granted.
If no rule were found for the "dev" namespace, the lookup would automatically fall back and check again using the cluster-wide namespace ("") to see if permission was granted or not.
Example Tree Structure
Here is a visual representation with annotations explaining what each path represents.
PermissionTrie
├── User:alice (SubjectNode)
│ └── cluster1 (ClusterNode)
│ ├── "" (NamespaceNode) // Cluster-wide rule
│ │ └── apps (APIGroupNode)
│ │ └── deployments (ResourceNode)
│ │ └── verbs: [get, list]
│ └── default (NamespaceNode) // Namespace-specific rule from a Role
│ └── "" (APIGroupNode - core API)
│ └── pods (ResourceNode)
│ └── verbs: [get, list, watch]
│
└── Group:dev-team (SubjectNode)
└── cluster1 (ClusterNode)
└── * (URLNode) // Non-resource URL rule (e.g., for /healthz)
└── verbs: [get]
This PR implements a permission trie structure to replace the nested loop-based RBAC authorization system, reducing authorization time.
Fixes Issue
Closes #58
Changes proposed
Backward Compatibility
Check List (Check all the applicable boxes)
Screenshots
Note to reviewers