mirror of
https://github.com/gravitational/teleport.git
synced 2026-09-21 14:35:22 +08:00
Teleport RBAC policies give built-in role certificates (proxy,
discovery, okta, node, kube...) access to the session recordings
API and audit log.
For the session recordings API, the policy enforcement completely
skips the RBAC logic and if the certificate was from a built-in role,
the client verification logic would skip RBAC entirely.
```go
func (a *ServerWithRoles) StreamSessionEvents(ctx context.Context, sessionID session.ID, startIndex int64) (chan apievents.AuditEvent, chan error) {
err := a.localServerAction()
isTeleportServer := err == nil
// StreamSessionEvents can be called internally, and when that
// happens we don't want to emit an event or check for permissions.
if isTeleportServer {
return a.alog.StreamSessionEvents(ctx, sessionID, startIndex)
}
```
From the built-in roles, only node had read access to
`types.KindSession`, but given the check above all of them had access,
including cases like `okta` where no session recording exists.
This means a user with access to a token or an agent certificate can
read, play and view every single session recording.
Historically, this bypass existed for one particular reason: when an
upload is abandoned without proper termination - this happens when the
agent is restarted while interactive sessions are alive, the agent
places the session in a temporary folder. This folder is constantly
monitored by a routine called `UploadCompleter`. This routine runs on
every teleport process and is responsible for deciding when a session
was abandoned - no active session tracker and the last written data was
24h ago and mark it completed, i.e. move it to another directory, so that
the file uploader could move it to auth server for long-term storage.
Since the session was not correctly terminated it could be the case it
misses the `session.end` or respective end event. This is not
particularly important for the recording itself since it's playable as is,
but it's critical for the session recordings list.
When a user goes to Session Recordings page or does `tctl recordings ls`,
Teleport issues a read request from the audit log to search for
`session.end`, `windows.desktop.session.end`, `db.session.end` and
`app.session.end`. If the audit log doesn't contain the events but the
agent successfully uploaded the recording, the recording won't be
included in the list and will be inaccessible from `tctl` or `tsh`.
To overcome this problem,
https://github.com/gravitational/teleport/pull/14521 introduced logic to
reconstruct the session end event from the recording itself. The logic
assumes (partially incorrect) that if the session recording holds the
session end event, the same event was already present in the audit log.
After the `UploadCompleter` successfully marked the upload as completed,
it scheduled a goroutine to stream the session and see if the session end
event exists. The goroutine had to run 2m after because it was considered
a good time for the file uploader to send the session to the auth server
and auth made it available in the long term storage. To stream it, the
agent contacted Auth Server through the same API users use to play sessions.
Because of an improper filtering and logic, any agent had access to any session.
Even without knowing the session id, given that the agent also had access to read
the audit log, it was able to search for the session end events and later access
them using the `StreamSessionEvents` API.
The main reason why it was implemented like this was because from the moment the
`UploadCompleter` marked the session as completed, auth server had no way to distinguish
between a complete session vs an incomplete session. So the logic was placed into the last
piece that still retained that information.
This PR fixes both problems. It removes RW access to audit logs,
lowering it to WO - agents can write it but can't read it, and removed
any access to StreamSessionEvents.
In order to remove the `StreamSessionEvents` logic being accessible by
the agents, this PR moves the same logic to auth server. There are 3
places where this logic must exist:
- Auth upload completer: If the cluster is operating with any sync mode
instead of async, Auth is the receiving point the the streams. If
something fails, the recording will live in auth server and not the
agent.
- Upload API in Auth: When clusters operate in async mode, agents'
fileuploader uses the auth grpc API to upload the events. Since auth
receives event by event, we can easily analyse if the session already
has a session end event and fill it if necessary
- Encrypted recordings upload: If the cluster operates with encrypted
recordings enabled, agents upload the data to the encrypted recordings
gRPC service. Before this fix, if the session was incomplete we didn't
even try to build the session end event and the session was hidden.
This PR exposes the completer logic in auth server and each one of the 3
cases mentioned call that auth's server function for consistency and
predictability.
Fixes https://github.com/gravitational/teleport-private/issues/2363
This PR fixes https://github.com/gravitational/teleport/issues/60861
accidentally.