Skip to content

Commit

Permalink
Add initial command to session trackers (#32947) (#33113)
Browse files Browse the repository at this point in the history
When user starts a session, we do not report the initial command used
which causes visibility problems to moderators when they need to figure
out if they join or not the session.

This PR exposes the intial command for SSH and Kubernetes so moderators
can decide if they want to join the session or not based on the initial
command.

Signed-off-by: Tiago Silva <tiago.silva@goteleport.com>
  • Loading branch information
tigrato committed Oct 9, 2023
1 parent 3ac9f08 commit afbe4c5
Show file tree
Hide file tree
Showing 14 changed files with 1,649 additions and 1,470 deletions.
3 changes: 3 additions & 0 deletions api/proto/teleport/legacy/types/types.proto
Original file line number Diff line number Diff line change
Expand Up @@ -5011,6 +5011,9 @@ message SessionTrackerSpecV1 {

// TargetSubKind is the sub kind of the target server.
string TargetSubKind = 22 [(gogoproto.jsontag) = "target_sub_kind,omitempty"];

// InitialCommand is the command that was executed to start this session.
repeated string InitialCommand = 23 [(gogoproto.jsontag) = "initial_command,omitempty"];
}

// SessionTrackerPolicySet is a set of RBAC policies held by the session tracker
Expand Down
8 changes: 8 additions & 0 deletions api/types/session_tracker.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,9 @@ type SessionTracker interface {

// GetTargetSubKind returns the sub kind of the target server.
GetTargetSubKind() string

// GetCommand returns the command that initiated the session.
GetCommand() []string
}

func NewSessionTracker(spec SessionTrackerSpecV1) (SessionTracker, error) {
Expand Down Expand Up @@ -336,6 +339,11 @@ func (s *SessionTrackerV1) GetTargetSubKind() string {
return s.Spec.TargetSubKind
}

// GetCommand returns command that intiated the session.
func (s *SessionTrackerV1) GetCommand() []string {
return s.Spec.InitialCommand
}

// Match checks if a given session tracker matches this filter.
func (f *SessionTrackerFilter) Match(s SessionTracker) bool {
if f.Kind != "" && string(s.GetSessionKind()) != f.Kind {
Expand Down
2,960 changes: 1,506 additions & 1,454 deletions api/types/types.pb.go

Large diffs are not rendered by default.

1 change: 1 addition & 0 deletions lib/kube/proxy/sess.go
Original file line number Diff line number Diff line change
Expand Up @@ -1195,6 +1195,7 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy
Created: time.Now(),
Reason: s.reason,
Invited: s.invitedUsers,
InitialCommand: s.req.URL.Query()["command"],
}

s.log.Debug("Creating session tracker")
Expand Down
2 changes: 2 additions & 0 deletions lib/session/session.go
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,8 @@ type Session struct {
Owner string `json:"owner"`
// Moderated is true if the session requires moderation (only relevant for Kind = ssh/k8s).
Moderated bool `json:"moderated"`
// Command is the command that was executed to start the session.
Command string `json:"command"`
}

// FileTransferRequestParams contain parameters for requesting a file transfer
Expand Down
29 changes: 17 additions & 12 deletions lib/srv/sess.go
Original file line number Diff line number Diff line change
Expand Up @@ -2055,19 +2055,24 @@ func (p *party) closeUnderSessionLock() {
// While ctx is open, the session tracker's expiration will be extended
// on an interval until the session tracker is closed.
func (s *session) trackSession(ctx context.Context, teleportUser string, policySet []*types.SessionTrackerPolicySet) error {
var initialCommand []string
if execRequest, err := s.scx.GetExecRequest(); err == nil {
initialCommand = []string{execRequest.GetCommand()}
}
trackerSpec := types.SessionTrackerSpecV1{
SessionID: s.id.String(),
Kind: string(types.SSHSessionKind),
State: types.SessionState_SessionStatePending,
Hostname: s.serverMeta.ServerHostname,
Address: s.serverMeta.ServerID,
ClusterName: s.scx.ClusterName,
Login: s.login,
HostUser: teleportUser,
Reason: s.scx.env[teleport.EnvSSHSessionReason],
HostPolicies: policySet,
Created: s.registry.clock.Now().UTC(),
TargetSubKind: s.serverMeta.ServerSubKind,
SessionID: s.id.String(),
Kind: string(types.SSHSessionKind),
State: types.SessionState_SessionStatePending,
Hostname: s.serverMeta.ServerHostname,
Address: s.serverMeta.ServerID,
ClusterName: s.scx.ClusterName,
Login: s.login,
HostUser: teleportUser,
Reason: s.scx.env[teleport.EnvSSHSessionReason],
HostPolicies: policySet,
Created: s.registry.clock.Now().UTC(),
TargetSubKind: s.serverMeta.ServerSubKind,
InitialCommand: initialCommand,
}

if s.scx.env[teleport.EnvSSHSessionInvited] != "" {
Expand Down
3 changes: 1 addition & 2 deletions lib/web/apiserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,6 @@ func NewHandler(cfg Config, opts ...HandlerOption) (*APIHandler, error) {
if err != nil {
h.log.WithError(err).Warnf("Invalid SSH proxy address %q, will use default port %v.",
cfg.ProxySSHAddr.String(), defaults.SSHProxyListenPort)

} else {
sshPortValue = sshPort
}
Expand Down Expand Up @@ -3011,6 +3010,7 @@ func trackerToLegacySession(tracker types.SessionTracker, clusterName string) se
Moderated: accessEvaluator.IsModerated(),
DatabaseName: tracker.GetDatabaseName(),
Owner: tracker.GetHostUser(),
Command: strings.Join(tracker.GetCommand(), " "),
}
}

Expand Down Expand Up @@ -3695,7 +3695,6 @@ func consumeTokenForAPICall(ctx context.Context, proxyClient auth.ClientI, token
}

return token, nil

}

// checkTokenTTL returns true if the token is still valid.
Expand Down
13 changes: 11 additions & 2 deletions tool/tsh/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -571,9 +571,18 @@ func serializeKubeSessions(sessions []types.SessionTracker, format string) (stri
}

func printSessions(output io.Writer, sessions []types.SessionTracker) {
table := asciitable.MakeTable([]string{"ID", "State", "Created", "Hostname", "Address", "Login", "Reason"})
table := asciitable.MakeTable([]string{"ID", "State", "Created", "Hostname", "Address", "Login", "Reason", "Command"})
for _, s := range sessions {
table.AddRow([]string{s.GetSessionID(), s.GetState().String(), s.GetCreated().Format(time.RFC3339), s.GetHostname(), s.GetAddress(), s.GetLogin(), s.GetReason()})
table.AddRow([]string{
s.GetSessionID(),
s.GetState().String(),
s.GetCreated().Format(time.RFC3339),
s.GetHostname(),
s.GetAddress(),
s.GetLogin(),
s.GetReason(),
strings.Join(s.GetCommand(), " "),
})
}

tableOutput := table.AsBuffer().String()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,6 @@ const session: Session = {
addr: '1.1.1.1:1111',
participantModes: ['observer', 'moderator', 'peer'],
moderated: false,
command:
'top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid',
};
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,10 @@ export default function SessionList(props: Props) {
headerText: 'Users',
render: renderUsersCell,
},
{
key: 'command',
headerText: 'Command',
},
{
key: 'durationText',
altSortKey: 'created',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -631,6 +631,11 @@ exports[`active sessions CTA 1`] = `
>
Users
</th>
<th
style="cursor: default;"
>
Command
</th>
<th>
<a>
Duration
Expand Down Expand Up @@ -662,6 +667,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
kubectl get pods
</td>
<td>
59 minutes
</td>
Expand All @@ -686,6 +694,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
ls -la
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -727,6 +738,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa3
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -768,6 +782,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -809,6 +826,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand All @@ -833,6 +853,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
3 minutes
</td>
Expand All @@ -857,6 +880,9 @@ exports[`active sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
13 minutes
</td>
Expand Down Expand Up @@ -1415,6 +1441,11 @@ exports[`loaded 1`] = `
>
Users
</th>
<th
style="cursor: default;"
>
Command
</th>
<th>
<a>
Duration
Expand Down Expand Up @@ -1446,6 +1477,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
kubectl get pods
</td>
<td>
59 minutes
</td>
Expand All @@ -1470,6 +1504,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
ls -la
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -1511,6 +1548,9 @@ exports[`loaded 1`] = `
<td>
lisa3
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -1552,6 +1592,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -1593,6 +1636,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand All @@ -1617,6 +1663,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
3 minutes
</td>
Expand All @@ -1641,6 +1690,9 @@ exports[`loaded 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
13 minutes
</td>
Expand Down Expand Up @@ -2199,6 +2251,11 @@ exports[`moderated sessions CTA 1`] = `
>
Users
</th>
<th
style="cursor: default;"
>
Command
</th>
<th>
<a>
Duration
Expand Down Expand Up @@ -2230,6 +2287,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
kubectl get pods
</td>
<td>
59 minutes
</td>
Expand All @@ -2254,6 +2314,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
ls -la
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -2295,6 +2358,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa3
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -2336,6 +2402,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand Down Expand Up @@ -2377,6 +2446,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
5 seconds
</td>
Expand All @@ -2401,6 +2473,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
3 minutes
</td>
Expand All @@ -2425,6 +2500,9 @@ exports[`moderated sessions CTA 1`] = `
<td>
lisa2
</td>
<td>
top -o command -o cpu -o boosts -o cycles -o cow -o user -o vsize -o csw -o threads -o ports -o ppid
</td>
<td>
13 minutes
</td>
Expand Down

0 comments on commit afbe4c5

Please sign in to comment.