Documentation Index
Fetch the complete documentation index at: https://mintlify.com/loft-sh/vcluster/llms.txt
Use this file to discover all available pages before exploring further.
vCluster implements a comprehensive RBAC system that operates at both the host cluster and virtual cluster levels. This page explains how to configure and manage RBAC for secure multi-tenant environments.
RBAC Architecture
vCluster uses a two-tier RBAC model:
- Host Cluster RBAC: Controls what vCluster can do in the host cluster
- Virtual Cluster RBAC: Controls what users can do inside the vCluster
Host Cluster RBAC
vCluster requires specific permissions in the host cluster to function. These permissions are managed through Kubernetes RBAC resources.
ClusterRole Permissions
When vCluster needs cluster-wide permissions, a ClusterRole is created:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: vcluster-my-vcluster
rules:
# Node access for scheduler
- apiGroups: [""]
resources: ["nodes", "nodes/status"]
verbs: ["get", "watch", "list"]
# Storage classes for PVC provisioning
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses", "csinodes", "csidrivers"]
verbs: ["get", "watch", "list"]
# Persistent volumes for storage
- apiGroups: [""]
resources: ["persistentvolumes"]
verbs: ["create", "delete", "patch", "update", "get", "list", "watch"]
From chart/templates/clusterrole.yaml:
rules:
# Platform integration
- apiGroups: ["cluster.loft.sh", "storage.loft.sh"]
resources: ["features", "virtualclusters"]
verbs: ["get", "list", "watch"]
# Node syncing
- apiGroups: [""]
resources: ["pods", "nodes", "nodes/status"]
verbs: ["get", "watch", "list"]
Role Permissions (Namespace-Scoped)
For namespace-scoped operations, vCluster uses a Role:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: vc-my-vcluster
namespace: my-vcluster-namespace
rules:
# Core workload resources
- apiGroups: [""]
resources: ["configmaps", "secrets", "services", "pods", "persistentvolumeclaims"]
verbs: ["create", "delete", "patch", "update", "get", "list", "watch"]
# Pod operations
- apiGroups: [""]
resources: ["pods/attach", "pods/portforward", "pods/exec", "pods/log"]
verbs: ["get", "list", "watch", "create"]
# Pod status updates
- apiGroups: [""]
resources: ["pods/status", "pods/ephemeralcontainers"]
verbs: ["patch", "update"]
# Events
- apiGroups: ["", "events.k8s.io"]
resources: ["events"]
verbs: ["create", "get", "list", "watch"]
ServiceAccount Configuration
vCluster uses ServiceAccounts for authentication:
apiVersion: v1
kind: ServiceAccount
metadata:
name: vc-my-vcluster
namespace: my-vcluster-namespace
automountServiceAccountToken: true
Bind the ServiceAccount to RBAC roles:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: vc-my-vcluster
namespace: my-vcluster-namespace
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: vc-my-vcluster
subjects:
- kind: ServiceAccount
name: vc-my-vcluster
namespace: my-vcluster-namespace
Custom RBAC Rules
Override ClusterRole Rules
Customize the vCluster ClusterRole:
rbac:
clusterRole:
overwriteRules:
# Custom rules replace defaults
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
Extend existing rules without replacing them:
rbac:
clusterRole:
extraRules:
- apiGroups: ["custom.io"]
resources: ["customresources"]
verbs: ["get", "list", "watch"]
Override Role Rules
Customize namespace-scoped permissions:
rbac:
role:
enabled: true
overwriteRules:
- apiGroups: [""]
resources: ["pods", "services"]
verbs: ["get", "list"]
Virtual Cluster RBAC
Inside the vCluster, standard Kubernetes RBAC applies. Users and ServiceAccounts are managed independently.
Creating Users
Create a ServiceAccount in the vCluster:
# Connect to vCluster
vcluster connect my-vcluster
# Create ServiceAccount
kubectl create serviceaccount developer
Creating Roles
Define a Role for developers:
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: default
rules:
- apiGroups: [""]
resources: ["pods", "services", "configmaps"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
Creating RoleBindings
Bind the Role to a ServiceAccount:
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: developer-binding
namespace: default
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: Role
name: developer
subjects:
- kind: ServiceAccount
name: developer
namespace: default
Cluster-Wide Roles
Create ClusterRoles for cluster-wide permissions:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-viewer
rules:
- apiGroups: [""]
resources: ["namespaces", "nodes", "persistentvolumes"]
verbs: ["get", "list", "watch"]
- apiGroups: ["storage.k8s.io"]
resources: ["storageclasses"]
verbs: ["get", "list", "watch"]
Bind with a ClusterRoleBinding:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: cluster-viewer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: cluster-viewer
subjects:
- kind: ServiceAccount
name: viewer
namespace: default
Delegating Authorization
vCluster implements delegating authorization to validate requests against the host cluster:
// From pkg/authorization/delegatingauthorizer/authorizer.go
func (l *delegatingAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
// Check if request applies to delegated resources
if !applies(a, l.resources, l.nonResources) {
return authorizer.DecisionNoOpinion, "", nil
}
// Create SubjectAccessReview for host cluster
accessReview := &authorizationv1.SubjectAccessReview{
Spec: authorizationv1.SubjectAccessReviewSpec{
User: a.GetUser().GetName(),
Groups: a.GetUser().GetGroups(),
ResourceAttributes: &authorizationv1.ResourceAttributes{
Namespace: a.GetNamespace(),
Verb: a.GetVerb(),
Resource: a.GetResource(),
},
},
}
err = l.delegatingClient.Create(ctx, accessReview)
if err != nil {
return authorizer.DecisionDeny, "", err
}
if accessReview.Status.Allowed && !accessReview.Status.Denied {
return authorizer.DecisionAllow, "", nil
}
return authorizer.DecisionDeny, accessReview.Status.Reason, nil
}
Impersonation
vCluster supports user impersonation for elevated operations:
// From pkg/authorization/impersonationauthorizer/authorizer.go
func (i *impersonationAuthorizer) Authorize(ctx context.Context, a authorizer.Attributes) (authorized authorizer.Decision, reason string, err error) {
if a.GetVerb() != "impersonate" || !a.IsResourceRequest() {
return authorizer.DecisionNoOpinion, "", nil
}
// Validate impersonation request against host cluster
accessReview := &authorizationv1.SubjectAccessReview{
Spec: authorizationv1.SubjectAccessReviewSpec{
ResourceAttributes: &authorizationv1.ResourceAttributes{
Verb: "impersonate",
Resource: a.GetResource(),
Name: a.GetName(),
},
},
}
// ...
}
Use impersonation in kubectl:
kubectl get pods --as=developer --as-group=developers
Multi-Namespace Mode
When multi-namespace mode is enabled, vCluster can manage resources across namespaces:
sync:
toHost:
namespaces:
enabled: true
This creates a ClusterRole instead of a Role:
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
name: vc-my-vcluster-multi
rules:
- apiGroups: [""]
resources: ["namespaces", "serviceaccounts"]
verbs: ["create", "delete", "patch", "update", "get", "watch", "list"]
Best Practices
Principle of Least Privilege
Grant only the minimum required permissions:
rbac:
clusterRole:
overwriteRules:
# Only enable required verbs
- apiGroups: [""]
resources: ["nodes"]
verbs: ["get", "list"] # No update/delete
Separate ServiceAccounts
Use different ServiceAccounts for different components:
controlPlane:
advanced:
workloadServiceAccount:
name: vcluster-workload-sa
headlessServiceAccount:
name: vcluster-headless-sa
Regular Audits
Audit RBAC configurations regularly:
# List all ClusterRoles
kubectl get clusterroles | grep vcluster
# View ClusterRole details
kubectl describe clusterrole vcluster-my-vcluster
# Check RoleBindings
kubectl get rolebindings -n vcluster-namespace
Use Namespaces for Isolation
Isolate vClusters in separate namespaces:
kubectl create namespace team-a-vcluster
kubectl create namespace team-b-vcluster
vcluster create team-a --namespace team-a-vcluster
vcluster create team-b --namespace team-b-vcluster
Limit Impersonation
Restrict impersonation to trusted users:
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: limited-impersonation
rules:
- apiGroups: [""]
resources: ["users", "groups", "serviceaccounts"]
verbs: ["impersonate"]
resourceNames: ["specific-user"] # Limit to specific users
Testing RBAC
Test ServiceAccount Permissions
# Test if ServiceAccount can list pods
kubectl auth can-i list pods \
--as=system:serviceaccount:default:developer \
-n default
# Test with specific verb
kubectl auth can-i delete deployments \
--as=system:serviceaccount:default:developer \
-n production
Verify ClusterRole Permissions
# Check what resources a ClusterRole can access
kubectl describe clusterrole vcluster-my-vcluster
# List all permissions for a user
kubectl auth can-i --list --as=developer
Troubleshooting
Permission Denied Errors
Check ServiceAccount permissions:
# Get ServiceAccount
kubectl get sa vc-my-vcluster -n vcluster-namespace
# Check RoleBindings
kubectl get rolebindings -n vcluster-namespace -o yaml
# Verify ClusterRoleBindings
kubectl get clusterrolebindings | grep vcluster
Missing Resources
Verify RBAC rules include required resources:
# Check if vCluster can access nodes
kubectl auth can-i list nodes \
--as=system:serviceaccount:vcluster-namespace:vc-my-vcluster
Unauthorized Errors
Enable audit logging to debug authorization:
controlPlane:
advanced:
auditLog:
enabled: true
Further Reading