RFD 219 - Kubernetes RBAC simplification (#56214)

* RFD Proposal for K8s RBAC simplification.

Signed-off-by: Tim Ross <[email protected]>

* Add section about user flow for day 0 / day 1.

Signed-off-by: Tim Ross <[email protected]>

* PR feedback - add conifguration field, use wildcard for groups.

Signed-off-by: Tim Ross <[email protected]>

* Add section about downgrade in rfd.

Signed-off-by: Tim Ross <[email protected]>

* Update RFD with latest consensus/feedback.

Signed-off-by: Tim Ross <[email protected]>

* Update RFD to use presets instead of managing clusterroles manually.

Signed-off-by: Tim Ross <[email protected]>

* fix typo.

Signed-off-by: Tim Ross <[email protected]>

* PR feedback.

Signed-off-by: Tim Ross <[email protected]>

* Add rollout section.

Signed-off-by: Tim Ross <[email protected]>

* Add backport section.

Signed-off-by: Tim Ross <[email protected]>

* Address PR feedback.

Signed-off-by: Tim Ross <[email protected]>

* Simplify design

Removes the ability to set custom names for ClusterRoleBindings and
instead provides a boolean flag to disable provisiong of Kubernetes
RBAC resource automatically.

Removes left over references to changing the default `kubernetes_groups`
values to prese bindings. All roles will be left referencing the
internal traits and all documentation will be updated to specify
the preset roles as traits for day 0 guides.

* Detail CRB prefixing

* fix: spelling

* fixup: remove reference to provisioning ClusterRoles

Co-authored-by: Hugo Shaka <[email protected]>

* fix: Remove exec confusion section

Co-authored-by: Hugo Shaka <[email protected]>

* fix: describe proposed day 0,1,2 flows better

Co-authored-by: Hugo Shaka <[email protected]>

* fix: remove duplicate metadata:

Co-authored-by: Hugo Shaka <[email protected]>

* Update required approvers

* Update RFD authors

* fix: typo

* Apply suggestion from @hugoShaka

Co-authored-by: Hugo Shaka <[email protected]>

* fix: clarify what the provisioning script is

---------

Signed-off-by: Tim Ross <[email protected]>
Co-authored-by: Tim Ross <[email protected]>
Co-authored-by: rosstimothy <[email protected]>
Co-authored-by: Hugo Shaka <[email protected]>
This commit is contained in:
Guillaume J. Charmes
2025-10-22 19:27:06 +00:00
committed by GitHub
co-authored by Hugo Shaka Tim Ross rosstimothy
parent 82bfc4183c
commit ea58757b6e
2 changed files with 301 additions and 0 deletions
+281
View File
@@ -0,0 +1,281 @@
---
authors: Guillaume Charmes ([email protected]), Tim Ross ([email protected])
state: draft
---
# RFD 0219 - Kubernetes RBAC Simplification
## Required Approvers
- Engineering: (@zmb3 || @rjones || @r0mant) && (@hugoShaka || @tigrato)
Product: @klizhentas
## What
The purpose of this RFD is to propose a simplification of the Kubernetes
RBAC (Role-Based Access Control) within the Teleport project.
The goal is to streamline the user experience and reduce the complexity of
getting up and running on day 0 and managing permissions later on.
## Why
Today, the Kubernetes RBAC in Teleport is complex and can be difficult for
users to manage.
A proper setup requires some external Kubernetes config and matching role
setup.
This complexity leads to misconfigurations and security issues.
Simplifying the RBAC model will help improve usability and security.
### References
A common issue currently is the un-intuitive result of complex rule sets and
more critically, difficult to get setup on day 0.
- @klizhentas struggling to setup a cluster following the `self-hosted` flow:
(internal) <https://gravitational.slack.com/archives/C03SULRAAG3/p1715394587181739>
- Customer confusion on role resolution:
- <https://github.com/gravitational/teleport/issues/45475>
- (internal) <https://goteleport.slack.com/archives/C0582MBSMHN/p1738187497666819>
- Unexpected `exec` grant on read-only user:
(internal) <https://gravitational.slack.com/archives/C32M8FP1V/p1739462454321459?thread_ts=1739462384.714419&cid=C32M8FP1V>
## Goal
Allow preset roles to be used to get started quickly.
## Proposal
### Prior work
While initially planned to be included in this RFD, due to customer requests,
the following has already been implemented and shipped:
- Support arbitrary resources, including CRDs #54426
- Simplify Namespace/Kind behavior #54938
- Handle all known resources on the Teleport side #55099
Given this, as RBAC has already been simplified quite a lot, a scoped down
version of the proposal would be to focus on new installs without impacting
existing customers.
### Preset roles
#### Background
Originally, Teleport preset roles were inspired by Kubernetes roles,
specifically, `edit`, `cluster-admin` and `view`.
- `cluster-admin` allows everything everywhere.
- `edit` allows CRUD on most builtin resources, but not administrative
resources.
- get/list/watch pods (including attach, exec, portforward and proxy),
secrets and services/proxy
- impersonate service accounts
- create/delete/deletecollection/patch/update pods (including exec/attach/
portforward/proxy)
- create pods/evictions
- create/delete/deletecollection/patch/update configmaps, events,
persistentvolumeclaims, replicationcontrollers (including scale), secrets,
serviceaccounts, services (including proxy)
- create serviceaccounts/token
- create/delete/deletecollection/patch/update deployments (including
rollback, scale), replicasets (including scale), statefulsets (including
scale), ingresses, networkpolicies
- create/delete/deletecollection/patch/update horizontalpodautoscalers, cronjobs,
jobs, poddisruptionbudgets, leases
- get/list/watch controllerrevisions, daemonsets, deployments, replicasets,
statefulsets, horizontalpodautoscalers, cronjobs, jobs, poddisruptionbudgets,
ingresses, networkpolicies, leases
- `view` allows read-only access to most builtin resources.
- get/list/watch pods, configmaps, endpoints, persistentvolumeclaims,
replicationcontrollers (including scale), serviceaccounts, services,
bindings, events, limitranges, namespaces, resourcequotas, endpointslices,
controllerrevisions, daemonset, deployments, replicasets, statefulsets,
horizontalpodautoscalers, cronjobs, jobs, poddisruptionbudgets, ingresses,
networkpolicies, leases
This resulted in the following Teleport roles:
- `editor`, which maps to `cluster-admin` and can do everything.
- `access`, which maps to `edit` and can do most CRUD operations.
- `auditor`, which maps to `view` and can do read-only operations.
#### New Kubernetes Bindings
In order to be consistent and allow for seamless use of Kubernetes within
Teleport, we will introduce the following new preset bindings:
- `kubernetes_groups` -> `ClusterRole`
- `teleport:preset:edit` -> `edit`
Can CRUD most basic builtin resources and read some limited administrative resources.
- `teleport:preset:cluster-admin` -> `cluster-admin`
Provides full access to all Kubernetes resources, including CRDs.
- `teleport:preset:view` -> `view`
Provides read-only access to some Kubernetes resources.
On the Kubernetes side, we will create the corresponding `ClusterRoleBindings` based on `kubernetes_groups`.
While there is an existing binding for `cluster-admin` via `system:masters`, it
is not available everywhere and there are no binding for `edit` nor `view`.
For consistency and reliability, we will create one binding for each preset
role.
Those bindings will be available to Teleport users via the user trait feature.
Kubernetes might introduce new API endpoints that should be allowed or denied.
Vendoring those roles on Teleport would require us to update the list for every
Kubernetes version, and would potentially cause a permission issues if a user
deploys an old Teleport version in a modern Kubernetes cluster. Relying on the
Kubernetes built-in roles for RBAC frees us from the maintenance burden and
prevents security issues caused by version mismatch.
Example:
```bash
tctl users add hugo --logins root --kubernetes-group teleport:preset:edit --roles=access
```
### Provisioning
To enable easy setup, provisioning methods will be updated to create the
required new ClusterRoleBindings.
#### Helm Chart
The Helm Chart will by default provision the new Kubernetes resources starting
in v19.0.0. An option will be added to the chart to allow opting out of creating
the default ClusterRoleBindings. All existing release branches will have this
flag set to disable the new functionality to minimize breaking changes.
Example:
```yaml
roles: kube,app,discovery
authToken: foo
proxyAddr: example.devteleport.com:443
kubeClusterName: myCluster
rbac:
defaultClusterRoleBindings: true
```
The ClusterRoleBindings created by the chart will be prefixed with the
chart release and the namespace to allow multiple deployments in the
same Kubernetes cluster not to conflict since ClusterRoleBinding resources
are global and not namespaced.
```yaml
{{- if .Values.rbac.defaultClusterRoleBindings -}}
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: {{ .Release.Name }}-{{ .Release.Namespace }}-preset-edit
```
#### Provision Script
For simplicity, the [provisioning script](https://github.com/gravitational/teleport/blob/89a13c7c7c6538e5b6afc1b820db0e2e3a9b87fb/examples/k8s-auth/get-kubeconfig.sh#L4)
will be updated to always create the Kubernetes resources, and will not provide a means for users to opt out of
the new behavior.
#### Auto Discovery
##### EKS / AKS
For both EKS and AKS, auto-discovery will be updated to create the expected
RBAC resources.
##### GKE
For GKE, we will need to change the documented GCP IAM role to enable admin
privileges.
Teleport will attempt to impersonate a privileged group, but there is a risk
GKE users will not be able to use the new preset roles out of the box.
A special attention to error management will be required to help users
understand the issue and how to resolve it, which can be easily done by
running the provision script for example.
#### Auto-update
Auto-update will not attempt to apply the new model, with the assumption that
existing setups are already working.
### UX
#### Resource enrollment UI
On the Web UI, the initial page generates a _Helm_ command line.
After enrollment, a test page is shown, prompting for a `kubernetes_groups`
value, which defaults to the user's trait and updates it if changed in this
page.
The following page is about testing the connection, and also have a form to
populate a subset of the users/groups.
The initial idea was to allow the user to update it's traits on the fly to not
have to logout/log back in, however, as there is no mention of traits, and
because the form is present on multiple pages with different behavior, and
because it requires the user to initially already have a role assigned that
contains the trait interpolation, we will remove both the 'Setup access' page
and the 'users/groups' form from the 'Test connection' page.
This will result in using the user's auth to test the connection instead of
requiring the user to enter a subset or all of it's groups/users, knowing
that the user cannot make add nor change any.
#### Error management
The error messages when using `kubectl` will be improved to include a link to
the documentation and more details on what is expected. This will help with
initial custom setups that skipped the provided provisioning scripts.
### User flow
#### Current flow
- Day 0 - Initial setup:
- User installs Teleport and sets up a Kubernetes cluster.
- User provisions the Kubernetes cluster using a script, discovery, or Helm
chart to create the impersonation ClusterRole/ClusterRoleBinding.
- User configures Kubernetes RBAC with a custom ClusterRole with some
permissions
- User configures Kubernetes RBAC with a custom ClusterRoleBinding, which
needs to be understood matches with the `kubernetes_groups` field in the
Teleport role.
- User configures Teleport role with `kubernetes_groups`, (unclear what
`kubernetes_users` does from the docs) fields to match the custom
ClusterRoleBinding.
- User configures Teleport role with `kubernetes_resources` and
`kubernetes_labels` to match to match or reduce the permissions granted by
the custom ClusterRole.
- Day 1 - Ongoing management:
- User needs to understand the interaction between the Teleport role and the
underlying Kubernetes RBAC.
- User may need to update the Teleport role if the underlying Kubernetes
RBAC changes.
- No clear guidance on how to which permission should be set where (Teleport
or Kubernetes).
- User may need to troubleshoot unexpected permissions or access issues.
#### Proposed flow
- Day 0 - Initial setup, prospect and hackers:
- Prospect installs Teleport
- Prospect creates its first Teleport local user with the trait `kubernetes_groups: "teleport:preset:cluster-admin"`
- Prospect deploys a Teleport agent in their Kubernetes cluster
- Prospect can access the Kubernetes cluster as administrator with their local Teleport user
- Day 1 - Multiple users, late stage prospect or new Teleport adopter
- Admin has some Kubernetes agents connected, SSO connector set up, and several users
- Admin creates per-team roles with different `spec.allow. kubernetes_labels` to select each team's cluster
- Admin sets the `teleport:preset:edit` or `teleport:preset:view` as `spec.allow.kubernetes_groups`
- Admin grants the role to users using SSO connector or Access Lists
- users from each team can access their Kubernetes clusters
- Day 2 - More granular access, advanced Teleport users
- Admin can create custom Kubernetes rolebindings, deploy them in their clusters and use them in their Teleport roles instead of the presets
- Admin can scope down read and edit roles to select namespaces or resources by using `kubernetes_resources` in their roles
+20
View File
@@ -129,11 +129,16 @@
"CEST",
"CGNAT",
"checkmodule",
"charmes",
"Cieślak",
"ciphertext",
"ckms",
"CLIPRDR",
"clusterawsadm",
"clusterrole",
"clusterroles",
"clusterrolebinding",
"clusterrolebindings",
"cmdline",
"cmpopts",
"cockroachdb",
@@ -147,6 +152,7 @@
"configurator",
"connectionupgrade",
"containerregistry",
"controllerrevisions",
"Corado",
"crashloop",
"creack",
@@ -162,6 +168,7 @@
"customtype",
"CUVE",
"cwallet",
"daemonset",
"Datalog",
"datapoint",
"datapoints",
@@ -173,6 +180,7 @@
"deconfigures",
"decryptable",
"DEFAA",
"deletecollection",
"delims",
"depguard",
"deploymentname",
@@ -180,6 +188,7 @@
"devel",
"devpay",
"devs",
"devteleport",
"diable",
"diceware",
"Dinis",
@@ -211,6 +220,7 @@
"eksctl",
"Elastisearch",
"elif",
"endpointslices",
"enduml",
"Enes",
"Entra",
@@ -280,6 +290,7 @@
"grpcserver",
"Grzegorz",
"gserviceaccount",
"guillaume",
"gvisor",
"gzdunek",
"gzipped",
@@ -287,6 +298,7 @@
"headlessauthn",
"healthcheck",
"healthcheckconfig",
"healthchecks",
"healthz",
"heartbeated",
"heartbeating",
@@ -296,6 +308,7 @@
"HGETALL",
"HKIA",
"HMAC",
"horizontalpodautoscalers",
"hostable",
"hostip",
"hostnames",
@@ -388,6 +401,7 @@
"libpq",
"libudev",
"libykcs",
"limitranges",
"listprofiles",
"litebk",
"livez",
@@ -466,6 +480,7 @@
"namespacing",
"netbox",
"nethealth",
"networkpolicies",
"nindent",
"nistp",
"nklaassen",
@@ -530,6 +545,7 @@
"Pawel",
"pchar",
"PCKS",
"persistentvolumeclaims",
"pgbouncer",
"pgconn",
"PGHOST",
@@ -552,6 +568,7 @@
"plantuml",
"plpgsql",
"pluggable",
"poddisruptionbudgets",
"podname",
"poka",
"policycoreutils",
@@ -640,11 +657,14 @@
"replaceall",
"replayable",
"replicaset",
"replicasets",
"replicationcontrollers",
"reprepro",
"requeries",
"requestable",
"resolv",
"resourcegroups",
"resourcequotas",
"restclient",
"reversetunnel",
"reversetunnelv",