diff --git a/bundle/manifests/gpu-operator-certified.clusterserviceversion.yaml b/bundle/manifests/gpu-operator-certified.clusterserviceversion.yaml index 926c21d0a6..4f68c63673 100644 --- a/bundle/manifests/gpu-operator-certified.clusterserviceversion.yaml +++ b/bundle/manifests/gpu-operator-certified.clusterserviceversion.yaml @@ -894,6 +894,7 @@ spec: - create - update - patch + - delete - apiGroups: - coordination.k8s.io resources: diff --git a/config/rbac/role.yaml b/config/rbac/role.yaml index 77677a3b39..a829da60da 100644 --- a/config/rbac/role.yaml +++ b/config/rbac/role.yaml @@ -233,6 +233,14 @@ rules: - patch - update - watch +- apiGroups: + - security.openshift.io + resourceNames: + - anyuid + resources: + - securitycontextconstraints + verbs: + - use - apiGroups: - security.openshift.io resourceNames: diff --git a/controllers/gpucluster_controller.go b/controllers/gpucluster_controller.go index 2a4e86a730..faab2aa456 100644 --- a/controllers/gpucluster_controller.go +++ b/controllers/gpucluster_controller.go @@ -75,6 +75,7 @@ type GPUClusterReconciler struct { //+kubebuilder:rbac:groups="",resources=namespaces,verbs=get;update;patch //+kubebuilder:rbac:groups=events.k8s.io,resources=events,verbs=create;patch //+kubebuilder:rbac:groups=resource.k8s.io,resources=resourceclaimtemplates,verbs=get;list;watch;create;update;delete +//+kubebuilder:rbac:groups=security.openshift.io,resources=securitycontextconstraints,verbs=use,resourceNames=anyuid func (r *GPUClusterReconciler) Reconcile(ctx context.Context, req ctrl.Request) (ctrl.Result, error) { logger := log.FromContext(ctx) diff --git a/deployments/gpu-operator/templates/clusterrole.yaml b/deployments/gpu-operator/templates/clusterrole.yaml index 5a12e51969..9423b9b632 100644 --- a/deployments/gpu-operator/templates/clusterrole.yaml +++ b/deployments/gpu-operator/templates/clusterrole.yaml @@ -190,6 +190,7 @@ rules: - create - update - patch + - delete - apiGroups: - coordination.k8s.io resources: diff --git a/internal/state/dra_driver_test.go b/internal/state/dra_driver_test.go index 48dbcb5b06..1598a68bb4 100644 --- a/internal/state/dra_driver_test.go +++ b/internal/state/dra_driver_test.go @@ -25,6 +25,7 @@ import ( "github.com/stretchr/testify/require" appsv1 "k8s.io/api/apps/v1" corev1 "k8s.io/api/core/v1" + rbacv1 "k8s.io/api/rbac/v1" "k8s.io/apimachinery/pkg/api/resource" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured" @@ -474,6 +475,28 @@ func TestDRADriverComputeDomainsContainerAndController(t *testing.T) { assert.Equal(t, "test-operator", depEnv["LEADER_ELECTION_LEASE_LOCK_NAMESPACE"]) } +func TestComputeDomainDaemonCliquePermissions(t *testing.T) { + s := newTestDRAState(t) + cr := sampleGPUCluster() + cr.Spec.DRADriver.ComputeDomains.Enabled = new(true) + objs, err := s.getManifestObjects(context.Background(), cr, draSupportedCatalog()) + require.NoError(t, err) + for _, obj := range objs { + if obj.GetKind() != "ClusterRole" || obj.GetName() != "compute-domain-daemon" { + continue + } + role := &rbacv1.ClusterRole{} + require.NoError(t, runtime.DefaultUnstructuredConverter.FromUnstructured(obj.Object, role)) + require.Contains(t, role.Rules, rbacv1.PolicyRule{ + APIGroups: []string{"resource.nvidia.com"}, + Resources: []string{"computedomaincliques"}, + Verbs: []string{"get", "list", "watch", "create", "update", "patch", "delete"}, + }, "owner-reference admission requires delete permission on the dependent clique") + return + } + t.Fatal("compute-domain-daemon ClusterRole not found") +} + func TestDRADriverDaemonsetsLabels(t *testing.T) { s := newTestDRAState(t) cr := sampleGPUCluster() diff --git a/internal/state/gpucluster_scc_test.go b/internal/state/gpucluster_scc_test.go index d95fd0628b..02c467606d 100644 --- a/internal/state/gpucluster_scc_test.go +++ b/internal/state/gpucluster_scc_test.go @@ -91,6 +91,59 @@ func TestDRADriverSCCAllowsMPSHostPID(t *testing.T) { require.True(t, allowHostPID, "MPS control daemon pods require hostPID") } +func TestComputeDomainDaemonAnyUIDBinding(t *testing.T) { + for _, tc := range []struct { + name string + openshift bool + computeDomains bool + }{ + {name: "openshift-enabled", openshift: true, computeDomains: true}, + {name: "openshift-disabled", openshift: true}, + {name: "kubernetes-enabled", computeDomains: true}, + {name: "kubernetes-disabled"}, + } { + t.Run(tc.name, func(t *testing.T) { + s := newTestDRAState(t) + cr := sampleGPUCluster() + cr.Spec.DRADriver.ComputeDomains.Enabled = new(tc.computeDomains) + catalog := draSupportedCatalog() + if tc.openshift { + catalog = draSupportedOpenshiftCatalog() + } + objs, err := s.getManifestObjects(context.Background(), cr, catalog) + require.NoError(t, err) + var binding *unstructured.Unstructured + for _, obj := range objs { + if obj.GetKind() == "ClusterRoleBinding" && obj.GetName() == "compute-domain-daemon-openshift-anyuid-role-binding" { + binding = obj + } + } + if tc.openshift && tc.computeDomains { + require.NotNil(t, binding) + require.Equal(t, map[string]any{ + "apiGroup": "rbac.authorization.k8s.io", + "kind": "ClusterRole", + "name": "system:openshift:scc:anyuid", + }, binding.Object["roleRef"]) + require.Equal(t, []any{map[string]any{ + "kind": "ServiceAccount", + "name": "compute-domain-daemon-service-account", + "namespace": "test-operator", + }}, binding.Object["subjects"]) + } else { + require.Nil(t, binding) + } + if tc.openshift { + scc := findSCC(t, objs, "nvidia-dra-driver") + require.NotNil(t, scc) + require.Contains(t, sccUsers(t, scc), "system:serviceaccount:test-operator:compute-domain-daemon-service-account") + require.Contains(t, scc.Object, "priority") + require.Nil(t, scc.Object["priority"]) + } + }) + } +} + func TestGPUClusterOperandSCCs(t *testing.T) { testCases := []struct { name string diff --git a/internal/state/testdata/golden/gpucluster-dra-driver-full-spec.yaml b/internal/state/testdata/golden/gpucluster-dra-driver-full-spec.yaml index 966ca13e50..498257331c 100644 --- a/internal/state/testdata/golden/gpucluster-dra-driver-full-spec.yaml +++ b/internal/state/testdata/golden/gpucluster-dra-driver-full-spec.yaml @@ -164,6 +164,7 @@ rules: - create - update - patch + - delete - apiGroups: - "" resources: diff --git a/manifests/state-dra-driver/0120_compute-domain-daemon-rbac.yaml b/manifests/state-dra-driver/0120_compute-domain-daemon-rbac.yaml index f00d8b05a4..c8ec333528 100644 --- a/manifests/state-dra-driver/0120_compute-domain-daemon-rbac.yaml +++ b/manifests/state-dra-driver/0120_compute-domain-daemon-rbac.yaml @@ -35,6 +35,7 @@ rules: - create - update - patch + - delete - apiGroups: - "" resources: @@ -57,4 +58,19 @@ roleRef: kind: ClusterRole name: compute-domain-daemon apiGroup: rbac.authorization.k8s.io +{{- if .OpenshiftVersion }} +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: compute-domain-daemon-openshift-anyuid-role-binding +subjects: +- kind: ServiceAccount + name: compute-domain-daemon-service-account + namespace: {{ .Namespace }} +roleRef: + kind: ClusterRole + name: system:openshift:scc:anyuid + apiGroup: rbac.authorization.k8s.io +{{- end }} {{- end }}