Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix active session filtering for legacy sessions #47448

Merged
merged 1 commit into from
Oct 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion api/types/constants.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,10 @@ const (
// KindSession is a recorded SSH session.
KindSession = "session"

// KindSSHSession is an active SSH session.
// KindSSHSession represents an active SSH session in early versions of Teleport
// prior to the introduction of moderated sessions. Note that ssh_session is not
// a "real" resource, and it is never used as the "session kind" value in the
// session_tracker resource.
KindSSHSession = "ssh_session"

// KindWebSession is a web session resource
Expand Down
5 changes: 5 additions & 0 deletions api/types/session_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ import (
// SessionKind is a type of session.
type SessionKind string

// These represent the possible values for the kind field in session trackers.
const (
// SSHSessionKind is the kind used for session tracking with the
// session_tracker resource used in Teleport 9+. Note that it is
// different from the legacy [types.KindSSHSession] value that was
// used prior to the introduction of moderated sessions.
SSHSessionKind SessionKind = "ssh"
KubernetesSessionKind SessionKind = "k8s"
DatabaseSessionKind SessionKind = "db"
Expand Down
10 changes: 5 additions & 5 deletions lib/auth/auth_with_roles.go
Original file line number Diff line number Diff line change
Expand Up @@ -279,12 +279,12 @@ func (a *ServerWithRoles) CreateSessionTracker(ctx context.Context, tracker type
return tracker, nil
}

func (a *ServerWithRoles) filterSessionTracker(ctx context.Context, joinerRoles []types.Role, tracker types.SessionTracker, verb string) bool {
func (a *ServerWithRoles) filterSessionTracker(joinerRoles []types.Role, tracker types.SessionTracker, verb string) bool {
// Apply RFD 45 RBAC rules to the session if it's SSH.
// This is a bit of a hack. It converts to the old legacy format
// which we don't have all data for, luckily the fields we don't have aren't made available
// to the RBAC filter anyway.
if tracker.GetKind() == types.KindSSHSession {
if tracker.GetSessionKind() == types.SSHSessionKind {
ruleCtx := &services.Context{User: a.context.User}
ruleCtx.SSHSession = &session.Session{
Kind: tracker.GetSessionKind(),
Expand Down Expand Up @@ -435,7 +435,7 @@ func (a *ServerWithRoles) GetSessionTracker(ctx context.Context, sessionID strin
return nil, trace.Wrap(err)
}

ok := a.filterSessionTracker(ctx, joinerRoles, tracker, types.VerbRead)
ok := a.filterSessionTracker(joinerRoles, tracker, types.VerbRead)
if !ok {
return nil, trace.NotFound("session %v not found", sessionID)
}
Expand All @@ -462,7 +462,7 @@ func (a *ServerWithRoles) GetActiveSessionTrackers(ctx context.Context) ([]types
}

for _, sess := range sessions {
ok := a.filterSessionTracker(ctx, joinerRoles, sess, types.VerbList)
ok := a.filterSessionTracker(joinerRoles, sess, types.VerbList)
if ok {
filteredSessions = append(filteredSessions, sess)
}
Expand Down Expand Up @@ -490,7 +490,7 @@ func (a *ServerWithRoles) GetActiveSessionTrackersWithFilter(ctx context.Context
}

for _, sess := range sessions {
ok := a.filterSessionTracker(ctx, joinerRoles, sess, types.VerbList)
ok := a.filterSessionTracker(joinerRoles, sess, types.VerbList)
if ok {
filteredSessions = append(filteredSessions, sess)
}
Expand Down
36 changes: 35 additions & 1 deletion lib/auth/auth_with_roles_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -6291,7 +6291,41 @@ func TestGetActiveSessionTrackers(t *testing.T) {
require.NoError(t, err)

return getActiveSessionsTestCase{"no access with match expression", tracker, role, false}
}()}
}(), func() getActiveSessionsTestCase {
tracker, err := types.NewSessionTracker(types.SessionTrackerSpecV1{
SessionID: "1",
Kind: string(types.SSHSessionKind),
})
require.NoError(t, err)

role, err := types.NewRoleWithVersion("dev", types.V3, types.RoleSpecV6{
Allow: types.RoleConditions{
AppLabels: types.Labels{"*": []string{"*"}},
DatabaseLabels: types.Labels{"*": []string{"*"}},
KubernetesLabels: types.Labels{"*": []string{"*"}},
KubernetesResources: []types.KubernetesResource{
{Kind: types.KindKubePod, Name: "*", Namespace: "*", Verbs: []string{"*"}},
},
NodeLabels: types.Labels{"*": []string{"*"}},
NodeLabelsExpression: `contains(user.spec.traits["cluster_ids"], labels["cluster_id"]) || contains(user.spec.traits["sub"], labels["owner"])`,
Logins: []string{"{{external.sub}}"},
WindowsDesktopLabels: types.Labels{"cluster_id": []string{"{{external.cluster_ids}}"}},
WindowsDesktopLogins: []string{"{{external.sub}}", "{{external.windows_logins}}"},
},
Deny: types.RoleConditions{
Rules: []types.Rule{
{
Resources: []string{types.KindDatabaseServer, types.KindAppServer, types.KindSession, types.KindSSHSession, types.KindKubeService, types.KindSessionTracker},
Verbs: []string{"list", "read"},
},
},
},
})
require.NoError(t, err)

return getActiveSessionsTestCase{"filter bug v3 role", tracker, role, false}
}(),
}

for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
Expand Down
Loading