Skip to content

Commit a288dc1

Browse files
andyatmiamiclaude
andcommitted
feat: allow auth overrides in debug menu
Backend auth is enabled by default in the Tilt dev environment (DISABLE_AUTH=false). Contributors need a way to set the kubeflow-userid and kubeflow-groups request headers from the frontend UI, and the dev cluster needs RBAC and access logging infrastructure to support end-to-end auth testing. Frontend (debug auth menu): - Add devAuth.ts utility with localStorage helpers and Axios interceptor - Add DebugAuthSection component with User/Groups form fields - Replace Debug page placeholder with the new auth section - Register interceptor on all API instances in notebookApisImpl - Add unit tests for all devAuth utility functions (12 tests) Dev infrastructure (developing/): - Add RBAC manifests for two dev users: "admin" (cluster-wide via kubeflow-workspaces-admin + supplement) and "user" (namespace-scoped in default via kubeflow-workspaces-edit + supplement), using the controller-defined ClusterRoles for realistic Kubeflow RBAC behavior - Add Istio access logging with structured JSON output including kubeflow-userid and kubeflow-groups headers, using MeshConfig extension provider and Telemetry API - Extract istioctl install flags into IstioOperator values file (developing/manifests/istio-install-values.yaml) - Move kind.yaml from scripts/ to manifests/ alongside other config - Update Tiltfile with dev-rbac and istio-gateway-logging resources - Document RBAC users and access logging in DEVELOPMENT_GUIDE.md Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com> Signed-off-by: Andy Stoneberg <astonebe@redhat.com>
1 parent 500c358 commit a288dc1

16 files changed

Lines changed: 520 additions & 36 deletions

File tree

DEVELOPMENT_GUIDE.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,6 +144,40 @@ Access the components through the Istio ingress gateway:
144144
145145
You can now make changes to the codebase, and Tilt will automatically rebuild and redeploy the affected components.
146146
147+
### Tilt - Authentication & RBAC
148+
149+
Tilt deploys RBAC bindings for two dev users from [`developing/manifests/rbac/`](developing/manifests/rbac/).
150+
The backend authenticates requests via `kubeflow-userid` and `kubeflow-groups` headers, then authorizes each API call with a Kubernetes [SubjectAccessReview](https://kubernetes.io/docs/reference/access-authn-authz/authorization/#checking-api-access).
151+
152+
| User | Scope | Description |
153+
|------|-------|-------------|
154+
| `admin` | Cluster-wide | Bound to `kubeflow-workspaces-admin` (workspaces) plus a supplement for WorkspaceKinds, PVCs, secrets, and namespaces. Full access to all resources. |
155+
| `user` | `default` namespace | Bound to `kubeflow-workspaces-edit` in `default` plus a supplement for PVCs and secrets. Cannot manage WorkspaceKinds or access other namespaces. |
156+
157+
These bindings use the same `kubeflow-workspaces-*` ClusterRoles that are defined by the [controller manifests](workspaces/controller/manifests/kustomize/base/manager/user_cluster_roles.yaml), so they reflect realistic Kubeflow RBAC behavior.
158+
159+
> [!TIP]
160+
>
161+
> You can switch between users from the **Debug** page in the frontend UI.
162+
> The default user is `admin`. Switch to `user` to test non-admin behavior (e.g., namespace-scoped permissions, 403 responses on admin-only pages).
163+
164+
### Tilt - Access Logging
165+
166+
Istio access logging is enabled on the ingress gateway, producing structured JSON logs that include authentication headers.
167+
This is useful for verifying that `kubeflow-userid` and `kubeflow-groups` headers flow correctly from the frontend through Istio to the backend.
168+
169+
To tail the access logs:
170+
171+
```bash
172+
kubectl logs -n istio-system -l app=istio-ingressgateway -f
173+
```
174+
175+
Example log entry:
176+
177+
```json
178+
{"duration":105,"kubeflow_groups":null,"kubeflow_userid":"admin","method":"GET","path":"/workspaces/api/v1/workspaces/default","response_code":200,"timestamp":"2026-05-21T14:12:11.965Z","upstream":"10.244.1.9:4000"}
179+
```
180+
147181
### Tilt - Clean Up
148182
149183
When you are done developing with Tilt, you can stop it and clean up the resources.

developing/Tiltfile

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,37 @@ k8s_resource(
6262
)
6363

6464

65+
# ============================================================================
66+
# Dev RBAC
67+
# ============================================================================
68+
# Create RBAC bindings for dev users (admin, user).
69+
# Uses the kubeflow-workspaces-* ClusterRoles from controller manifests,
70+
# plus dev-only supplements for resources the backend also checks (PVCs, secrets, etc).
71+
72+
rbac_path = os.path.join(tilt_root, "manifests/rbac")
73+
k8s_yaml(
74+
kustomize(rbac_path, kustomize_bin=kustomize_bin),
75+
allow_duplicates=True,
76+
)
77+
78+
k8s_resource(
79+
objects=[
80+
"dev-admin-workspaces:clusterrolebinding",
81+
"dev-admin-supplement:clusterrole",
82+
"dev-admin-supplement:clusterrolebinding",
83+
"dev-user-workspaces:rolebinding",
84+
"dev-user-global-read:clusterrole",
85+
"dev-user-global-read:clusterrolebinding",
86+
"dev-user-resources:role",
87+
"dev-user-resources:rolebinding",
88+
],
89+
new_name="dev-rbac",
90+
resource_deps=["workspaces-controller"],
91+
pod_readiness="ignore",
92+
labels=["rbac"],
93+
)
94+
95+
6596
# ============================================================================
6697
# Backend
6798
# ============================================================================
@@ -94,7 +125,7 @@ for o in backend_objects:
94125
"SWAGGER_SCHEME": "https",
95126
"SWAGGER_HOST": "localhost:8443",
96127
"SWAGGER_BASE_PATH": "/workspaces/api/v1",
97-
"DISABLE_AUTH": "true",
128+
"DISABLE_AUTH": "false",
98129
}
99130

