sessionrecording,ssh/tailssh,k8s-operator: log connected recorder address (#13382)

Updates tailscale/corp#19821

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
This commit is contained in:
Irbe Krumina 2024-09-07 08:11:33 +03:00 committed by GitHub
parent 7ce9c1944a
commit 2b0d0ddf5d
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 18 additions and 8 deletions

View File

@ -15,6 +15,7 @@
"io" "io"
"net" "net"
"net/http" "net/http"
"net/http/httptrace"
"net/netip" "net/netip"
"strings" "strings"
@ -137,8 +138,15 @@ func (h *Hijacker) setUpRecording(ctx context.Context, conn net.Conn) (net.Conn,
errChan <-chan error errChan <-chan error
) )
h.log.Infof("kubectl exec session will be recorded, recorders: %v, fail open policy: %t", h.addrs, h.failOpen) h.log.Infof("kubectl exec session will be recorded, recorders: %v, fail open policy: %t", h.addrs, h.failOpen)
// TODO (irbekrm): send client a message that session will be recorded. qp := h.req.URL.Query()
wc, _, errChan, err = h.connectToRecorder(ctx, h.addrs, h.ts.Dial) container := strings.Join(qp[containerKey], "")
var recorderAddr net.Addr
trace := &httptrace.ClientTrace{
GotConn: func(info httptrace.GotConnInfo) {
recorderAddr = info.Conn.RemoteAddr()
},
}
wc, _, errChan, err = h.connectToRecorder(httptrace.WithClientTrace(ctx, trace), h.addrs, h.ts.Dial)
if err != nil { if err != nil {
msg := fmt.Sprintf("error connecting to session recorders: %v", err) msg := fmt.Sprintf("error connecting to session recorders: %v", err)
if h.failOpen { if h.failOpen {
@ -151,13 +159,12 @@ func (h *Hijacker) setUpRecording(ctx context.Context, conn net.Conn) (net.Conn,
return nil, multierr.New(errors.New(msg), err) return nil, multierr.New(errors.New(msg), err)
} }
return nil, errors.New(msg) return nil, errors.New(msg)
} else {
h.log.Infof("exec session to container %q in Pod %q namespace %q will be recorded, the recording will be sent to a tsrecorder instance at %q", container, h.pod, h.ns, recorderAddr)
} }
// TODO (irbekrm): log which recorder
h.log.Info("successfully connected to a session recorder")
cl := tstime.DefaultClock{} cl := tstime.DefaultClock{}
rec := tsrecorder.New(wc, cl, cl.Now(), h.failOpen, h.log) rec := tsrecorder.New(wc, cl, cl.Now(), h.failOpen, h.log)
qp := h.req.URL.Query()
tty := strings.Join(qp[ttyKey], "") tty := strings.Join(qp[ttyKey], "")
hasTerm := (tty == "true") // session has terminal attached hasTerm := (tty == "true") // session has terminal attached
ch := sessionrecording.CastHeader{ ch := sessionrecording.CastHeader{
@ -169,7 +176,7 @@ func (h *Hijacker) setUpRecording(ctx context.Context, conn net.Conn) (net.Conn,
Kubernetes: &sessionrecording.Kubernetes{ Kubernetes: &sessionrecording.Kubernetes{
PodName: h.pod, PodName: h.pod,
Namespace: h.ns, Namespace: h.ns,
Container: strings.Join(qp[containerKey], " "), Container: container,
}, },
} }
if !h.who.Node.IsTagged() { if !h.who.Node.IsTagged() {

View File

@ -78,7 +78,10 @@ func Test_Hijacker(t *testing.T) {
tc := &fakes.TestConn{} tc := &fakes.TestConn{}
ch := make(chan error) ch := make(chan error)
h := &Hijacker{ h := &Hijacker{
connectToRecorder: func(context.Context, []netip.AddrPort, func(context.Context, string, string) (net.Conn, error)) (wc io.WriteCloser, rec []*tailcfg.SSHRecordingAttempt, _ <-chan error, err error) { connectToRecorder: func(context.Context,
[]netip.AddrPort,
func(context.Context, string, string) (net.Conn, error),
) (wc io.WriteCloser, rec []*tailcfg.SSHRecordingAttempt, _ <-chan error, err error) {
if tt.failRecorderConnect { if tt.failRecorderConnect {
err = errors.New("test") err = errors.New("test")
} }

View File

@ -105,7 +105,7 @@ func ConnectToRecorder(ctx context.Context, recs []netip.AddrPort, dial func(con
} }
attempt.FailureMessage = err.Error() attempt.FailureMessage = err.Error()
errs = append(errs, err) errs = append(errs, err)
continue continue // try the next recorder
} }
return pw, attempts, errChan, nil return pw, attempts, errChan, nil
} }