ssh/tailssh,tailcfg: add connID to ssheventnotifyrequest and castheader
This change adds a ConnectionID field to both SSHEventNotifyRequest and CastHeader that identifies the ID of a connection to the SSH server. Updates tailscale/corp#9967 Signed-off-by: Charlotte Brandhorst-Satzkorn <charlotte@tailscale.com>
This commit is contained in:
parent
68307c1411
commit
29ded8f9f9
|
@ -1410,6 +1410,11 @@ type CastHeader struct {
|
||||||
|
|
||||||
// LocalUser is the effective username on the server.
|
// LocalUser is the effective username on the server.
|
||||||
LocalUser string `json:"localUser"`
|
LocalUser string `json:"localUser"`
|
||||||
|
|
||||||
|
// ConnectionID uniquely identifies a connection made to the SSH server.
|
||||||
|
// It may be shared across multiple sessions over the same connection in
|
||||||
|
// case of SSH multiplexing.
|
||||||
|
ConnectionID string `json:"connectionID"`
|
||||||
}
|
}
|
||||||
|
|
||||||
// sessionRecordingClient returns an http.Client that uses srv.lb.Dialer() to
|
// sessionRecordingClient returns an http.Client that uses srv.lb.Dialer() to
|
||||||
|
@ -1458,7 +1463,6 @@ func (ss *sshSession) connectToRecorder(ctx context.Context, recs []netip.AddrPo
|
||||||
if len(recs) == 0 {
|
if len(recs) == 0 {
|
||||||
return nil, nil, nil, errors.New("no recorders configured")
|
return nil, nil, nil, errors.New("no recorders configured")
|
||||||
}
|
}
|
||||||
var attempts []*tailcfg.SSHRecordingAttempt
|
|
||||||
// We use a special context for dialing the recorder, so that we can
|
// We use a special context for dialing the recorder, so that we can
|
||||||
// limit the time we spend dialing to 30 seconds and still have an
|
// limit the time we spend dialing to 30 seconds and still have an
|
||||||
// unbounded context for the upload.
|
// unbounded context for the upload.
|
||||||
|
@ -1466,12 +1470,11 @@ func (ss *sshSession) connectToRecorder(ctx context.Context, recs []netip.AddrPo
|
||||||
defer dialCancel()
|
defer dialCancel()
|
||||||
hc, err := ss.sessionRecordingClient(dialCtx)
|
hc, err := ss.sessionRecordingClient(dialCtx)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
attempts = append(attempts, &tailcfg.SSHRecordingAttempt{
|
return nil, nil, nil, err
|
||||||
FailureMessage: err.Error(),
|
|
||||||
})
|
|
||||||
return nil, attempts, nil, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var errs []error
|
var errs []error
|
||||||
|
var attempts []*tailcfg.SSHRecordingAttempt
|
||||||
for _, ap := range recs {
|
for _, ap := range recs {
|
||||||
attempt := &tailcfg.SSHRecordingAttempt{
|
attempt := &tailcfg.SSHRecordingAttempt{
|
||||||
Recorder: ap,
|
Recorder: ap,
|
||||||
|
@ -1557,11 +1560,9 @@ func (ss *sshSession) openFileForRecording(now time.Time) (_ io.WriteCloser, err
|
||||||
func (ss *sshSession) startNewRecording() (_ *recording, err error) {
|
func (ss *sshSession) startNewRecording() (_ *recording, err error) {
|
||||||
// We store the node key as soon as possible when creating
|
// We store the node key as soon as possible when creating
|
||||||
// a new recording incase of FUS.
|
// a new recording incase of FUS.
|
||||||
var nodeKey key.NodePublic
|
nodeKey := ss.conn.srv.lb.NodeKey()
|
||||||
if nk := ss.conn.srv.lb.NodeKey(); nk.IsZero() {
|
if nodeKey.IsZero() {
|
||||||
return nil, errors.New("ssh server is unavailable: no node key")
|
return nil, errors.New("ssh server is unavailable: no node key")
|
||||||
} else {
|
|
||||||
nodeKey = nk
|
|
||||||
}
|
}
|
||||||
|
|
||||||
recorders, onFailure := ss.recorders()
|
recorders, onFailure := ss.recorders()
|
||||||
|
@ -1664,6 +1665,7 @@ func (ss *sshSession) startNewRecording() (_ *recording, err error) {
|
||||||
LocalUser: ss.conn.localUser.Username,
|
LocalUser: ss.conn.localUser.Username,
|
||||||
SrcNode: strings.TrimSuffix(ss.conn.info.node.Name, "."),
|
SrcNode: strings.TrimSuffix(ss.conn.info.node.Name, "."),
|
||||||
SrcNodeID: ss.conn.info.node.StableID,
|
SrcNodeID: ss.conn.info.node.StableID,
|
||||||
|
ConnectionID: ss.conn.connID,
|
||||||
}
|
}
|
||||||
if !ss.conn.info.node.IsTagged() {
|
if !ss.conn.info.node.IsTagged() {
|
||||||
ch.SrcNodeUser = ss.conn.info.uprof.LoginName
|
ch.SrcNodeUser = ss.conn.info.uprof.LoginName
|
||||||
|
@ -1694,6 +1696,7 @@ func (ss *sshSession) startNewRecording() (_ *recording, err error) {
|
||||||
func (ss *sshSession) notifyControl(ctx context.Context, nodeKey key.NodePublic, notifyType tailcfg.SSHEventType, attempts []*tailcfg.SSHRecordingAttempt, url string) {
|
func (ss *sshSession) notifyControl(ctx context.Context, nodeKey key.NodePublic, notifyType tailcfg.SSHEventType, attempts []*tailcfg.SSHRecordingAttempt, url string) {
|
||||||
re := tailcfg.SSHEventNotifyRequest{
|
re := tailcfg.SSHEventNotifyRequest{
|
||||||
EventType: notifyType,
|
EventType: notifyType,
|
||||||
|
ConnectionID: ss.conn.connID,
|
||||||
CapVersion: tailcfg.CurrentCapabilityVersion,
|
CapVersion: tailcfg.CurrentCapabilityVersion,
|
||||||
NodeKey: nodeKey,
|
NodeKey: nodeKey,
|
||||||
SrcNode: ss.conn.info.node.ID,
|
SrcNode: ss.conn.info.node.ID,
|
||||||
|
|
|
@ -2080,6 +2080,12 @@ type SSHRecorderFailureAction struct {
|
||||||
type SSHEventNotifyRequest struct {
|
type SSHEventNotifyRequest struct {
|
||||||
// EventType is the type of notify request being sent.
|
// EventType is the type of notify request being sent.
|
||||||
EventType SSHEventType
|
EventType SSHEventType
|
||||||
|
|
||||||
|
// ConnectionID uniquely identifies a connection made to the SSH server.
|
||||||
|
// It may be shared across multiple sessions over the same connection in
|
||||||
|
// case a single connection creates multiple sessions.
|
||||||
|
ConnectionID string
|
||||||
|
|
||||||
// CapVersion is the client's current CapabilityVersion.
|
// CapVersion is the client's current CapabilityVersion.
|
||||||
CapVersion CapabilityVersion
|
CapVersion CapabilityVersion
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue