Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

cmd/k8s-operator,ssh/tailssh,tsnet: optionally record 'kubectl exec' sessions via Kubernetes operator's API server proxy #12274

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

irbekrm
Copy link
Contributor

@irbekrm irbekrm commented May 29, 2024

Adds the ability to forward contents of 'kubectl exec' sessions over the API server proxy to a configured tsrecorder instance.

Users can now configure via grants that kubectl exec sessions over an API server proxy should be recorded.

If so, the proxy hijacks the connection, parses the byte stream as SPDY frames and, for frames that SPDY data frames for stdout/stderr data streams, forwards the payload to the configured session recorder.
If the connection to session recorder fails (either at the point where the proxy is establishing the connection or during the session) the session is only allowed to continue (without recording) if the enforceRecorder is not set to true.

Example user workflow

Scenario: enforce that tailnet users in group group:engineering must have their kubectl exec sessions recorded and sent to (one of) tsrecorder instances tagged by tag:recorder when execing over an API server proxy tagged by tag:k8s-operator:

  • deploy a tsrecorder with ACL tag tag:recorder, deploy a Kubernetes operator with tag:k8s-operator configured to run API server proxy. Ensure that operator has access to the recorder (ACLs).

  • configure ACLs

"grants": [
		{
			"src": ["group:engineering"],
			"dst": ["tag:k8s-operator"],
			"app": {
				"tailscale.com/cap/kubernetes": [{
					"recorder":        ["tag:recorder"],
					"enforceRecorder": true, // fail closed
				}],
			},
		},

kubectl exec sessions from group:engineering via tag:k8s-operator should now be recorded, if no recorders can be reached, the session will be refused.

Notes

  • We check if the session appears to be SPDY. If it is not, we error out and the connection will be refused (even if the recording policy was enforceRecorder = false, see 40e30e5#r1649006397)

  • Tailscale SSH servers are also able to store the recording on disk. For now I am not planning to add this to the operator unless there is a use case (latency?) and am assuming that everyone will be ok to deploy a tsrecorder. We are also planning on making it possible to configure the operator to deploy tsrecorder.

  • Tsrecorder treats these session recordings same as any other. See UI screenshot:

loc

Next steps

  • support for websocket clients

  • additional configuration in tsrecorder to show Kubernetes-specific info such as Pod name/namespace

  • metrics

  • look into dropping connections if ACLs are changed mid-session

  • more testing around performance and the behaviour in cases of ACL reconfig etc. I have, a few times, obeserved a command on recorded session lag for a noticeable period of time before returning

Updates tailscale/corp#19821

@irbekrm irbekrm requested a review from a team as a code owner May 29, 2024 12:15
@irbekrm irbekrm marked this pull request as draft May 29, 2024 12:16
@irbekrm irbekrm force-pushed the irbekrm/sessionrecorder branch 6 times, most recently from 0ccb6a4 to ba208ce Compare June 5, 2024 09:55
@irbekrm irbekrm force-pushed the irbekrm/sessionrecorder branch 7 times, most recently from 0ebeaba to 8265e1f Compare June 21, 2024 09:28
@irbekrm irbekrm marked this pull request as ready for review June 21, 2024 09:29
@irbekrm irbekrm removed the request for review from a team June 21, 2024 09:29
@irbekrm irbekrm force-pushed the irbekrm/sessionrecorder branch 2 times, most recently from 1e4307f to 6566c57 Compare June 21, 2024 12:01
…ssions

The Kubernetes operator's API server proxy, when it receives a request
for 'kubectl exec' session now reads 'RecorderAddrs', 'EnforceRecorder'
fields from tailcfg.KubernetesCapRule.
If 'RecorderAddrs' is set to one or more addresses (of a tsrecorder instance(s)),
it attempts to connect to those and sends the session contents
to the recorder before forwarding the request to the kube API
server. If connection cannot be established or fails midway,
it is only allowed if 'EnforceRecorder' is not true (fail open).

Updates tailscale/corp#19821

Co-authored-by: Maisem Ali <maisem@tailscale.com>
Signed-off-by: Irbe Krumina <irbe@tailscale.com>
var sf spdyFrame
ok, err := sf.Parse(c.writeBuf.Bytes(), log)
if err != nil {
return 0, fmt.Errorf("error parsing data: %w", err)
Copy link
Contributor Author

@irbekrm irbekrm Jun 21, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here we could also, if the policy was to fail open, forward the raw bytes to the original destination anyway (and stop attempting to record the next reads and writes as well?) . Perhaps we can revisit that part in a next iteration

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

1 participant