Skip to content

fix(operator): grant the service account read on pods - #294

Merged
v0l merged 2 commits into
masterfrom
fix/operator-pods-rbac-293
Jul 28, 2026
Merged

v0l merged 2 commits into
masterfrom
fix/operator-pods-rbac-293

Conversation

@v0l

@v0l v0l commented Jul 28, 2026

Copy link
Copy Markdown
Contributor

Closes #293.

The operator's ClusterRole never granted pods, so read_workload_health 403s on every pass (lnvps_operator/src/app_deployments.rs:1516) and write_back_status takes its None branch and leaves the stored status untouched — which is exactly the state #276 existed to replace. Deployments were already granted via the apps group, so the replica counts were readable; only the container statuses, which carry the reason, were not.

RBAC here is a static manifest, not something the operator creates: lnvps_operator/src references no rbac.authorization.k8s.io type at all, and lnvps_operator/k8s-minimal.yaml:17-41 is the only ClusterRole in the repo. So the rule is added here and Kieran has to apply it — merging this changes nothing in the cluster on its own.

Read-only (get, list, watch); the operator never writes a pod.

Do not apply this file to the live cluster

The manifest binds lnvps-system/lnvps-operator (k8s-minimal.yaml:14,58); the 403 names system:serviceaccount:lnvps:lnvps-operator. The live install was not created from this file, so kubectl apply -f would grant the running operator nothing and, if the live binding shares the name, would rewrite its subjects and take away the permissions it has now. Filed separately as #295 — that mismatch is not this PR's to fix.

Grant the rule against the live objects instead. Confirm what is actually bound, then patch the role it names:

kubectl get clusterrolebinding lnvps-operator -o yaml   # read roleRef.name and subjects[].namespace
kubectl patch clusterrole <roleRef.name> --type=json \
  -p '[{"op":"add","path":"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/rules/-","value":{"apiGroups":[""],"resources":["pods"],"verbs":["get","list","watch"]}}]'

That touches only the ClusterRole, which is cluster-scoped and carries no namespace, and never the binding.

#291's usage collection is not affected. It reads Prometheus over HTTP (lnvps_operator/src/metrics.rs:47-95), not the Kubernetes API, so it never touches this service account's permissions.

A test parses the shipped manifest and asserts the ClusterRole covers the reads the loop makes (lnvps_operator/src/main.rs:367). Verified it fails on the manifest as it stood.

cargo test --workspace passes at a3bd8bf apart from lnvps_e2e, which needs a migrated MySQL and fails on table-not-found before reaching any assertion; clippy is clean on lnvps_operator.

The reconcile loop lists pods to read why a workload is not ready, but the
ClusterRole never granted it, so every read 403s and the health check falls
back to leaving the stored status alone.
The example manifest is not the deployed one, so asserting on it tests a file the cluster does not use.
@v0l
v0l merged commit bfdb3de into master Jul 28, 2026
1 check passed
@v0l
v0l deleted the fix/operator-pods-rbac-293 branch July 28, 2026 12:31
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Operator cannot list pods in app-N namespaces, so the workload health read added in #276 never runs

1 participant