diff --git a/rfd/0183-access-request-kube-resource-allow-list.md b/rfd/0183-access-request-kube-resource-allow-list.md index 97a6dd2c76b4f..f9f9be51655a8 100644 --- a/rfd/0183-access-request-kube-resource-allow-list.md +++ b/rfd/0183-access-request-kube-resource-allow-list.md @@ -60,7 +60,7 @@ This is already supported. The admin can use `kubernetes_resources` field to res ```yaml kind: role metadata: - name: kube-access-request + name: kube-access spec: allow: # Only lists namespaces starting with "pumpkin-" prefixes @@ -75,6 +75,17 @@ spec: '*': '*' kubernetes_users: - '{{internal.kubernetes_users}}' + +---- + +kind: role +metadata: + name: requester +spec: + allow: + request: + search_as_roles: + - kube-access ``` Requesting for namespace not in this list is denied. @@ -102,7 +113,7 @@ spec: kind: role metadata: - name: kube-access-request + name: kube-access spec: allow: kubernetes_resources: @@ -117,7 +128,18 @@ spec: kubernetes_labels: '*': '*' kubernetes_users: - - '{{internal.kubernetes_users}}' + - '{{internal.kubernetes_users}} + +---- + +kind: role +metadata: + name: requester +spec: + allow: + request: + search_as_roles: + - kube-access ``` ## As an admin, I want to require users to request for Kubernetes subresources instead of the whole Kubernetes cluster @@ -132,7 +154,8 @@ spec: options: request_mode: # Disables requesting whole Kubernetes cluster, but can request any of the kube subresources - kubernetes: ['resource'] + kubernetes_resources: + - kind: * ``` User requesting kube_cluster will be denied. @@ -149,7 +172,9 @@ spec: options: request_mode: # Can request only pods or namespaces - kubernetes: ['pod', 'namespace'] + kubernetes_resources: + - kind: namespace + - kind: pod ``` User requesting any other Kubernetes kind will get denied. @@ -158,7 +183,9 @@ User requesting any other Kubernetes kind will get denied. ## New request field for role spec -We will introduce a new role option under the `options` section named `request_mode`: +We will introduce a new role option under the `options` section named `request_mode` and re-use the existing data structure for [KubernetesResource](https://github.com/gravitational/teleport/blob/c49eb984648b506f3223804784a54ddec8d4d2d3/api/proto/teleport/legacy/types/types.proto#L3293). Not all fields in KubernetesResource object will initially be supported. The first iteration will only support the [`kind` field](https://github.com/gravitational/teleport/blob/c49eb984648b506f3223804784a54ddec8d4d2d3/api/proto/teleport/legacy/types/types.proto#L3297). + +The `kind` field will support `asterisks` and the names of all [Kubernetes subresource kinds](https://github.com/gravitational/teleport/blob/110b23aefb3c4b91c9d8cca594041b93f0e078dd/api/types/constants.go#L1233). ```yaml kind: role @@ -168,31 +195,24 @@ spec: options: # new field request_mode: - kubernetes: [] + kubernetes_resources: [] ``` -The `options.request_mode.kubernetes` list will accept the same const we use in our backend [kube_cluster](https://github.com/gravitational/teleport/blob/5924c97d7fc831aeed20990e4c72fe6a0bc95fba/api/types/constants.go#L203) and any of its [Kubernetes subresource kinds](https://github.com/gravitational/teleport/blob/110b23aefb3c4b91c9d8cca594041b93f0e078dd/api/types/constants.go#L1233). - -An admin may not care what kind of subresources a user requests, as long as the user is not requesting the whole Kubernetes cluster. For this case we will introduce a separate const `resource` that means a user can request to any Kubernetes subresources. - -| Request Mode Values | Explanation | -| --------------------------------------------- | :--------------------------------------------------------------: | -| [] | no restrictions | -| `options.request_mode.kubernetes` not defined | no restrictions | -| [kube_cluster, resource] | no restrictions | -| [resource] | requires users to request for any of the Kubernetes subresources | -| [kube_cluster] | requires users to request for the whole Kubernetes cluster | -| [namespace] | requires users to request for only namespaces | -| [namespace, pod] | requires users to request for only namespaces OR pods | +| kubernetes_resources list example | Explanation | +| --------------------------------------- | :--------------------------------------------------------------: | +| [] or `request_mode` not defined | no restrictions | +| [{ kind: '*' }] | requires users to request for any of the Kubernetes subresources | +| [{ kind: 'namespace' }] | requires users to request for only namespaces | +| [{ kind: 'namespace'}, { kind: 'pod' }] | requires users to request for only namespaces OR pods | -The `options.request_mode.kubernetes` values will be validated for expected value upon role create or update. +The `kind` values will be validated for expected value upon role create or update. ## Request Validation -During the request creation flow is where we will validate/enforce the `options.request_mode.kubernetes`. +During the request creation flow is where we will validate/enforce the `options.request_mode.kubernetes_resources`. -1. Determine if requested `kind` is in the `options.request_mode.kubernetes` list -1. Allow creation if request kind is in allow list, otherwise reject creation with error message: `Not allowed to request Kubernetes resource kind "". Allowed kinds: ""` +1. Determine if requested `kind` is in the `options.request_mode.kubernetes_resources` list +1. Allow creation if request kind is in allow list, otherwise reject creation with error message: `Not allowed to request Kubernetes resource kind "". Allowed kinds: ""` ## New proto fields @@ -200,7 +220,7 @@ Data structure that will hold different modes: ```proto message AccessRequestMode { - repeated string Kubernetes = 1 [(gogoproto.jsontag) = "kubernetes,omitempty"]; + repeated KubernetesResource KubernetesResources = 1 [(gogoproto.jsontag) = "kubernetes_resources,omitempty"]; } ``` @@ -238,10 +258,49 @@ These are the current states the web UI can take regarding Kubernetes resources - if list is empty, the UI will render whatever UI options we support, which is currently just allowing user to either select `kube_cluster` or `namespace` - if list contains only `kube_cluster`, the UI will not render options for selecting namespaces - if list contains only `namespace`, the UI will prevent user from clicking `submit` button until user has selected at least one namespace for the selected `kube_cluster` -- if list contains kinds not supported by the web UI, the UI will prevent user from clicking `submit` button, with a disabled message `Your role requires requesting Kubernetes resource 's, but the web UI does not support this request yet. Use "tsh request create --resource ////" instead` +- if list only contains kinds not supported by the web UI, the UI will prevent user from clicking `submit` button, with a disabled message `Your role requires requesting Kubernetes resource 's, but the web UI does not support this request yet. Use "tsh request create --resource ////" instead` ## CLI tsh already has support for requesting [all these resources](https://github.com/gravitational/teleport/blob/110b23aefb3c4b91c9d8cca594041b93f0e078dd/api/types/constants.go#L1201). There is nothing to add to the CLI, we will just let it error out upon request creation validation. + +## Future Field Support + +In future iterations we can add support for more fields in the [KubernetesResource](https://github.com/gravitational/teleport/blob/c49eb984648b506f3223804784a54ddec8d4d2d3/api/proto/teleport/legacy/types/types.proto#L3293) structure to provide admins more ways to restrict a request. + +For example given these roles: + +```yaml +kind: role +metadata: + name: kube-access +spec: + allow: + kubernetes_resources: + # Only allow lists namespaces starting with "coffee-" prefixes + - kind: namespace + name: 'coffee-*' + verbs: + - list + +----- + +kind: role +metadata: + name: requester +spec: + allow: + request: + search_as_roles: + - kube-access + options: + request_mode: + kubernetes_resources: + - kind: 'namespace' + # Adding support for this field + name: 'coffee-latte +``` + +The `kube-access` role will allow user to list and select namespaces starting with `coffee-*` and the `request_mode` will further restrict this to only allow requesting for namespace `coffee-latte`.