mirror of
https://github.com/projectcapsule/capsule.git
synced 2026-08-23 06:26:43 +00:00
feat: upstream enterprise preview --------- Signed-off-by: Oliver Baehler <oliver@sudo-i.net> Co-authored-by: CorentinPtrl <pitrel.corentin@gmail.com>
236 lines
5.7 KiB
Go
236 lines
5.7 KiB
Go
// Copyright 2020-2026 Project Capsule Authors
|
|
// SPDX-License-Identifier: Apache-2.0
|
|
|
|
package v1beta2
|
|
|
|
import (
|
|
"context"
|
|
"sort"
|
|
|
|
corev1 "k8s.io/api/core/v1"
|
|
rbacv1 "k8s.io/api/rbac/v1"
|
|
"k8s.io/apimachinery/pkg/labels"
|
|
"k8s.io/apimachinery/pkg/selection"
|
|
"sigs.k8s.io/controller-runtime/pkg/client"
|
|
|
|
"github.com/projectcapsule/capsule/pkg/api/rbac"
|
|
)
|
|
|
|
func (in *Tenant) GetRoleBindings() []rbac.AdditionalRoleBindingsSpec {
|
|
roleBindings := make([]rbac.AdditionalRoleBindingsSpec, 0, len(in.Spec.AdditionalRoleBindings))
|
|
|
|
for _, owner := range in.Status.Owners {
|
|
roleBindings = append(roleBindings, owner.ToAdditionalRolebindings()...)
|
|
}
|
|
|
|
roleBindings = append(roleBindings, in.Spec.AdditionalRoleBindings...)
|
|
|
|
return roleBindings
|
|
}
|
|
|
|
func (in *Tenant) GetPromotionRoleBindings() []rbac.AdditionalRoleBindingsWithNamespaceSpec {
|
|
roleBindings := make([]rbac.AdditionalRoleBindingsWithNamespaceSpec, 0, len(in.Status.Promotions))
|
|
|
|
for _, promotion := range in.Status.Promotions {
|
|
roleBindings = append(roleBindings, promotion.ToAdditionalRolebindings()...)
|
|
}
|
|
|
|
return roleBindings
|
|
}
|
|
|
|
func (in *Tenant) IsFull() bool {
|
|
// we don't have limits on assigned Namespaces
|
|
if in.Spec.NamespaceOptions == nil || in.Spec.NamespaceOptions.Quota == nil {
|
|
return false
|
|
}
|
|
|
|
return len(in.Status.Namespaces) >= int(*in.Spec.NamespaceOptions.Quota)
|
|
}
|
|
|
|
func (in *Tenant) AssignNamespaces(namespaces []corev1.Namespace) {
|
|
l := make([]string, 0, len(namespaces))
|
|
|
|
for _, ns := range namespaces {
|
|
l = append(l, ns.GetName())
|
|
}
|
|
|
|
sort.Strings(l)
|
|
|
|
in.Status.Namespaces = l
|
|
in.Status.Size = uint(len(l))
|
|
}
|
|
|
|
func (in *Tenant) GetNamespaces() (res []string) {
|
|
return in.Status.Namespaces
|
|
}
|
|
|
|
// Fetch all namespaces defined in the status.
|
|
func (in *Tenant) GetNamespaceObjects(ctx context.Context, c client.Reader) (namespaces []corev1.Namespace, err error) {
|
|
nsList := &corev1.NamespaceList{}
|
|
|
|
if len(in.Status.Namespaces) == 0 {
|
|
return nsList.Items, nil
|
|
}
|
|
|
|
req, err := labels.NewRequirement(
|
|
corev1.LabelMetadataName,
|
|
selection.In,
|
|
in.Status.Namespaces,
|
|
)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
selector := labels.NewSelector().Add(*req)
|
|
|
|
if err := c.List(ctx, nsList, client.MatchingLabelsSelector{Selector: selector}); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return nsList.Items, nil
|
|
}
|
|
|
|
func (in *Tenant) GetOwnerProxySettings(name string, kind rbac.OwnerKind) []rbac.ProxySettings {
|
|
return in.Spec.Owners.FindOwner(name, kind).ProxyOperations
|
|
}
|
|
|
|
// GetClusterRolePermissions returns a map where the clusterRole is the key
|
|
// and the value is a list of permission subjects (kind and name) that reference that role.
|
|
// These mappings are gathered from the owners and additionalRolebindings spec.
|
|
func (in *Tenant) GetSubjectsByClusterRoles(ignoreOwnerKind []rbac.OwnerKind) (rolePerms map[string][]rbacv1.Subject) {
|
|
rolePerms = make(map[string][]rbacv1.Subject)
|
|
|
|
// Helper to add permissions for a given clusterRole
|
|
addPermission := func(clusterRole string, permission rbacv1.Subject) {
|
|
if _, exists := rolePerms[clusterRole]; !exists {
|
|
rolePerms[clusterRole] = []rbacv1.Subject{}
|
|
}
|
|
|
|
rolePerms[clusterRole] = append(rolePerms[clusterRole], permission)
|
|
}
|
|
|
|
// Helper to check if a kind is in the ignoreOwnerKind list
|
|
isIgnoredKind := func(kind string) bool {
|
|
for _, ignored := range ignoreOwnerKind {
|
|
if kind == ignored.String() {
|
|
return true
|
|
}
|
|
}
|
|
|
|
return false
|
|
}
|
|
|
|
// Process owners
|
|
for _, owner := range in.Status.Owners {
|
|
if !isIgnoredKind(owner.Kind.String()) {
|
|
for _, clusterRole := range owner.ClusterRoles {
|
|
perm := rbacv1.Subject{
|
|
Name: owner.Name,
|
|
Kind: owner.Kind.String(),
|
|
}
|
|
addPermission(clusterRole, perm)
|
|
}
|
|
}
|
|
}
|
|
|
|
// Process additional role bindings
|
|
for _, role := range in.Spec.AdditionalRoleBindings {
|
|
for _, subject := range role.Subjects {
|
|
if !isIgnoredKind(subject.Kind) {
|
|
perm := rbacv1.Subject{
|
|
Name: subject.Name,
|
|
Kind: subject.Kind,
|
|
}
|
|
addPermission(role.ClusterRoleName, perm)
|
|
}
|
|
}
|
|
}
|
|
|
|
return rolePerms
|
|
}
|
|
|
|
func (in *Tenant) GetClusterRolesBySubject(ignoreOwnerKind []rbac.OwnerKind) []rbac.SubjectRoles {
|
|
ignore := make(map[string]struct{}, len(ignoreOwnerKind))
|
|
for _, k := range ignoreOwnerKind {
|
|
ignore[k.String()] = struct{}{}
|
|
}
|
|
|
|
roleSet := map[string]map[string]map[string]struct{}{}
|
|
|
|
ensure := func(kind, name string) map[string]struct{} {
|
|
km, ok := roleSet[kind]
|
|
if !ok {
|
|
km = map[string]map[string]struct{}{}
|
|
roleSet[kind] = km
|
|
}
|
|
|
|
ns, ok := km[name]
|
|
if !ok {
|
|
ns = map[string]struct{}{}
|
|
km[name] = ns
|
|
}
|
|
|
|
return ns
|
|
}
|
|
|
|
for _, owner := range in.Status.Owners {
|
|
kind := owner.Kind.String()
|
|
if _, skip := ignore[kind]; skip {
|
|
continue
|
|
}
|
|
|
|
s := ensure(kind, owner.Name)
|
|
for _, r := range owner.ClusterRoles {
|
|
s[r] = struct{}{}
|
|
}
|
|
}
|
|
|
|
for _, rb := range in.Spec.AdditionalRoleBindings {
|
|
for _, subj := range rb.Subjects {
|
|
if _, skip := ignore[subj.Kind]; skip {
|
|
continue
|
|
}
|
|
|
|
s := ensure(subj.Kind, subj.Name)
|
|
s[rb.ClusterRoleName] = struct{}{}
|
|
}
|
|
}
|
|
|
|
// Flatten deterministically: sort kinds, names, roles
|
|
kinds := make([]string, 0, len(roleSet))
|
|
for k := range roleSet {
|
|
kinds = append(kinds, k)
|
|
}
|
|
|
|
sort.Strings(kinds)
|
|
|
|
totalSubjects := 0
|
|
for _, byName := range roleSet {
|
|
totalSubjects += len(byName)
|
|
}
|
|
|
|
out := make([]rbac.SubjectRoles, 0, totalSubjects)
|
|
|
|
for _, kind := range kinds {
|
|
names := make([]string, 0, len(roleSet[kind]))
|
|
for n := range roleSet[kind] {
|
|
names = append(names, n)
|
|
}
|
|
|
|
sort.Strings(names)
|
|
|
|
for _, name := range names {
|
|
roles := make([]string, 0, len(roleSet[kind][name]))
|
|
for r := range roleSet[kind][name] {
|
|
roles = append(roles, r)
|
|
}
|
|
|
|
sort.Strings(roles)
|
|
|
|
out = append(out, rbac.SubjectRoles{Kind: kind, Name: name, Roles: roles})
|
|
}
|
|
}
|
|
|
|
return out
|
|
}
|