Files
teleport/lib/services/session_recording.go
T
Tiago Silva 05419f28b6 support where RBAC on application session recordings (#69630)
* support `where` RBAC on application session recordings

application session recordings are backed by AppSessionChunk events, but
those events were never wired into the session recording RBAC path, so
`where` clauses on `kind: session` rules could not match them.

Fixes https://github.com/gravitational/teleport/issues/67775

Signed-off-by: Tiago Silva <[email protected]>

* fix unit test

* handle feedback

---------

Signed-off-by: Tiago Silva <[email protected]>
2026-08-13 14:29:20 +00:00

146 lines
4.5 KiB
Go

/*
* Teleport
* Copyright (C) 2025 Gravitational, Inc.
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package services
import (
apidefaults "github.com/gravitational/teleport/api/defaults"
headerv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/header/v1"
linuxdesktopv1 "github.com/gravitational/teleport/api/gen/proto/go/teleport/linuxdesktop/v1"
"github.com/gravitational/teleport/api/types"
apievents "github.com/gravitational/teleport/api/types/events"
)
// ExtendWithSessionEnd extends the context with a session end event and
// rebuilds the resource from the event. An AccessChecker must be provided
// to allow access checks to other resources in the where clause.
func (ctx *Context) ExtendWithSessionEnd(sessionEnd apievents.AuditEvent, checker AccessChecker) {
ctx.Session = sessionEnd
ctx.Resource = rebuildResourceFromSessionEndEvent(sessionEnd)
if linuxEnd, ok := sessionEnd.(*apievents.LinuxDesktopSessionEnd); ok {
ctx.Resource153 = linuxdesktopv1.LinuxDesktop_builder{
Kind: types.KindLinuxDesktop,
SubKind: "",
Version: types.V1,
Metadata: headerv1.Metadata_builder{
Name: linuxEnd.DesktopName,
Labels: linuxEnd.DesktopLabels,
}.Build(),
Spec: linuxdesktopv1.LinuxDesktopSpec_builder{
Addr: linuxEnd.DesktopAddr,
}.Build(),
}.Build()
}
// AccessCheker is set here to allow access checks to other resources
// in the where clause.
ctx.AccessChecker = checker
}
// rebuildResourceFromSessionEndEvent rebuilds a resource from a session end event.
// This is used to reconstruct the resource that was active at the time of the session end event
// for audit log RBAC purposes.
func rebuildResourceFromSessionEndEvent(event apievents.AuditEvent) types.Resource {
switch sEnd := event.(type) {
case *apievents.SessionEnd:
if sEnd == nil {
return nil
}
switch sEnd.Protocol {
case apievents.EventProtocolSSH:
return &types.ServerV2{
Kind: types.KindNode,
Version: types.V2,
Metadata: types.Metadata{
Name: sEnd.ServerMetadata.ServerID,
Namespace: sEnd.ServerMetadata.ServerNamespace,
Labels: sEnd.ServerMetadata.ServerLabels,
},
Spec: types.ServerSpecV2{
Addr: sEnd.ServerMetadata.ServerAddr,
Hostname: sEnd.ServerMetadata.ServerHostname,
},
}
case apievents.EventProtocolKube:
return &types.KubernetesClusterV3{
Kind: types.KindKubernetesCluster,
Version: types.V3,
Metadata: types.Metadata{
Name: sEnd.KubernetesClusterMetadata.KubernetesCluster,
Namespace: apidefaults.Namespace,
Labels: sEnd.KubernetesClusterMetadata.KubernetesLabels,
},
Spec: types.KubernetesClusterSpecV3{},
}
}
case *apievents.WindowsDesktopSessionEnd:
if sEnd == nil {
return nil
}
return &types.WindowsDesktopV3{
ResourceHeader: types.ResourceHeader{
Kind: types.KindWindowsDesktop,
Version: types.V3,
Metadata: types.Metadata{
Name: sEnd.DesktopName,
Namespace: apidefaults.Namespace,
Labels: sEnd.DesktopLabels,
},
},
Spec: types.WindowsDesktopSpecV3{
Addr: sEnd.DesktopAddr,
Domain: sEnd.Domain,
},
}
case *apievents.AppSessionChunk:
if sEnd == nil {
return nil
}
return &types.AppV3{
Kind: types.KindApp,
Version: types.V3,
Metadata: types.Metadata{
Name: sEnd.AppName,
Namespace: apidefaults.Namespace,
Labels: sEnd.AppLabels,
},
Spec: types.AppSpecV3{
URI: sEnd.AppURI,
PublicAddr: sEnd.AppPublicAddr,
},
}
case *apievents.DatabaseSessionEnd:
if sEnd == nil {
return nil
}
return &types.DatabaseV3{
Kind: types.KindDatabase,
Version: types.V3,
Metadata: types.Metadata{
Name: sEnd.DatabaseService,
Namespace: apidefaults.Namespace,
Labels: sEnd.DatabaseLabels,
},
Spec: types.DatabaseSpecV3{
Protocol: sEnd.DatabaseProtocol,
URI: sEnd.DatabaseURI,
},
}
}
return nil
}