feat(rbac): scope OIDC kubectl/Headlamp access to read-only#1657
Open
devantler wants to merge 2 commits into
Open
feat(rbac): scope OIDC kubectl/Headlamp access to read-only#1657devantler wants to merge 2 commits into
devantler wants to merge 2 commits into
Conversation
OIDC (Dex + GitHub) was bound to cluster-admin via the oidc-admin
ClusterRoleBinding, so any browser login became full admin. Make
day-to-day OIDC access least-privilege (read-only) and keep admin as
break-glass via the root client-certificate kubeconfig stored in the
vault.
- Add cluster-reader ClusterRole: cluster-scoped infra reads (nodes,
PVs, storage, CRDs, API services, CSRs, RBAC objects, node/pod
metrics). Excludes Secrets and all write/exec verbs.
- Replace oidc-admin (cluster-admin) with two read-only bindings:
oidc-view (built-in view) + oidc-cluster-reader (cluster-reader),
both for User oidc:${admin_email}.
- Update docs/oidc-kubectl.md: read-only model + break-glass procedure.
roleRef is immutable, so this is a delete+recreate of the binding. The
cert-based admin path is untouched, so there is no lockout window.
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR changes the RBAC model for Dex/GitHub OIDC logins so day-to-day access (kubectl + Headlamp) is read-only, and reserves cluster-admin for break-glass via the root client-certificate kubeconfig stored in the vault.
Changes:
- Added a new
cluster-readerClusterRole to cover cluster visibility gaps not provided by the built-inviewrole (nodes, PVs, CRDs, API services, classes, metrics, RBAC objects, etc.) withget/list/watchonly. - Replaced the
oidc-admin(cluster-admin) ClusterRoleBinding with two read-only bindings:oidc-view(built-inview) +oidc-cluster-reader(cluster-reader). - Updated OIDC kubectl documentation to reflect the read-only + break-glass workflow.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
| k8s/bases/infrastructure/cluster-roles/kustomization.yaml | Registers the new cluster-reader role in the cluster-roles base. |
| k8s/bases/infrastructure/cluster-roles/cluster-reader.yaml | Introduces the read-only cluster-reader ClusterRole covering additional visibility resources. |
| k8s/bases/infrastructure/cluster-role-bindings/kustomization.yaml | Switches the base to apply oidc-readonly.yaml instead of oidc-admin.yaml. |
| k8s/bases/infrastructure/cluster-role-bindings/oidc-readonly.yaml | Adds read-only bindings (view + cluster-reader) for the OIDC user identity. |
| k8s/bases/infrastructure/cluster-role-bindings/oidc-admin.yaml | Removes the cluster-admin binding for OIDC identity. |
| docs/oidc-kubectl.md | Updates instructions and adds break-glass admin guidance consistent with the new RBAC model. |
Address Copilot review on #1657: the cluster-reader ClusterRole and its binding were described as "cluster-scoped infra", but they also grant a few namespaced resources cluster-wide (RBAC roles/rolebindings and pod metrics). Reword the header comment, the binding comment, and the docs RBAC table to say "what `view` omits — mostly cluster-scoped, plus RBAC objects and pod metrics". No rule changes. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
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.
Why
OIDC access (Dex + GitHub) was bound to cluster-admin via the
oidc-adminClusterRoleBinding — so any browser login (kubectl and Headlamp) became full admin. This makes day-to-day OIDC access read-only (least privilege), and reserves admin for break-glass via the root client-certificate kubeconfig kept in the vault.This is Part A of moving the operator's daily prod credentials to dev-friendly, OIDC-backed, read-only ones. Part B (swapping the local
~/.kube/configto OIDC-only and generating anos:reader~/.talos/config) is a local-workstation step, done after this is reconciled and verified — intentionally not in this PR.What changed
cluster-roles/cluster-reader.yaml— a ClusterRole for the cluster-scoped resources the built-inviewrole omits: nodes, PVs, storage classes, CRDs, API services, priority/runtime/ingress classes, CSRs, RBAC objects, and node/pod metrics (kubectl top). Excludes Secrets and every write/exec verb (get/list/watch only).cluster-role-bindings/oidc-admin.yaml(→cluster-admin) withoidc-readonly.yaml, two bindings forUser: oidc:${admin_email}:oidc-viewviewoidc-cluster-readercluster-readerdocs/oidc-kubectl.mdupdated for the read-only model + a Break-glass admin access section.flux-web-admins(the limited Flux-UI binding) is unchanged.Security model after this change
Design notes
roleRefis immutable, so changing the role is a delete + recreate of the binding (Flux prunesoidc-admin, applies the new ones). The cert-based admin path is untouched, so there is no lockout window during rollout.viewrather than mutatingviewglobally via aggregation, so no other subject's permissions change.view's conservative defaults is read access to RBAC objects — invaluable for diagnosingForbiddenerrors, and exposes no secret material. Easy to drop if undesired.Rollout / safety
kubectl auth whoami,auth can-i --list,get secrets→ Forbidden) while still holding the cert admin as fallback.Validation
kubectl kustomizebuilds clean for bothproviders/hetzner/infrastructureandproviders/docker/infrastructure.ksail workload validateandksail --config ksail.prod.yaml workload validate— 257 files validated, both.🤖 Generated with Claude Code