Skip to content

Commit

Permalink
Add initial command to session trackers (#32947)
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 7, 2023
1 parent 0834f13 commit c210c39
Show file tree
Hide file tree
Showing 15 changed files with 1,650 additions and 1,468 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 @@ -4977,6 +4977,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 @@ -125,6 +125,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 @@ -344,6 +347,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,970 changes: 1,511 additions & 1,459 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 @@ -1206,6 +1206,7 @@ func (s *session) trackSession(p *party, policySet []*types.SessionTrackerPolicy
Reason: s.reason,
Invited: s.invitedUsers,
HostID: s.forwarder.cfg.HostID,
InitialCommand: s.req.URL.Query()["command"],
}

s.log.Debug("Creating session tracker")
Expand Down
9 changes: 6 additions & 3 deletions lib/kube/proxy/sess_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"context"
"fmt"
"net/http"
"net/url"
"testing"

"github.com/google/uuid"
Expand Down Expand Up @@ -110,9 +111,11 @@ func Test_session_trackSession(t *testing.T) {
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
sess := &session{
log: logrus.New().WithField(trace.Component, "test"),
id: uuid.New(),
req: &http.Request{},
log: logrus.New().WithField(trace.Component, "test"),
id: uuid.New(),
req: &http.Request{
URL: &url.URL{},
},
podName: "podName",
accessEvaluator: auth.NewSessionAccessEvaluator(tt.args.policies, types.KubernetesSessionKind, "username"),
ctx: authContext{
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
9 changes: 7 additions & 2 deletions lib/srv/sess.go
Original file line number Diff line number Diff line change
Expand Up @@ -2037,6 +2037,10 @@ func (p *party) closeUnderSessionLock() error {
// on an interval until the session tracker is closed.
func (s *session) trackSession(ctx context.Context, teleportUser string, policySet []*types.SessionTrackerPolicySet, p *party) error {
s.log.Debugf("Tracking participant: %s", p.id)
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),
Expand All @@ -2057,8 +2061,9 @@ func (s *session) trackSession(ctx context.Context, teleportUser string, policyS
LastActive: s.registry.clock.Now().UTC(),
},
},
HostID: s.registry.Srv.ID(),
TargetSubKind: s.serverMeta.ServerSubKind,
HostID: s.registry.Srv.ID(),
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 @@ -2496,7 +2496,6 @@ func (h *Handler) getSiteNamespaces(w http.ResponseWriter, r *http.Request, _ ht
}

func makeUnifiedResourceRequest(r *http.Request) (*proto.ListUnifiedResourcesRequest, error) {

values := r.URL.Query()

limit, err := queryLimitAsInt32(values, "limit", defaults.MaxIterationLimit)
Expand Down Expand Up @@ -3156,6 +3155,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 @@ -3836,7 +3836,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/common/kube.go
Original file line number Diff line number Diff line change
Expand Up @@ -575,9 +575,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

0 comments on commit c210c39

Please sign in to comment.