Kubernetes API server proxy 'kubectl' session recording
In Tailscale 1.70 and later, you can record kubectl exec, kubectl debug, kubectl attach, and kubectl run session contents when using the Kubernetes API server proxy.
Recorded sessions are sent to a configured tsrecorder instance in your tailnet.
The tsrecorder supports storing recorded sessions in an S3-compatible storage or on disk.
A recording contains:
- The command sent in the
kubectlcall. For example,kubectl exec -- cat /myfile.txtwill show up ascat /myfile.txt. - The session type being recorded (either
execorattach) - The contents of
stdoutandstderrfrom the attached terminal, but notstdin. This prevents the recording of sensitive input, such as passwords. - Session start timestamp.
- Name and namespace of the
Podand name of the container being recorded. - Tailscale hostname of the API server proxy.
- Tailscale identity that initiated the session:
- Tailscale hostname of the source device from which the
kubectlsession was inititated. - If the source device is tagged, tags of the device.
- If the source device is not tagged, Tailscale user ID and login name.
- Tailscale hostname of the source device from which the
The API server proxy sends session contents to tsrecorder over the tailnet, so the traffic is end-to-end encrypted using WireGuard, like any other tailnet traffic.
You can choose whether a kubectl session should be allowed ('fail open') or be forbidden ('fail closed') if the recording fails. For example, if a connection to tsrecorder cannot be established or fails.
Prerequisites
- Set up the Tailscale Kubernetes Operator with the API server proxy enabled.
- Deploy a tagged
tsrecorderinstance. Note that you can also deploytsrecorderon Kubernetes using the operator. - Ensure that your ACLs allow the operator to access port
80of thetsrecorder.
Configure the session recording
You can configure session recording options using grants.
Grants only configure how the API server proxy treats incoming connections; they do not configure tailnet device connectivity. To allow clients to connect, refer to the API server proxy prerequisites.
You must specify the source (the tailnet identity that initiates the kubectl session), the destination (the API server proxy), and the tsrecorder instance. You can also specify the failure policy. The default failure policy is to fail open.
The following example:
- Allows requests from
group:engineeringto connect to the API server proxy on all operator instances tagged withtag:k8s-operatoron port443. - Enforces session recording for
kubectlsessions from tailnet groupgroup:engineeringto all API server proxy instances tagged withtag:k8s-operator. - Configures the recorded sessions to be sent to a
tsrecorderinstance tagged withtag:tsrecorder. - Sets failure policy to "fail closed" (if the recording fails, forbid the session).
"acls": [
{"action": "accept", "src": ["group:engineering"], "dst": ["tag:k8s-operator:443"]}
],
"grants": [
{
"src": ["group:engineering"],
"dst": ["tag:k8s-operator"],
"app": {
"tailscale.com/cap/kubernetes": [{
"recorder": ["tag:tsrecorder"],
"enforceRecorder": true,
}],
},
},
]
If tag:tsrecorder resolves to multiple tailnet IP addresses, the API server proxy will send the recording to the first instance to which it succeeds at establishing a connection.
Combine session recording and group impersonation in grant rules
A grant can also combine session recording rules and API server proxy impersonation rules.
The following example:
-
Allows requests from
group:engineeringto connect to the API server proxy on all operator instances tagged withtag:k8s-operatoron port443. -
Configures session recording for
kubectlsessions from groupgroup:engineeringto all operator instances tagged withtag:k8s-operator. -
Configures the recorded sessions to be sent to a tsrecorder instance tagged with
tag:tsrecorder. -
Configures that requests from
group:engineeringshould be impersonated as from Kubernetes groupsystem:masters.
"acls": [
{"action": "accept", "src": ["group:engineering"], "dst": ["tag:k8s-operator:443"]}
],
"grants": [
{
"src": ["group:engineering"],
"dst": ["tag:k8s-operator"],
"app": {
"tailscale.com/cap/kubernetes": [{
"impersonate": {
"groups": ["system:masters"],
},
"recorder": ["tag:tsrecorder"],
}],
},
},
]
Enforce recording of all sessions
To ensure the recording of all kubectl sessions, use the wildcard syntax (*) as the grant's source and/or destination.
The following example:
-
Enforces recording of all
kubectlsessions from any source to any API server proxy instance. -
Configures the recording to be sent to tsrecorder instance tagged with
tag:tsrecorder.
"grants": [
{
"src": ["*"],
"dst": ["*"],
"app": {
"tailscale.com/cap/kubernetes": [{
"recorder": ["tag:tsrecorder"],
"enforceRecorder": true,
}],
},
},
]
Known issues and limitations
- In some cases, if an established connection to
tsrecorderfails midway (because thetsrecorderinstance fails), the session will be allowed to continue even if the policy is to fail closed. We are working on fixing this.
