Files
OpenShell/deploy/helm/openshell/tests/clusterrole_test.yaml
ansjindal d009f30121 feat(helm): make cluster-scoped RBAC optional (#3459)
The gateway chart always rendered the ClusterRole and ClusterRoleBinding, so
every install and upgrade required cluster-admin even when only namespaced
objects were needed. Installers that are namespace-admin GitOps or platform
controllers could not run the release at all, and clusters where cluster-scoped
RBAC is owned by a separate team had no supported way to split the install.

Add an rbac values block so a cluster-admin can apply the cluster-scoped objects
once and a namespace-admin can install and upgrade the release without
cluster-scoped permissions:

  rbac:
    create: true
    clusterScoped:
      create: true
      clusterRoleName: ""
      clusterRoleBindingName: ""

rbac.clusterScoped.create gates the ClusterRole and ClusterRoleBinding, and is
independent of the workspace mode. rbac.create additionally gates the namespaced
sandbox Role and RoleBinding, which matters because Kubernetes escalation
prevention stops an installer holding only the built-in admin role from creating
a Role that grants agents.x-k8s.io verbs it does not itself hold. The certgen
hook and credential driver RBAC keep their existing flags.

Both flags default to true, so current installs are unchanged. The helpers treat
a missing rbac block as enabled so upgrades with --reuse-values do not drop RBAC,
matching the existing workspaceResources pattern. The ClusterRoleBinding roleRef
follows clusterRoleName so a separately applied ClusterRole can carry a name the
cluster-admin chooses.

Document the migration for a release that already owns the cluster-scoped
objects: Helm deletes objects that leave the manifest, so annotate them with
helm.sh/resource-policy=keep before setting the flag, otherwise the gateway
loses TokenReview until a cluster-admin re-applies them.

Signed-off-by: ansjindal <ansjindal@nvidia.com>
2026-09-28 05:50:07 +00:00

205 lines
5.8 KiB
YAML

# SPDX-FileCopyrightText: Copyright (c) 2025-2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0
suite: ClusterRole RBAC
templates:
- templates/clusterrole.yaml
release:
name: openshell
namespace: my-namespace
tests:
- it: includes the release namespace in the ClusterRole name
asserts:
- equal:
path: metadata.name
value: openshell-node-reader-my-namespace
- it: grants managed namespace NetworkPolicy apply permissions
set:
server.drivers.kubernetes.workspaceMode: managed
asserts:
- contains:
path: rules
content:
apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "create", "patch", "update"]
- it: limits namespaced admission reads to PVCs
set:
server.drivers.kubernetes.workspaceMode: managed
server.drivers.kubernetes.allowDriverConfig: true
asserts:
- contains:
path: rules
content:
apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get"]
- notContains:
path: rules
content:
apiGroups: [""]
resources: ["secrets"]
verbs: ["get"]
- notContains:
path: rules
content:
apiGroups: [""]
resources: ["configmaps"]
verbs: ["get"]
- it: omits PVC admission reads when caller driver config is disabled
set:
server.drivers.kubernetes.workspaceMode: managed
asserts:
- notContains:
path: rules
content:
apiGroups: [""]
resources: ["persistentvolumeclaims"]
verbs: ["get"]
- it: preserves sandbox-runtime fence permissions when gateway isolation is disabled
set:
server.drivers.kubernetes.workspaceMode: managed
networkPolicy.enabled: false
asserts:
- contains:
path: rules
content:
apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["create", "get"]
- notContains:
path: rules
content:
apiGroups: ["networking.k8s.io"]
resources: ["networkpolicies"]
verbs: ["get", "create", "patch", "update"]
- it: omits credential Secret access in managed mode
set:
server.drivers.kubernetes.workspaceMode: managed
server.credentialDrivers.kubernetesSecrets.enabled: true
asserts:
- notContains:
path: rules
content:
apiGroups: [""]
resources: ["secrets"]
verbs: ["get", "create", "patch", "delete"]
- it: omits all Secret rules in operator mode
set:
server.drivers.kubernetes.workspaceMode: operator
server.tls.clientTlsSecretName: custom-client-tls
server.credentialDrivers.kubernetesSecrets.enabled: true
asserts:
- notExists:
path: rules[*].resources[?(@ == "secrets")]
- it: names no Secrets in managed mode
set:
server.drivers.kubernetes.workspaceMode: managed
server.tls.clientTlsSecretName: custom-client-tls
server.sandboxImagePullSecrets:
- name: registry-one
- name: registry-two
asserts:
- notExists:
path: rules[*].resourceNames
- contains:
path: rules
content:
apiGroups: [""]
resources: ["secrets"]
verbs: ["create", "delete"]
- it: omits secrets rule entirely in shared mode
set:
server.drivers.kubernetes.workspaceMode: shared
asserts:
- notExists:
path: rules[*].resources[?(@ == "secrets")]
- it: grants managed sandbox-runtime companion permissions
set:
server.drivers.kubernetes.workspaceMode: managed
asserts:
- contains:
path: rules
content:
apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list", "patch", "watch"]
- contains:
path: rules
content:
apiGroups: [""]
resources: ["services"]
verbs: ["create", "get"]
- contains:
path: rules
content:
apiGroups: [""]
resources: ["secrets"]
verbs: ["create", "delete"]
- it: grants operator sandbox-runtime companion permissions
set:
server.drivers.kubernetes.workspaceMode: operator
asserts:
- contains:
path: rules
content:
apiGroups: [""]
resources: ["pods"]
verbs: ["create", "delete", "get", "list", "patch", "watch"]
- contains:
path: rules
content:
apiGroups: [""]
resources: ["services"]
verbs: ["create", "get"]
- it: omits the ClusterRole when cluster-scoped RBAC is disabled
set:
rbac.clusterScoped.create: false
asserts:
- hasDocuments:
count: 0
- it: omits the ClusterRole when all chart-managed RBAC is disabled
set:
rbac.create: false
asserts:
- hasDocuments:
count: 0
- it: omits the ClusterRole independently of the workspace mode
set:
rbac.clusterScoped.create: false
server.drivers.kubernetes.workspaceMode: managed
asserts:
- hasDocuments:
count: 0
- it: uses the configured ClusterRole name
set:
rbac.clusterScoped.clusterRoleName: platform-openshell-node-reader
asserts:
- equal:
path: metadata.name
value: platform-openshell-node-reader
- it: creates the ClusterRole when legacy values omit the rbac block
set:
rbac: null
asserts:
- hasDocuments:
count: 1
- equal:
path: metadata.name
value: openshell-node-reader-my-namespace