Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -3,12 +3,12 @@ kind: ClusterRole
metadata:
labels:
app.kubernetes.io/name: clusterrole
app.kubernetes.io/instance: evalhub-proxy-role
app.kubernetes.io/instance: evalhub-auth-reviewer-role
app.kubernetes.io/component: kube-rbac-proxy
app.kubernetes.io/created-by: trustyai-service-operator
app.kubernetes.io/part-of: trustyai-service-operator
app.kubernetes.io/managed-by: kustomize
name: evalhub-proxy-role
name: evalhub-auth-reviewer-role
rules:
- apiGroups:
- authentication.k8s.io
Expand All @@ -22,17 +22,3 @@ rules:
- subjectaccessreviews
verbs:
- create
- apiGroups:
- trustyai.opendatahub.io
resources:
- evalhubs
verbs:
- get
- apiGroups:
- trustyai.opendatahub.io
resources:
- evalhubs/proxy
verbs:
- get
- create
- update
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ metadata:
labels:
app.kubernetes.io/component: evalhub
app.kubernetes.io/name: trustyai-service-operator
name: evalhub-resource-manager-binding
name: evalhub-job-config-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: evalhub-resource-manager
name: evalhub-job-config
subjects:
- kind: ServiceAccount
name: controller-manager
Expand Down
14 changes: 14 additions & 0 deletions config/rbac/evalhub/evalhub_job_config_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
# ClusterRole for EvalHub job ConfigMap management
# Split from the monolithic evalhub-resource-manager for least-privilege.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: evalhub-job-config
labels:
app.kubernetes.io/name: trustyai-service-operator
app.kubernetes.io/component: evalhub
rules:
- apiGroups: [""]
resources: ["configmaps"]
verbs: ["create", "get", "update", "delete"]
15 changes: 15 additions & 0 deletions config/rbac/evalhub/evalhub_jobs_writer_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: evalhub
app.kubernetes.io/name: trustyai-service-operator
name: evalhub-jobs-writer-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: evalhub-jobs-writer
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
14 changes: 14 additions & 0 deletions config/rbac/evalhub/evalhub_jobs_writer_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
---
# ClusterRole for EvalHub job creation
# Split from the monolithic evalhub-resource-manager for least-privilege.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: evalhub-jobs-writer
labels:
app.kubernetes.io/name: trustyai-service-operator
app.kubernetes.io/component: evalhub
rules:
- apiGroups: ["batch"]
resources: ["jobs"]
verbs: ["create", "delete"]
19 changes: 19 additions & 0 deletions config/rbac/evalhub/evalhub_mlflow_access_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
# ClusterRoleBinding granting the operator SA the evalhub-mlflow-access permissions.
# The operator needs to hold these permissions itself in order to create
# namespace-scoped RoleBindings that reference this ClusterRole (RBAC escalation prevention).
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: evalhub
app.kubernetes.io/name: trustyai-service-operator
name: evalhub-mlflow-access-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: evalhub-mlflow-access
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
18 changes: 18 additions & 0 deletions config/rbac/evalhub/evalhub_mlflow_access_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
---
# ClusterRole for MLflow kubernetes-auth access
# MLflow's kubernetes-workspace-provider checks permissions via SelfSubjectAccessReview
# against the "mlflow.kubeflow.org" API group (not core Kubernetes resources).
# This role is pre-created at operator installation time and bound to
# EvalHub ServiceAccounts via RoleBindings created by the operator.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: evalhub-mlflow-access
labels:
app.kubernetes.io/name: trustyai-service-operator
app.kubernetes.io/component: evalhub
rules:
- apiGroups: ["mlflow.kubeflow.org"]
resources:
- experiments
verbs: ["create", "get", "list", "update", "delete"]
19 changes: 19 additions & 0 deletions config/rbac/evalhub/evalhub_mlflow_jobs_binding.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
---
# ClusterRoleBinding granting the operator SA the evalhub-mlflow-jobs-access permissions.
# The operator needs to hold these permissions itself in order to create
# namespace-scoped RoleBindings that reference this ClusterRole (RBAC escalation prevention).
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
labels:
app.kubernetes.io/component: evalhub
app.kubernetes.io/name: trustyai-service-operator
name: evalhub-mlflow-jobs-access-binding
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: evalhub-mlflow-jobs-access
subjects:
- kind: ServiceAccount
name: controller-manager
namespace: system
17 changes: 17 additions & 0 deletions config/rbac/evalhub/evalhub_mlflow_jobs_role.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
---
# ClusterRole for MLflow kubernetes-auth access (jobs only)
# Jobs only need to create experiments and log metrics — they should not
# update or delete existing experiments. The proxy SA retains full CRUD
# via the broader evalhub-mlflow-access ClusterRole.
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: evalhub-mlflow-jobs-access
labels:
app.kubernetes.io/name: trustyai-service-operator
app.kubernetes.io/component: evalhub
rules:
- apiGroups: ["mlflow.kubeflow.org"]
resources:
- experiments
verbs: ["create", "get", "list"]
20 changes: 0 additions & 20 deletions config/rbac/evalhub_jobs_proxy_role.yaml

This file was deleted.

26 changes: 0 additions & 26 deletions config/rbac/evalhub_resource_manager_role.yaml

This file was deleted.

