kube,tailcfg: store parsed recorder tags in a separate field (#12429)

Add an additional RecorderAddrs field to tailscale.com/cap/kubernetes
capability. RecorderAddrs will only be populated by control
with the addresses of any tsrecorder tags set via Recorder.

Updates tailscale/corp#19821

Signed-off-by: Irbe Krumina <irbe@tailscale.com>
pull/12437/head
Irbe Krumina 6 months ago committed by GitHub
parent 3511d1f8a2
commit a95ea31a4e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -6,21 +6,30 @@
// Further, the API should not be considered stable. // Further, the API should not be considered stable.
package kube package kube
import "net/netip"
// KubernetesCapRule is a rule provided via PeerCapabilityKubernetes capability. // KubernetesCapRule is a rule provided via PeerCapabilityKubernetes capability.
type KubernetesCapRule struct { type KubernetesCapRule struct {
// Impersonate is a list of rules that specify how to impersonate the caller // Impersonate is a list of rules that specify how to impersonate the caller
// when proxying to the Kubernetes API. // when proxying to the Kubernetes API.
Impersonate *ImpersonateRule `json:"impersonate,omitempty"` Impersonate *ImpersonateRule `json:"impersonate,omitempty"`
// Recorders defines a tag that should resolve to a tsrecorder // Recorders defines a tag of a tsrecorder instance(s) that a recording
// instance(s). If set, any `kubectl exec` session from a client // of a 'kubectl exec' session, matching `src` of this grant, to an API
// matching `src` of this grant to an API server proxy matching `dst` of // server proxy, matching `dst` of this grant, should be sent to.
// this grant will be recorded and the recording will be sent to the // This list must not contain more than one tag. The field
// tsrecorder. // name matches the `Recorder` field with equal semantics for Tailscale
// This list must not contain more than one tag. // SSH session recorder. This field is set by users in ACL grants and is
// The field name matches the `Recorder` field with equal semantics for Tailscale SSH // then parsed by control, which resolves the tags and populates `RecorderAddrs``.
// session recorder.
// https://tailscale.com/kb/1246/tailscale-ssh-session-recording#turn-on-session-recording-in-acls // https://tailscale.com/kb/1246/tailscale-ssh-session-recording#turn-on-session-recording-in-acls
Recorders []string `json:"recorder,omitempty"` Recorders []string `json:"recorder,omitempty"`
// RecorderAddrs is a list of addresses that should be addresses of one
// or more tsrecorder instance(s). If set, any `kubectl exec` session
// from a client matching `src` of this grant to an API server proxy
// matching `dst` of this grant will be recorded and the recording will
// be sent to the tsrecorder. This field does not exist in the user
// provided ACL grants - it is populated by control, which obtains the
// addresses by resolving the tags provided via `Recorders` field.
RecorderAddrs []netip.AddrPort `json:"recoderAddrs,omitempty"`
// EnforceRecorder defines whether a kubectl exec session from a client // EnforceRecorder defines whether a kubectl exec session from a client
// matching `src` to an API server proxy matching `dst` should fail // matching `src` to an API server proxy matching `dst` should fail
// closed if it cannot be recorded (i.e if no recoder can be reached). // closed if it cannot be recorded (i.e if no recoder can be reached).

@ -858,11 +858,13 @@ func TestMarshalToRawMessageAndBack(t *testing.T) {
type inner struct { type inner struct {
Groups []string `json:"groups,omitempty"` Groups []string `json:"groups,omitempty"`
} }
testip := netip.MustParseAddrPort("1.2.3.4:80")
type testRule struct { type testRule struct {
Ports []int `json:"ports,omitempty"` Ports []int `json:"ports,omitempty"`
ToggleOn bool `json:"toggleOn,omitempty"` ToggleOn bool `json:"toggleOn,omitempty"`
Name string `json:"name,omitempty"` Name string `json:"name,omitempty"`
Groups inner `json:"groups,omitempty"` Groups inner `json:"groups,omitempty"`
Addrs []netip.AddrPort `json:"addrs"`
} }
tests := []struct { tests := []struct {
name string name string
@ -881,7 +883,7 @@ func TestMarshalToRawMessageAndBack(t *testing.T) {
}, },
{ {
name: "all values", name: "all values",
val: testRule{Ports: []int{80, 443}, Name: "foo", ToggleOn: true, Groups: inner{Groups: []string{"foo", "bar"}}}, val: testRule{Ports: []int{80, 443}, Name: "foo", ToggleOn: true, Groups: inner{Groups: []string{"foo", "bar"}}, Addrs: []netip.AddrPort{testip}},
capType: PeerCapability("foo"), capType: PeerCapability("foo"),
}, },
} }

Loading…
Cancel
Save