100131
# Replace existing keys and add missing ones
@@ -262,6 +293,7 @@ k8s_resource(
262293
"selfsigned-issuer:clusterissuer",
263294
"gateway-tls:certificate",
264295
"kubeflow-gateway:gateway",
296+
"gateway-access-logging:telemetry",
265297
],
266298
new_name="istio-gateway",
267299
pod_readiness="ignore",

developing/manifests/istio-gateway/kustomization.yaml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,4 +4,5 @@ kind: Kustomization
44
resources:
55
- namespace.yaml
66
- gateway-cert.yaml
7-
- gateway.yaml
7+
- gateway.yaml
8+
- telemetry.yaml
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
apiVersion: telemetry.istio.io/v1
2+
kind: Telemetry
3+
metadata:
4+
name: gateway-access-logging
5+
namespace: istio-system
6+
spec:
7+
selector:
8+
matchLabels:
9+
app: istio-ingressgateway
10+
accessLogging:
11+
- providers:
12+
- name: dev-access-log
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
apiVersion: install.istio.io/v1alpha1
2+
kind: IstioOperator
3+
spec:
4+
profile: default
5+
components:
6+
cni:
7+
enabled: true
8+
meshConfig:
9+
extensionProviders:
10+
- name: dev-access-log
11+
envoyFileAccessLog:
12+
path: /dev/stdout
13+
logFormat:
14+
labels:
15+
timestamp: "%START_TIME%"
16+
method: "%REQ(:METHOD)%"
17+
path: "%REQ(X-ENVOY-ORIGINAL-PATH?:PATH)%"
18+
response_code: "%RESPONSE_CODE%"
19+
kubeflow_userid: "%REQ(KUBEFLOW-USERID)%"
20+
kubeflow_groups: "%REQ(KUBEFLOW-GROUPS)%"
21+
upstream: "%UPSTREAM_HOST%"
22+
duration: "%DURATION%"
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: ClusterRoleBinding
3+
metadata:
4+
name: dev-admin-workspaces
5+
subjects:
6+
- kind: User
7+
name: admin
8+
apiGroup: rbac.authorization.k8s.io
9+
roleRef:
10+
kind: ClusterRole
11+
name: kubeflow-workspaces-admin
12+
apiGroup: rbac.authorization.k8s.io
13+
---
14+
# Dev supplement: resources the backend checks via SubjectAccessReview
15+
# that kubeflow-workspaces-admin doesn't cover.
16+
# Note: storageclasses "list" is omitted because the frontend always passes a
17+
# namespace query param, which triggers a "create PVCs" check instead.
18+
apiVersion: rbac.authorization.k8s.io/v1
19+
kind: ClusterRole
20+
metadata:
21+
name: dev-admin-supplement
22+
rules:
23+
- apiGroups: [""]
24+
resources: [namespaces]
25+
verbs: [list]
26+
- apiGroups: [""]
27+
resources: [persistentvolumeclaims]
28+
verbs: [create, delete, get, list]
29+
- apiGroups: [""]
30+
resources: [secrets]
31+
verbs: [create, delete, get, list, update]
32+
- apiGroups: [kubeflow.org]
33+
resources: [workspacekinds]
34+
verbs: [create, delete, get, list, update]
35+
---
36+
apiVersion: rbac.authorization.k8s.io/v1
37+
kind: ClusterRoleBinding
38+
metadata:
39+
name: dev-admin-supplement
40+
subjects:
41+
- kind: User
42+
name: admin
43+
apiGroup: rbac.authorization.k8s.io
44+
roleRef:
45+
kind: ClusterRole
46+
name: dev-admin-supplement
47+
apiGroup: rbac.authorization.k8s.io
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
apiVersion: kustomize.config.k8s.io/v1beta1
2+
kind: Kustomization
3+
4+
resources:
5+
- admin.yaml
6+
- user.yaml
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
apiVersion: rbac.authorization.k8s.io/v1
2+
kind: RoleBinding
3+
metadata:
4+
name: dev-user-workspaces
5+
namespace: default
6+
subjects:
7+
- kind: User
8+
name: user
9+
apiGroup: rbac.authorization.k8s.io
10+
roleRef:
11+
kind: ClusterRole
12+
name: kubeflow-workspaces-edit
13+
apiGroup: rbac.authorization.k8s.io
14+
---
15+
# Dev supplement: cluster-scoped namespace listing for the namespace selector.
16+
# Other cluster-wide permissions (workspacekinds, storageclasses) are NOT needed
17+
# because the frontend passes namespace context to those endpoints, which triggers
18+
# namespace-scoped checks (e.g., "create PVCs" instead of "list storageclasses").
19+
apiVersion: rbac.authorization.k8s.io/v1
20+
kind: ClusterRole
21+
metadata:
22+
name: dev-user-global-read
23+
rules:
24+
- apiGroups: [""]
25+
resources: [namespaces]
26+
verbs: [list]
27+
---
28+
apiVersion: rbac.authorization.k8s.io/v1
29+
kind: ClusterRoleBinding
30+
metadata:
31+
name: dev-user-global-read
32+
subjects:
33+
- kind: User
34+
name: user
35+
apiGroup: rbac.authorization.k8s.io
36+
roleRef:
37+
kind: ClusterRole
38+
name: dev-user-global-read
39+
apiGroup: rbac.authorization.k8s.io
40+
---
41+
# Dev supplement: PVC and secret management in default namespace
42+
apiVersion: rbac.authorization.k8s.io/v1
43+
kind: Role
44+
metadata:
45+
name: dev-user-resources
46+
namespace: default
47+
rules:
48+
- apiGroups: [""]
49+
resources: [persistentvolumeclaims]
50+
verbs: [create, delete, get, list]
51+
- apiGroups: [""]
52+
resources: [secrets]
53+
verbs: [create, delete, get, list, update]
54+
---
55+
apiVersion: rbac.authorization.k8s.io/v1
56+
kind: RoleBinding
57+
metadata:
58+
name: dev-user-resources
59+
namespace: default
60+
subjects:
61+
- kind: User
62+
name: user
63+
apiGroup: rbac.authorization.k8s.io
64+
roleRef:
65+
kind: Role
66+
name: dev-user-resources
67+
apiGroup: rbac.authorization.k8s.io

developing/scripts/setup-istio.sh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,9 @@ if "${ISTIOCTL}" verify-install >/dev/null 2>&1; then
2626
echo "Istio is already installed"
2727
else
2828
echo "Installing Istio with default profile and CNI plugin..."
29-
"${ISTIOCTL}" install --set profile=default --set components.cni.enabled=true -y
29+
"${ISTIOCTL}" install \
30+
-f "${DEVELOPING_DIR}/manifests/istio-install-values.yaml" \
31+
-y
3032
fi
3133

3234
echo "Waiting for Istio control plane to be ready..."

0 commit comments

Comments
 (0)