13 changes: 9 additions & 4 deletions config/rbac/kustomization.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,15 @@ resources:
- auth_proxy_role.yaml
- auth_proxy_role_binding.yaml
- auth_proxy_client_clusterrole.yaml
- evalhub_proxy_role.yaml
- evalhub_jobs_proxy_role.yaml
- evalhub_resource_manager_role.yaml
- evalhub_resource_manager_binding.yaml
- evalhub/evalhub_auth_reviewer_role.yaml
- evalhub/evalhub_jobs_writer_role.yaml
- evalhub/evalhub_jobs_writer_binding.yaml
- evalhub/evalhub_job_config_role.yaml
- evalhub/evalhub_job_config_binding.yaml
- evalhub/evalhub_mlflow_access_role.yaml
- evalhub/evalhub_mlflow_access_binding.yaml
- evalhub/evalhub_mlflow_jobs_role.yaml
- evalhub/evalhub_mlflow_jobs_binding.yaml
- nemoguardrail_editor_role.yaml
- nemoguardrail_viewer_role.yaml
- trustyaiservice_editor_role.yaml
Expand Down
2 changes: 1 addition & 1 deletion config/rbac/role.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,7 @@ rules:
- rbac.authorization.k8s.io
resources:
- rolebindings
- roles
verbs:
- create
- delete
Expand Down Expand Up @@ -251,7 +252,6 @@ rules:
verbs:
- create
- get
- update
- apiGroups:
- trustyai.opendatahub.io
resources:
Expand Down
9 changes: 6 additions & 3 deletions controllers/evalhub/configmap.go
Original file line number Diff line number Diff line change
Expand Up @@ -326,9 +326,12 @@ func (r *EvalHubReconciler) generateProxyConfigData(instance *evalhubv1alpha1.Ev
proxyConfig := map[string]interface{}{
"authorization": map[string]interface{}{
"resourceAttributes": map[string]interface{}{
"namespace": instance.Namespace,
"apiGroup": "trustyai.opendatahub.io",
"resource": "evalhubs",
"namespace": instance.Namespace,
"apiGroup": "trustyai.opendatahub.io",
"resource": "evalhubs",
// kube-rbac-proxy expects the Kubernetes ResourceAttributes key "name".
// Keep "resourceName" for compatibility with older config consumers.
"name": instance.Name,
"resourceName": instance.Name,
"subresource": "proxy",
},
Expand Down
11 changes: 11 additions & 0 deletions controllers/evalhub/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,17 @@ const (
dbDriver = "pgx"
dbDefaultMaxOpen = 25
dbDefaultMaxIdle = 5

// Service CA configuration
serviceCAVolumeName = "service-ca"
serviceCAMountPath = "/etc/evalhub/ca"
serviceCACertFile = "service-ca.crt"

// MLFlow projected token configuration
mlflowTokenVolumeName = "mlflow-token"
mlflowTokenMountPath = "/var/run/secrets/mlflow"
mlflowTokenFile = "token"
mlflowTokenExpiration = 3600 // seconds
)

var (
Expand Down
49 changes: 47 additions & 2 deletions controllers/evalhub/deployment.go
Original file line number Diff line number Diff line change
Expand Up @@ -119,6 +119,18 @@ func (r *EvalHubReconciler) buildDeploymentSpec(ctx context.Context, instance *e
Name: "EVALHUB_INSTANCE_NAME",
Value: instance.Name,
},
{
Name: "MLFLOW_CA_CERT_PATH",
Value: serviceCAMountPath + "/" + serviceCACertFile,
},
{
Name: "MLFLOW_WORKSPACE",
Value: instance.Namespace,
},
{
Name: "MLFLOW_TOKEN_PATH",
Value: mlflowTokenMountPath + "/" + mlflowTokenFile,
},
}

// Merge environment variables with CR values taking precedence
Expand All @@ -131,6 +143,16 @@ func (r *EvalHubReconciler) buildDeploymentSpec(ctx context.Context, instance *e
MountPath: "/etc/evalhub",
ReadOnly: true,
},
{
Name: serviceCAVolumeName,
MountPath: serviceCAMountPath,
ReadOnly: true,
},
{
Name: mlflowTokenVolumeName,
MountPath: mlflowTokenMountPath,
ReadOnly: true,
},
}
if instance.Spec.IsDatabaseConfigured() {
volumeMounts = append(volumeMounts, corev1.VolumeMount{
Expand All @@ -139,7 +161,6 @@ func (r *EvalHubReconciler) buildDeploymentSpec(ctx context.Context, instance *e
ReadOnly: true,
})
}

// Container definition based on k8s examples
container := corev1.Container{
Name: containerName,
Expand Down Expand Up @@ -296,6 +317,31 @@ func (r *EvalHubReconciler) buildDeploymentSpec(ctx context.Context, instance *e
},
},
},
{
Name: serviceCAVolumeName,
VolumeSource: corev1.VolumeSource{
ConfigMap: &corev1.ConfigMapVolumeSource{
LocalObjectReference: corev1.LocalObjectReference{
Name: instance.Name + "-service-ca",
},
},
},
},
{
Name: mlflowTokenVolumeName,
VolumeSource: corev1.VolumeSource{
Projected: &corev1.ProjectedVolumeSource{
Sources: []corev1.VolumeProjection{
{
ServiceAccountToken: &corev1.ServiceAccountTokenProjection{
Path: mlflowTokenFile,
ExpirationSeconds: func() *int64 { e := int64(mlflowTokenExpiration); return &e }(),
},
},
},
},
},
},
}
if instance.Spec.IsDatabaseConfigured() {
volumes = append(volumes, corev1.Volume{
Expand All @@ -311,7 +357,6 @@ func (r *EvalHubReconciler) buildDeploymentSpec(ctx context.Context, instance *e
},
})
}

// Pod template with both containers and required volumes
podTemplate := corev1.PodTemplateSpec{
ObjectMeta: metav1.ObjectMeta{
Expand Down
Loading
Loading