Skip to content

Commit

Permalink
Re-use existing data structure for request mode
Browse files Browse the repository at this point in the history
  • Loading branch information
kimlisa committed Oct 2, 2024
1 parent 4c7b83a commit 4e7ad75
Showing 1 changed file with 85 additions and 26 deletions.
111 changes: 85 additions & 26 deletions rfd/0183-access-request-kube-resource-allow-list.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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.
Expand Down Expand Up @@ -102,7 +113,7 @@ spec:
kind: role
metadata:
name: kube-access-request
name: kube-access
spec:
allow:
kubernetes_resources:
Expand All @@ -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
Expand All @@ -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.
Expand All @@ -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.
Expand All @@ -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
Expand All @@ -168,39 +195,32 @@ spec:
options:
# new field
request_mode:
kubernetes: [<list of kinds>]
kubernetes_resources: [<list of KubernetesResource objects>]
```

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 "<KIND>". Allowed kinds: "<options.request_mode.kubernetes>"`
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 "<KIND>". Allowed kinds: "<options.request_mode.kubernetes_resources>"`

## New proto fields

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"];
}
```

Expand Down Expand Up @@ -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 <kind>'s, but the web UI does not support this request yet. Use "tsh request create --resource /<teleport-cluster-name>/<subresource kind>/<kube-cluster-name>/<subresource-name>" 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 <kind>'s, but the web UI does not support this request yet. Use "tsh request create --resource /<teleport-cluster-name>/<subresource kind>/<kube-cluster-name>/<subresource-name>" 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`.

0 comments on commit 4e7ad75

Please sign in to comment.