rustkernel_core/security/
rbac.rs1use serde::{Deserialize, Serialize};
6use std::collections::HashSet;
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
10#[serde(rename_all = "snake_case")]
11pub enum Permission {
12 KernelExecute,
14 KernelConfigure,
16 KernelMonitor,
18 KernelAdmin,
20 StateRead,
22 StateWrite,
24 SecretsRead,
26 SecretsWrite,
28 TenantRead,
30 TenantAdmin,
32}
33
34#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
36#[serde(rename_all = "snake_case")]
37pub enum KernelPermission {
38 Execute,
40 Configure,
42 Monitor,
44 Admin,
46}
47
48impl From<KernelPermission> for Permission {
49 fn from(p: KernelPermission) -> Self {
50 match p {
51 KernelPermission::Execute => Permission::KernelExecute,
52 KernelPermission::Configure => Permission::KernelConfigure,
53 KernelPermission::Monitor => Permission::KernelMonitor,
54 KernelPermission::Admin => Permission::KernelAdmin,
55 }
56 }
57}
58
59#[derive(Debug, Clone, Default, Serialize, Deserialize)]
61pub struct PermissionSet {
62 permissions: HashSet<Permission>,
63}
64
65impl PermissionSet {
66 pub fn empty() -> Self {
68 Self {
69 permissions: HashSet::new(),
70 }
71 }
72
73 pub fn all() -> Self {
75 let mut permissions = HashSet::new();
76 permissions.insert(Permission::KernelExecute);
77 permissions.insert(Permission::KernelConfigure);
78 permissions.insert(Permission::KernelMonitor);
79 permissions.insert(Permission::KernelAdmin);
80 permissions.insert(Permission::StateRead);
81 permissions.insert(Permission::StateWrite);
82 permissions.insert(Permission::SecretsRead);
83 permissions.insert(Permission::SecretsWrite);
84 permissions.insert(Permission::TenantRead);
85 permissions.insert(Permission::TenantAdmin);
86 Self { permissions }
87 }
88
89 pub fn contains(&self, permission: Permission) -> bool {
91 self.permissions.contains(&permission)
92 }
93
94 pub fn add(&mut self, permission: Permission) {
96 self.permissions.insert(permission);
97 }
98
99 pub fn remove(&mut self, permission: Permission) {
101 self.permissions.remove(&permission);
102 }
103
104 pub fn union(&self, other: &PermissionSet) -> PermissionSet {
106 PermissionSet {
107 permissions: self
108 .permissions
109 .union(&other.permissions)
110 .cloned()
111 .collect(),
112 }
113 }
114
115 pub fn intersection(&self, other: &PermissionSet) -> PermissionSet {
117 PermissionSet {
118 permissions: self
119 .permissions
120 .intersection(&other.permissions)
121 .cloned()
122 .collect(),
123 }
124 }
125
126 pub fn iter(&self) -> impl Iterator<Item = &Permission> {
128 self.permissions.iter()
129 }
130}
131
132impl FromIterator<Permission> for PermissionSet {
133 fn from_iter<I: IntoIterator<Item = Permission>>(iter: I) -> Self {
134 Self {
135 permissions: iter.into_iter().collect(),
136 }
137 }
138}
139
140#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
142#[serde(rename_all = "snake_case")]
143pub enum Role {
144 Viewer,
146 User,
148 Operator,
150 Admin,
152 Custom(String),
154}
155
156impl Role {
157 pub fn permissions(&self) -> PermissionSet {
159 match self {
160 Role::Viewer => [Permission::KernelMonitor, Permission::StateRead]
161 .into_iter()
162 .collect(),
163 Role::User => [
164 Permission::KernelExecute,
165 Permission::KernelMonitor,
166 Permission::StateRead,
167 ]
168 .into_iter()
169 .collect(),
170 Role::Operator => [
171 Permission::KernelExecute,
172 Permission::KernelConfigure,
173 Permission::KernelMonitor,
174 Permission::StateRead,
175 Permission::StateWrite,
176 ]
177 .into_iter()
178 .collect(),
179 Role::Admin => PermissionSet::all(),
180 Role::Custom(_) => PermissionSet::empty(), }
182 }
183}
184
185#[derive(Debug, Clone, Serialize, Deserialize)]
187pub struct RoleBinding {
188 pub name: String,
190 pub role: Role,
192 pub subjects: Vec<Subject>,
194 pub scope: Option<String>,
196}
197
198impl RoleBinding {
199 pub fn new(name: impl Into<String>, role: Role) -> Self {
201 Self {
202 name: name.into(),
203 role,
204 subjects: Vec::new(),
205 scope: None,
206 }
207 }
208
209 pub fn for_user(mut self, user_id: impl Into<String>) -> Self {
211 self.subjects.push(Subject::User(user_id.into()));
212 self
213 }
214
215 pub fn for_group(mut self, group: impl Into<String>) -> Self {
217 self.subjects.push(Subject::Group(group.into()));
218 self
219 }
220
221 pub fn in_scope(mut self, scope: impl Into<String>) -> Self {
223 self.scope = Some(scope.into());
224 self
225 }
226}
227
228#[derive(Debug, Clone, Serialize, Deserialize)]
230#[serde(tag = "type", rename_all = "snake_case")]
231pub enum Subject {
232 User(String),
234 Group(String),
236 ServiceAccount(String),
238}
239
240#[cfg(test)]
241mod tests {
242 use super::*;
243
244 #[test]
245 fn test_permission_set() {
246 let mut perms = PermissionSet::empty();
247 assert!(!perms.contains(Permission::KernelExecute));
248
249 perms.add(Permission::KernelExecute);
250 assert!(perms.contains(Permission::KernelExecute));
251
252 perms.remove(Permission::KernelExecute);
253 assert!(!perms.contains(Permission::KernelExecute));
254 }
255
256 #[test]
257 fn test_all_permissions() {
258 let perms = PermissionSet::all();
259 assert!(perms.contains(Permission::KernelExecute));
260 assert!(perms.contains(Permission::KernelAdmin));
261 assert!(perms.contains(Permission::SecretsWrite));
262 }
263
264 #[test]
265 fn test_role_permissions() {
266 let viewer_perms = Role::Viewer.permissions();
267 assert!(viewer_perms.contains(Permission::KernelMonitor));
268 assert!(!viewer_perms.contains(Permission::KernelExecute));
269
270 let user_perms = Role::User.permissions();
271 assert!(user_perms.contains(Permission::KernelExecute));
272 assert!(!user_perms.contains(Permission::KernelAdmin));
273
274 let admin_perms = Role::Admin.permissions();
275 assert!(admin_perms.contains(Permission::KernelAdmin));
276 }
277
278 #[test]
279 fn test_permission_union() {
280 let perms1: PermissionSet = [Permission::KernelExecute].into_iter().collect();
281 let perms2: PermissionSet = [Permission::KernelMonitor].into_iter().collect();
282
283 let union = perms1.union(&perms2);
284 assert!(union.contains(Permission::KernelExecute));
285 assert!(union.contains(Permission::KernelMonitor));
286 }
287
288 #[test]
289 fn test_role_binding() {
290 let binding = RoleBinding::new("admin-binding", Role::Admin)
291 .for_user("user-123")
292 .for_group("admins")
293 .in_scope("tenant-456");
294
295 assert_eq!(binding.role, Role::Admin);
296 assert_eq!(binding.subjects.len(), 2);
297 assert_eq!(binding.scope.as_deref(), Some("tenant-456"));
298 }
299}