feat: add rbac policy matrix

This commit is contained in:
Philipp
2026-06-10 20:01:22 +02:00
parent 000c08dae7
commit 772ed6bf8d
4 changed files with 148 additions and 0 deletions
+83
View File
@@ -0,0 +1,83 @@
package rbac
type Role string
const (
RoleOwner Role = "owner"
RoleAdmin Role = "admin"
RoleMember Role = "member"
RoleViewer Role = "viewer"
)
type Action string
const (
ActionVMRead Action = "vm.read"
ActionVMPower Action = "vm.power"
ActionVMCreate Action = "vm.create"
ActionVMDelete Action = "vm.delete"
ActionVMConsole Action = "vm.console"
ActionProjectRead Action = "project.read"
ActionProjectManage Action = "project.manage"
ActionSSHKeyRead Action = "ssh_key.read"
ActionSSHKeyManage Action = "ssh_key.manage"
ActionAuditRead Action = "audit.read"
ActionClusterManage Action = "cluster.manage"
)
func Can(role Role, action Action) bool {
allowed, ok := permissions[role]
if !ok {
return false
}
return allowed[action]
}
var permissions = map[Role]map[Action]bool{
RoleOwner: allow(
ActionVMRead,
ActionVMPower,
ActionVMCreate,
ActionVMDelete,
ActionVMConsole,
ActionProjectRead,
ActionProjectManage,
ActionSSHKeyRead,
ActionSSHKeyManage,
ActionAuditRead,
),
RoleAdmin: allow(
ActionVMRead,
ActionVMPower,
ActionVMCreate,
ActionVMDelete,
ActionVMConsole,
ActionProjectRead,
ActionProjectManage,
ActionSSHKeyRead,
ActionSSHKeyManage,
ActionAuditRead,
),
RoleMember: allow(
ActionVMRead,
ActionVMPower,
ActionVMCreate,
ActionVMConsole,
ActionProjectRead,
ActionSSHKeyRead,
),
RoleViewer: allow(
ActionVMRead,
ActionVMConsole,
ActionProjectRead,
ActionSSHKeyRead,
),
}
func allow(actions ...Action) map[Action]bool {
allowed := make(map[Action]bool, len(actions))
for _, action := range actions {
allowed[action] = true
}
return allowed
}
+58
View File
@@ -0,0 +1,58 @@
package rbac
import "testing"
func TestCan(t *testing.T) {
tests := []struct {
name string
role Role
action Action
want bool
}{
{name: "owner can manage project", role: RoleOwner, action: ActionProjectManage, want: true},
{name: "owner can read audit", role: RoleOwner, action: ActionAuditRead, want: true},
{name: "admin can delete vm", role: RoleAdmin, action: ActionVMDelete, want: true},
{name: "admin can manage ssh keys", role: RoleAdmin, action: ActionSSHKeyManage, want: true},
{name: "member can create vm", role: RoleMember, action: ActionVMCreate, want: true},
{name: "member cannot delete vm", role: RoleMember, action: ActionVMDelete, want: false},
{name: "member cannot read audit", role: RoleMember, action: ActionAuditRead, want: false},
{name: "viewer can read vm", role: RoleViewer, action: ActionVMRead, want: true},
{name: "viewer can open console", role: RoleViewer, action: ActionVMConsole, want: true},
{name: "viewer cannot power vm", role: RoleViewer, action: ActionVMPower, want: false},
{name: "viewer cannot create vm", role: RoleViewer, action: ActionVMCreate, want: false},
{name: "tenant roles cannot manage cluster", role: RoleOwner, action: ActionClusterManage, want: false},
{name: "unknown role denied", role: Role("unknown"), action: ActionVMRead, want: false},
{name: "unknown action denied", role: RoleOwner, action: Action("unknown.action"), want: false},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
if got := Can(tt.role, tt.action); got != tt.want {
t.Fatalf("Can(%q, %q) = %v, want %v", tt.role, tt.action, got, tt.want)
}
})
}
}
func TestPolicyMatrix(t *testing.T) {
roles := []Role{RoleOwner, RoleAdmin, RoleMember, RoleViewer}
actions := []Action{
ActionVMRead,
ActionVMPower,
ActionVMCreate,
ActionVMDelete,
ActionVMConsole,
ActionProjectRead,
ActionProjectManage,
ActionSSHKeyRead,
ActionSSHKeyManage,
ActionAuditRead,
ActionClusterManage,
}
for _, role := range roles {
for _, action := range actions {
_ = Can(role, action)
}
}
}