rfd/0186-optionally-require-reason-for-access-request.md
Add the ability to set a policy to make a reason required for an access request to be submitted (#20164).
Improves user experience for environments with audit/compliance policies that require a reason. Adding the ability to mark a reason as required would allow both tsh and the web UI to prompt for a reason without the end user needing to remember that it's required and as a result reduce the number of invalid access requests that need to be rejected.
Let's assume scenario where there are two roles kube-access and node-access
user bob can request:
kind: role
version: v7
metadata:
name: kube-access
spec:
allow:
kubernetes_resources:
- kind: '*'
namespace: '*'
name: '*'
verbs: ['*']
kind: role
version: v7
metadata:
name: node-access
spec:
allow:
logins: ['admin']
node_labels:
'*': '*'
The administrator may want to configure a user bob to be able to:
kube-access, but only if a non-empty reason is providednode-access with or without providing a reasonWhen user bob requests access to kube-access role without providing a
reason they receive an error:
$ tsh request create --roles kube-access
Creating request...
ERROR: request reason must be specified (required by static role configuration)
When user bob provides a reason the action is successful:
$ tsh request create --roles kube-access --reason "Ticket 1234"
Creating request...
Request ID: 0192f6c0-cd34-79bc-9e51-14b983265106
Username: bob
Roles: kube-access
Reason: "Ticket 1234"
Reviewers: [none] (suggested)
Access Expires: 2024-11-04 22:28:22
Status: PENDING
hint: use 'tsh login --request-id=<request-id>' to login with an approved request
Waiting for request approval...
When user bob requests access to node-access without providing a reason the
action succeeds:
$ e/build/tsh request create --roles node-access
Creating request...
Request ID: 0192f6c7-ba5e-76b6-8af0-372d6a9d2406
Username: bob
Roles: node-access
Reason: [none]
Reviewers: [none] (suggested)
Access Expires: 2024-11-04 22:28:22
Status: PENDING
hint: use 'tsh login --request-id=<request-id>' to login with an approved request
Waiting for request approval...
Introduce a new role.spec.allow.reason.mode setting which could be set to "required" or "optional" (default).
Example:
kind: role
version: v7
metadata:
name: kube-access-requester
spec:
allow:
request:
roles:
- kube-access
reason:
mode: "required"
The problems with the approach:
options.request_access: "always" and a role with allow.request.mode: "required". Should the reason be requested regardless during login? (yes)options.request_access: reason - how to satisfy all
of them?Currently a role can have request_access option set to one of the following
values: optional, always and reason as described in
https://goteleport.com/docs/admin-guides/access-controls/access-requests/access-request-configuration/#how-clients-request-access.
The idea is to support another value reason-required.
[!CAUTION] role.options.request_access is a global configuration, therefore it doesn't meet the requirement of requiring reason only for some resources/roles.
It has to be noted that role.options.request_access has a global scope. I.e. if it's set on any role all access requests to all roles and resources are affected.
Example:
For two roles kube-access-requester and node-access-requester as defined
below:
kind: role
version: v7
metadata:
name: kube-access-requester
spec:
allow:
request:
roles:
- kube-access
options:
request_access: reason-required
kind: role
version: v7
metadata:
name: node-access-requester
spec:
allow:
request:
roles:
- node-access
A user with both roles kube-access-requester and node-access-requester
assigned will be affected by request_access set in role kube-access-requester
while requesting access to role node-access allowed by
node-access-requester role.
Because request_access option is global a priority has to be establish when more than one role has the option specified:
Problems:
[!NOTE] This is a breaking change.
The solution would be like in 1. but with changed semantics of request_access option. It would become role-scoped instead of global.
Example:
For two roles kube-access-requester and node-access-requester as defined
below:
kind: role
version: v7
metadata:
name: kube-access-requester
spec:
allow:
request:
roles:
- kube-access
options:
request_access: reason-required
kind: role
version: v7
metadata:
name: node-access-requester
spec:
allow:
request:
roles:
- node-access
options:
request_access: optional # default, doesn't need to be set explicitly
A user with kube-access-requester and node-access-requester roles assigned
would have to provide a reason while creating an access request for
kube-access role but wouldn't have to provide reason while requesting access
to node-access role.
The example above is clear and simple, but there are problems with the implementation:
This would be similar to review_request.deny.where. See
https://goteleport.com/docs/admin-guides/access-controls/access-requests/access-request-configuration/#allowing-and-denying-reviews-for-specific-roles
Example:
kind: role
version: v7
metadata:
name: request-kube-access-with-reason
spec:
allow:
request:
roles:
- kube-access
where: 'request.reason != ""'
The problems with the approach:
role.options.request_access option is evaluated
only during login, so the user has to re-login to have a correct UX if there
are changes to their assigned roles.The chosen implementation is:
1. Add a new role.spec.allow.request.reason.mode setting
It seems to be least confusing, declarative and straight-forward.
One thing to note is that when a user:
role.spec.options.request_access: alwaysrole.spec.allow.request.reason.required: trueIt will be effectively equivalent of setting role.spec.options.request_access: reason in any of the roles.
The IGS section of the test plan needs to be extended with these items: