diff --git a/cmd/k8s-operator/deploy/crds/tailscale.com_connectors.yaml b/cmd/k8s-operator/deploy/crds/tailscale.com_connectors.yaml
index 74d32d53d..03c51c755 100644
--- a/cmd/k8s-operator/deploy/crds/tailscale.com_connectors.yaml
+++ b/cmd/k8s-operator/deploy/crds/tailscale.com_connectors.yaml
@@ -181,6 +181,14 @@ spec:
items:
type: string
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this Connector should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - rule: self == oldSelf
+ message: Connector tailnet is immutable
x-kubernetes-validations:
- rule: has(self.subnetRouter) || (has(self.exitNode) && self.exitNode == true) || has(self.appConnector)
message: A Connector needs to have at least one of exit node, subnet router or app connector configured.
diff --git a/cmd/k8s-operator/deploy/crds/tailscale.com_proxygroups.yaml b/cmd/k8s-operator/deploy/crds/tailscale.com_proxygroups.yaml
index 98ca1c378..0254f01b8 100644
--- a/cmd/k8s-operator/deploy/crds/tailscale.com_proxygroups.yaml
+++ b/cmd/k8s-operator/deploy/crds/tailscale.com_proxygroups.yaml
@@ -139,6 +139,14 @@ spec:
items:
type: string
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this ProxyGroup should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - rule: self == oldSelf
+ message: ProxyGroup tailnet is immutable
type:
description: |-
Type of the ProxyGroup proxies. Supported types are egress, ingress, and kube-apiserver.
diff --git a/cmd/k8s-operator/deploy/crds/tailscale.com_recorders.yaml b/cmd/k8s-operator/deploy/crds/tailscale.com_recorders.yaml
index 48db3ef4b..e8cce7b0b 100644
--- a/cmd/k8s-operator/deploy/crds/tailscale.com_recorders.yaml
+++ b/cmd/k8s-operator/deploy/crds/tailscale.com_recorders.yaml
@@ -1688,6 +1688,14 @@ spec:
items:
type: string
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this Recorder should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - rule: self == oldSelf
+ message: Recorder tailnet is immutable
x-kubernetes-validations:
- rule: '!(self.replicas > 1 && (!has(self.storage) || !has(self.storage.s3)))'
message: S3 storage must be used when deploying multiple Recorder replicas
diff --git a/cmd/k8s-operator/deploy/manifests/operator.yaml b/cmd/k8s-operator/deploy/manifests/operator.yaml
index 71c0b89b1..9219636a9 100644
--- a/cmd/k8s-operator/deploy/manifests/operator.yaml
+++ b/cmd/k8s-operator/deploy/manifests/operator.yaml
@@ -206,6 +206,14 @@ spec:
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
type: string
type: array
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this Connector should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - message: Connector tailnet is immutable
+ rule: self == oldSelf
type: object
x-kubernetes-validations:
- message: A Connector needs to have at least one of exit node, subnet router or app connector configured.
@@ -3145,6 +3153,14 @@ spec:
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
type: string
type: array
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this ProxyGroup should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - message: ProxyGroup tailnet is immutable
+ rule: self == oldSelf
type:
description: |-
Type of the ProxyGroup proxies. Supported types are egress, ingress, and kube-apiserver.
@@ -4968,6 +4984,14 @@ spec:
pattern: ^tag:[a-zA-Z][a-zA-Z0-9-]*$
type: string
type: array
+ tailnet:
+ description: |-
+ Tailnet specifies the tailnet this Recorder should join. If blank, the default tailnet is used. When set, this
+ name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ type: string
+ x-kubernetes-validations:
+ - message: Recorder tailnet is immutable
+ rule: self == oldSelf
type: object
x-kubernetes-validations:
- message: S3 storage must be used when deploying multiple Recorder replicas
diff --git a/k8s-operator/api.md b/k8s-operator/api.md
index db5402b27..31f351013 100644
--- a/k8s-operator/api.md
+++ b/k8s-operator/api.md
@@ -141,6 +141,7 @@ _Appears in:_
| `appConnector` _[AppConnector](#appconnector)_ | AppConnector defines whether the Connector device should act as a Tailscale app connector. A Connector that is
configured as an app connector cannot be a subnet router or an exit node. If this field is unset, the
Connector does not act as an app connector.
Note that you will need to manually configure the permissions and the domains for the app connector via the
Admin panel.
Note also that the main tested and supported use case of this config option is to deploy an app connector on
Kubernetes to access SaaS applications available on the public internet. Using the app connector to expose
cluster workloads or other internal workloads to tailnet might work, but this is not a use case that we have
tested or optimised for.
If you are using the app connector to access SaaS applications because you need a predictable egress IP that
can be whitelisted, it is also your responsibility to ensure that cluster traffic from the connector flows
via that predictable IP, for example by enforcing that cluster egress traffic is routed via an egress NAT
device with a static IP address.
https://tailscale.com/kb/1281/app-connectors | | |
| `exitNode` _boolean_ | ExitNode defines whether the Connector device should act as a Tailscale exit node. Defaults to false.
This field is mutually exclusive with the appConnector field.
https://tailscale.com/kb/1103/exit-nodes | | |
| `replicas` _integer_ | Replicas specifies how many devices to create. Set this to enable
high availability for app connectors, subnet routers, or exit nodes.
https://tailscale.com/kb/1115/high-availability. Defaults to 1. | | Minimum: 0
|
+| `tailnet` _string_ | Tailnet specifies the tailnet this Connector should join. If blank, the default tailnet is used. When set, this
name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set. | | |
#### ConnectorStatus
@@ -743,6 +744,7 @@ _Appears in:_
| `hostnamePrefix` _[HostnamePrefix](#hostnameprefix)_ | HostnamePrefix is the hostname prefix to use for tailnet devices created
by the ProxyGroup. Each device will have the integer number from its
StatefulSet pod appended to this prefix to form the full hostname.
HostnamePrefix can contain lower case letters, numbers and dashes, it
must not start with a dash and must be between 1 and 62 characters long. | | Pattern: `^[a-z0-9][a-z0-9-]{0,61}$`
Type: string
|
| `proxyClass` _string_ | ProxyClass is the name of the ProxyClass custom resource that contains
configuration options that should be applied to the resources created
for this ProxyGroup. If unset, and there is no default ProxyClass
configured, the operator will create resources with the default
configuration. | | |
| `kubeAPIServer` _[KubeAPIServerConfig](#kubeapiserverconfig)_ | KubeAPIServer contains configuration specific to the kube-apiserver
ProxyGroup type. This field is only used when Type is set to "kube-apiserver". | | |
+| `tailnet` _string_ | Tailnet specifies the tailnet this ProxyGroup should join. If blank, the default tailnet is used. When set, this
name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set. | | |
#### ProxyGroupStatus
@@ -903,6 +905,7 @@ _Appears in:_
| `enableUI` _boolean_ | Set to true to enable the Recorder UI. The UI lists and plays recorded sessions.
The UI will be served at :443. Defaults to false.
Corresponds to --ui tsrecorder flag https://tailscale.com/kb/1246/tailscale-ssh-session-recording#deploy-a-recorder-node.
Required if S3 storage is not set up, to ensure that recordings are accessible. | | |
| `storage` _[Storage](#storage)_ | Configure where to store session recordings. By default, recordings will
be stored in a local ephemeral volume, and will not be persisted past the
lifetime of a specific pod. | | |
| `replicas` _integer_ | Replicas specifies how many instances of tsrecorder to run. Defaults to 1. | | Minimum: 0
|
+| `tailnet` _string_ | Tailnet specifies the tailnet this Recorder should join. If blank, the default tailnet is used. When set, this
name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set. | | |
#### RecorderStatefulSet
diff --git a/k8s-operator/apis/v1alpha1/types_connector.go b/k8s-operator/apis/v1alpha1/types_connector.go
index 58457500f..ebedea18f 100644
--- a/k8s-operator/apis/v1alpha1/types_connector.go
+++ b/k8s-operator/apis/v1alpha1/types_connector.go
@@ -133,6 +133,12 @@ type ConnectorSpec struct {
// +optional
// +kubebuilder:validation:Minimum=0
Replicas *int32 `json:"replicas,omitempty"`
+
+ // Tailnet specifies the tailnet this Connector should join. If blank, the default tailnet is used. When set, this
+ // name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Connector tailnet is immutable"
+ Tailnet string `json:"tailnet,omitempty"`
}
// SubnetRouter defines subnet routes that should be exposed to tailnet via a
diff --git a/k8s-operator/apis/v1alpha1/types_proxygroup.go b/k8s-operator/apis/v1alpha1/types_proxygroup.go
index 28fd9e009..8cbcc2d19 100644
--- a/k8s-operator/apis/v1alpha1/types_proxygroup.go
+++ b/k8s-operator/apis/v1alpha1/types_proxygroup.go
@@ -97,6 +97,12 @@ type ProxyGroupSpec struct {
// ProxyGroup type. This field is only used when Type is set to "kube-apiserver".
// +optional
KubeAPIServer *KubeAPIServerConfig `json:"kubeAPIServer,omitempty"`
+
+ // Tailnet specifies the tailnet this ProxyGroup should join. If blank, the default tailnet is used. When set, this
+ // name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="ProxyGroup tailnet is immutable"
+ Tailnet string `json:"tailnet,omitempty"`
}
type ProxyGroupStatus struct {
diff --git a/k8s-operator/apis/v1alpha1/types_recorder.go b/k8s-operator/apis/v1alpha1/types_recorder.go
index 67cffbf09..d5a22e82c 100644
--- a/k8s-operator/apis/v1alpha1/types_recorder.go
+++ b/k8s-operator/apis/v1alpha1/types_recorder.go
@@ -81,6 +81,12 @@ type RecorderSpec struct {
// +optional
// +kubebuilder:validation:Minimum=0
Replicas *int32 `json:"replicas,omitzero"`
+
+ // Tailnet specifies the tailnet this Recorder should join. If blank, the default tailnet is used. When set, this
+ // name must match that of a valid Tailnet resource. This field is immutable and cannot be changed once set.
+ // +optional
+ // +kubebuilder:validation:XValidation:rule="self == oldSelf",message="Recorder tailnet is immutable"
+ Tailnet string `json:"tailnet,omitempty"`
}
type RecorderStatefulSet struct {