fix: separate ServiceAccount for router workloads#433
fix: separate ServiceAccount for router workloads#433ambient-code[bot] wants to merge 4 commits intomainfrom
Conversation
The controller and router previously shared the same `controller-manager` ServiceAccount, giving the router unnecessary cluster-wide secrets CRUD access. This creates a dedicated `router-sa` ServiceAccount with no RBAC bindings and `automountServiceAccountToken: false`, following the principle of least privilege. Fixes #351 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
|
Important Review skippedBot user detected. To trigger a single review, invoke the ⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: You can disable this status message by setting the Use the checkbox below for a quick retry:
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
✅ Deploy Preview for jumpstarter-docs ready!
To edit notification comments on pull requests, go to your Netlify project configuration. |
| kind: Role | ||
| metadata: | ||
| labels: | ||
| app.kubernetes.io/name: jumpstarter-router |
There was a problem hiding this comment.
do not modify any helm, it has been deprecated.
Helm charts are deprecated; only the operator deployment path should be modified for the separate router ServiceAccount. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Status UpdateReview feedback addressed
CI failures analysisThe following CI jobs failed:
The Helm chart revert should resolve the helm-path failures. The operator-path changes (separate |
The router process needs Kubernetes API access at startup to load its configuration from a ConfigMap (via ctrl.GetConfigOrDie() and LoadRouterConfiguration). Setting AutomountServiceAccountToken: false on both the ServiceAccount and pod spec prevented the router from authenticating, causing the pod to crash and never become ready (180s timeout in CI). Changes: - Remove AutomountServiceAccountToken: false from router ServiceAccount and pod spec so the token is mounted - Add a minimal router Role granting read-only access to configmaps and secrets (the only resources the router needs) - Add a RoleBinding to bind the router Role to the router ServiceAccount This maintains the security goal of separating the router SA from the controller SA while granting only the minimum permissions needed. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Root cause of CI failureThe router pod ( The router's Fix
This maintains the security goal of separating the router SA from the controller SA (the router SA has far fewer permissions than the controller SA) while providing the minimum permissions the router actually needs. |
CI Fix: Router ServiceAccount needs K8s API accessRoot cause: The router process calls Fix (commit 93ce272):
This maintains the security separation goal — the router SA has far fewer permissions than the controller SA — while granting the minimum permissions the router actually needs to function. |
| APIGroups: []string{""}, | ||
| Resources: []string{"secrets"}, | ||
| Verbs: []string{"get", "list", "watch"}, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
does the router really need to get/list/watch secrets? why?
| Resources: []string{"secrets"}, | ||
| Verbs: []string{"get", "list", "watch"}, | ||
| }, | ||
| }, |
There was a problem hiding this comment.
Good catch — you're right, it doesn't. Looking at LoadRouterConfiguration in controller/internal/config/config.go, the router only calls client.Get() on a ConfigMap (jumpstarter-controller), and LoadGrpcConfiguration just parses the in-memory config struct without any K8s API calls. The router never reads secrets.
I'll remove the secrets permission from the router Role so it only has get/list/watch on configmaps.
The router only reads a ConfigMap via LoadRouterConfiguration() and does not access any secrets. Remove the secrets PolicyRule from the router Role per review feedback. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Summary
router-saServiceAccount with zero RBAC bindings andautomountServiceAccountToken: falsefor router workloadscontroller-managerSA with full RBAC (secrets CRUD, CRD access, leader election)Fixes #351
Changes
Helm chart
rbac/service_account.yaml: Split intocontroller-manager(controller) androuter-sa(router)rbac/role_binding.yaml,leader_election_role.yaml,leader_election_role_binding.yaml: Updated labels fromjumpstarter-routertojumpstarter-controllerrouter-deployment.yaml,additional-router-deployment.yaml: Userouter-sawithautomountServiceAccountToken: falseOperator
rbac.go: AddedcreateRouterServiceAccount()and reconciliation logic for the router SAjumpstarter_controller.go: UpdatedcreateRouterDeployment()to use{name}-router-sawithautomountServiceAccountToken: falseTest plan
go build ./...passes for the operator (confirmed locally)router-sawith no token mountedcontroller-managerSA with full RBACcontroller-managerSA🤖 Generated with Claude Code