cmd/k8s-operator,k8s-operator/sessionrecording: support recording kubectl exec sessions over WebSockets (#12947)

cmd/k8s-operator,k8s-operator/sessionrecording: support recording WebSocket sessions

Kubernetes currently supports two streaming protocols, SPDY and WebSockets.
WebSockets are replacing SPDY, see
https://github.com/kubernetes/enhancements/issues/4006.
We were currently only supporting SPDY, erroring out if session
was not SPDY and relying on the kube's built-in SPDY fallback.

This PR:

- adds support for parsing contents of 'kubectl exec' sessions streamed
over WebSockets

- adds logic to distinguish 'kubectl exec' requests for a SPDY/WebSockets
sessions and call the relevant handler

Updates tailscale/corp#19821

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
Co-authored-by: Tom Proctor <tomhjp@users.noreply.github.com>
This commit is contained in:
Irbe Krumina
2024-08-14 19:57:50 +03:00
committed by GitHub
parent 4c2e978f1e
commit a15ff1bade
13 changed files with 1270 additions and 73 deletions

View File

@ -37,30 +37,40 @@ func Test_Hijacker(t *testing.T) {
failRecorderConnPostConnect bool // send error down the error channel
wantsConnClosed bool
wantsSetupErr bool
proto Protocol
}{
{
name: "setup succeeds, conn stays open",
name: "setup_succeeds_conn_stays_open",
proto: SPDYProtocol,
},
{
name: "setup fails, policy is to fail open, conn stays open",
name: "setup_succeeds_conn_stays_open_ws",
proto: WSProtocol,
},
{
name: "setup_fails_policy_is_to_fail_open_conn_stays_open",
failOpen: true,
failRecorderConnect: true,
proto: SPDYProtocol,
},
{
name: "setup fails, policy is to fail closed, conn is closed",
name: "setup_fails_policy_is_to_fail_closed_conn_is_closed",
failRecorderConnect: true,
wantsSetupErr: true,
wantsConnClosed: true,
proto: SPDYProtocol,
},
{
name: "connection fails post-initial connect, policy is to fail open, conn stays open",
name: "connection_fails_post-initial_connect_policy_is_to_fail_open_conn_stays_open",
failRecorderConnPostConnect: true,
failOpen: true,
proto: SPDYProtocol,
},
{
name: "connection fails post-initial connect, policy is to fail closed, conn is closed",
name: "connection_fails_post-initial_connect,_policy_is_to_fail_closed_conn_is_closed",
failRecorderConnPostConnect: true,
wantsConnClosed: true,
proto: SPDYProtocol,
},
}
for _, tt := range tests {
@ -79,6 +89,7 @@ func Test_Hijacker(t *testing.T) {
log: zl.Sugar(),
ts: &tsnet.Server{},
req: &http.Request{URL: &url.URL{}},
proto: tt.proto,
}
ctx := context.Background()
_, err := h.setUpRecording(ctx, tc)