Repository navigation
Isolate experiment runners and infrastructure credentials - #714
Merged
Merged
Conversation
Replace the job-creator permissions on the default ServiceAccount, which runner Pods executing user code also used, with one ServiceAccount per component and least-privilege RBAC. Runners get an account with no permissions. Add NetworkPolicies for runner egress and backend ingress, and remove the legacy bindings from existing clusters. Part of #709 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The frontend proves its identity with an audience-bound ServiceAccount token that the backend checks through TokenReview. Each runner gets a token that is only valid for its own experiment and can only write progress fields. Runner Jobs run without an API token, as non-root with a read-only root filesystem, dropped capabilities, resource limits and a deadline; admin and privileged experiments keep root for apt-get. The backend now sends notification emails, so runners no longer receive the Gmail credentials. Part of #709 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
The runner authenticates every backend call with its experiment token and asks the backend to send the notification email. Uploaded zip files are checked for path escapes and size before extraction. The image gets an unprivileged user. Part of #709 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…iments Send the backend-audience ServiceAccount token on start and cancel requests. The start route now requires a signed-in user who owns the experiment (or an admin), and the stored creator role and email come from the session instead of the request. Part of #709 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
…oundaries The production chart values read the root password from a Secret that deploy.sh creates. Add a security page to the docs and a script that verifies the isolation on a development cluster. Part of #709 Co-Authored-By: Claude Fable 5.2 <noreply@anthropic.com>
1 task done
5 tasks
rhit-changs
self-requested a review
November 12, 2026 23:20
rhit-changs
enabled auto-merge
November 12, 2026 23:21
rhit-changs
approved these changes
Nov 12, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
#711 and #712 were merged into main as
d1ccafeand644c797. This PR now targetsmainas the final PR in the stack.Security hardening: isolate experiment runners and infrastructure credentials
Closes #709. Carries over the findings from #476.
User-submitted experiment code now runs behind a clear boundary. A runner can compute and report its own results, and nothing else. The Python coverage scripts now propagate pytest failures to CI.
Identities and permissions
kubernetes_init/security/). Nothing is bound todefaultany more; the oldjob-creatorClusterRole is removed.default, create TokenReviews. Frontend: list Pods, read Pod logs, patch the two Deployments and the worker node (admin redeploy). Runner: no permissions, no API token mounted.kubernetes_init/init.pyapply the manifests.init.py --updatemigrates an existing cluster.Runner containment
apps/backend/job-runner.yamlbymodules/runner_job.py: non-root user 10001, all capabilities dropped, no privilege escalation, read-only root filesystem with four scratch volumes, default seccomp profile.apps/runner/modules/archive.py).Backend authentication
glados-backend) that the backend checks with the TokenReview API.Network and MongoDB
kubernetes_init/security/network-policies.yaml: runners accept nothing inbound and may reach only DNS, the backend and public addresses; the backend accepts only frontend and runner Pods. Flannel does not enforce NetworkPolicy, so until the cluster has an enforcing plugin the token checks are the boundary that holds. Documented as a known gap.deploy.shcreates theglados-mongodb-authSecret instead. The previously published password should be rotated (steps in the docs).Runtime versions
Tests and checks
coverage.shin both apps now returns pytest's exit status. It previously ended with anecho, so CI could never fail; six stale runner fixture failures are now resolved by adding the current required fields and updating the expected defaults in the tests.default, secrets per Deployment, non-root runner), Job construction, endpoint authentication, mail, archive extraction.development_scripts/security/verify_isolation.shchecks a development cluster: what each identity may do, and whether a runner-shaped Pod can reach any backend endpoint without credentials, MongoDB, or the API server.docs/docs/infrastructure/security.mddescribing the boundary, limits, rollout and known gaps.Rollout
Allow existing runner Jobs to finish before rolling out the authenticated backend. Existing Jobs have no runner token and cannot report to the new endpoints.
Restarting the Deployments is not enough the first time. From
kubernetes_init/with cluster access, runpython3 init.py --update, then rotate the MongoDB password and createglados-mongodb-authbeforehelm upgrade.Known gaps left open
Cancellation changes here connect #712's authorized cancellation to the runner-token lifecycle. Tokens are revoked after accepted deletion, failed deletion preserves runner access, and missing-Job retries remain supported.
Follow-up validation
ebc13bapassed all 43 tests. Local Windows execution passed 40 tests with three previously documented CSV newline failures.Hosted CI on the latest commit
All 9 applicable checks passed on
249e7be, including frontend tests/type checks/lint (647 tests), backend tests (91), Google authentication checks, all container builds, documentation build, and runner lint/tests (43 tests; pylint 9.53/10). Frontend CI, backend CI, runner CI.Collaborator review integration
Includes #711 at
d1faa36and #712 at99dc835. The collaborator's54d2183cancellation UI and structured refusal behavior are preserved. Late runner writes cannot overwrite archived terminal experiments, including archived cancellations. Runner service credentials and token revocation remain integrated with the common cancellation service.Runner fixture follow-up
Only
apps/runner/tests/test_experiment.pyandapps/runner/tests/test_parameters.pychanged inebc13ba. Experiment fixtures now includecreatorRole,creatorEmail,trialResultLineNumber, andsendEmail. Expected defaults includeexperimentExecutableandstatus, and Boolean/String fixtures includeuseDefault. Existing assertions continue to cover valid inputs, missing defaults, and invalid inputs.An independent reviewer found no actionable issues and independently reproduced 25 passing targeted tests on Python 3.9. The full Linux runner CI passed all 43 tests. CI log https://github.com/AutomatingSciencePipeline/Monorepo/actions/runs/43299522155/job/131466624451 .