teleport/rfd/0044-session-where-condition.md
Andrej Tokarčík 0e47b8826d
RFD 44: RBAC where conditions for session recordings list/read (#8084)
`where` conditions for session recordings.

* RFD XY: Users accessing their own SSH sessions

* Update 00XY-access-self-recordings.md

* Update and rename 00XY-access-self-recordings.md to 00XY-access-own-sessions.md

* Add more notes on individual storage backends

* Update 00XY-access-own-sessions.md

* Propose to adapt SearchSessionEvents instead of adding new SearchCompletedSessions

* Update 00XY-access-own-sessions.md

* Migrate DynamoDB events to store their fields as a map

* Update 00XY-access-own-sessions.md

* Update and rename 00XY-access-own-sessions.md to 00XY-session-where-condition.md

* Update 00XY-session-where-condition.md

* Pick a number for the RFD, update status

Co-authored-by: Alan Parra <alan.parra@goteleport.com>
2021-11-10 09:00:12 -08:00

4.5 KiB

authors state
Andrej Tokarčík (andrej@goteleport.com) implemented

RFD 44 - RBAC where conditions for session recordings list/read

What

The where condition in RBAC rules for session recordings should be allowed to refer to the session recording as in:

spec:
  allow:
    rules:
    - resources: [session]
      verbs: [list, read]
      where: contains(session.participants, user.metadata.name)

For list requests, the condition should become part of the query sent to the backend.

Why

To be able to provide users with the capability to view recordings of the sessions they have participated in, without having to be granted the privilege to view all session recordings.

Details

Subconditions involving session

A new identifier session for use in where clauses is introduced.

For read requests, any occurrence of the identifier refers to the session.end event associated with the requested session ID -- the whole where condition is then evaluated with this binding. If the condition is satisfied, the read request continues with a query to the backend.

For list requests, the where condition cannot be evaluated as is since there is no particular event to bind to the session identifier. Instead, the largest admissible subcondition involving session shall be extracted and passed to the backend as an additional filtering condition. For example, consider the where condition:

(contains(session.participants, user.metadata.name) && !equals(user.metadata.name, "blocked"))
  || equals(user.metadata.name, "admin")
  • If user.metadata.name is equal to "admin", the largest admissible subcondition would be true -- the list query would be performed on the backend with no additional filtering conditions.
  • If user.metadata.name is equal to "blocked", the largest admissible subcondition would be false -- the whole request would be rejected with AccessDenied.
  • Otherwise, the largest admissible subcondition would be contains(session.participants, user.metadata.name) -- the list query would be performed on the backend with this additional filtering condition applied.

API

As it stands, the list of session recordings is obtained by searching (SearchEvents) for session.end events. This already makes it difficult to follow the principle of least privilege since the call requires the ability to list all events, not only the session-related ones.

The method SearchSessionEvents appears to have been meant to address this privilege creep: it checks privileges for KindSession instead of KindEvent. The Proxy Web UI shall be updated to call SearchSessionEvents instead of SearchEvents when building lists of session recordings.

Moreover, SearchSessionEvents shall be modified to search only for session.end events (instead of both session.start and session.end) and to accept an additional parameter for the where subcondition described above.

Backends

DynamoDB

Currently, the fields of an event are stored as a JSON string in the Fields attribute. To allow for efficient filtering, the fields should be stored as a proper DynamoDB map instead since DynamoDB allows to refer to map elements inside the filter/condition expressions (e.g. contains(FieldsMap.participants, :participant)). This will also enable efficient event-specific queries for any other use case in the future.

The whole event table shall therefore be migrated so that the current Fields (DynamoDB string) is converted into a new FieldsMap attribute (DynamoDB map).

The received session-related subcondition shall be converted into a DynamoDB filter expression.

Firestore

The Firestore event table should be migrated to store event fields as a native map type. The schema should be extended with any necessary indexes to allow for backend-side filtering by both the event type and the fields map attributes.

The received session-related subcondition shall be converted into a Firestore query object.

File log

The event file is processed and the individual entries unmarshaled at the Auth server.

The received session-related subcondition shall be converted into a boolean function applicable to the unmarshaled event fields.