Use multiple tailnets for devices running on Kubernetes

Last validated:

When deploying the Tailscale Kubernetes Operator's custom resources, you may want workloads to communicate across clusters and across tailnets. In Tailscale v1.96 and later, you can use the Tailnet custom resource definition to specify which tailnet a ProxyGroup, Connector, or Recorder instance should use.

Prerequisites

You need access to multiple tailnets, either through separate logins or managed by a single organization. For more information on managing multiple tailnets within a single organization, refer to managing multiple tailnets.

Each tailnet you want to expose requires the appropriate tagOwners set in your ACL policy file for the Tailscale Kubernetes Operator:

"tagOwners": {
	"tag:k8s-operator": [],
	"tag:k8s": ["tag:k8s-operator"],
}

If you use different tags from the default tag:k8s-operator, use those in place of the example given above.

Each tailnet also requires an OAuth client that the operator uses to generate auth keys for workloads. Before creating a Tailnet resource, create a new OAuth client in the OAuth clients for the tailnet you want to provide access to. Create the client with Devices Core, Auth Keys, Services write scopes, and the tag tag:k8s-operator.

Create a Tailnet resource

Each Tailnet resource references a set of OAuth credentials stored as a Kubernetes Secret within the same namespace as the operator.

Once you have the client ID and secret, create a Secret resource:

apiVersion: v1
kind: Secret
metadata:
  name: example-tailnet
  namespace: tailscale
stringData:
  client_id: "<CLIENT_ID>"
  client_secret: "<CLIENT_SECRET>"

If you deployed the Tailscale Kubernetes Operator into a different namespace, use the name of that namespace instead of tailscale.

Next, create a Tailnet resource that references the secret containing the OAuth credentials:

apiVersion: tailscale.com/v1alpha
kind: Tailnet
metadata:
  name: example-tailnet
spec:
  credentials:
    secretName: example-tailnet

Tailnet resources are cluster-scoped and do not require a value in the namespace field.

Once deployed, the operator checks that the specified credentials exist and have access to the Tailscale API. If successful, the Tailnet resource transitions into the TailnetReady state and can be used by other resources. Use the kubectl get tailnet command to view the status of your tailnet.

Configure resources to use a specific tailnet

Once you have one or more Tailnet resources in your cluster, you can create ProxyGroup, Connector, and Recorder resources that connect to that tailnet using the spec.tailnet field. This field is immutable, with a blank tailnet denoting that the resource should use the tailnet that the operator was originally configured with.

The following examples show how to configure these resources to use a specific tailnet.

A Connector resource using a specific tailnet:

apiVersion: tailscale.com/v1alpha1
kind: Connector
metadata:
	name: example-connector
spec:
	replicas: 3
	tailnet: example-tailnet
	exitNode: true

For more information on Connector resources, refer to create exit nodes and subnet routers on Kubernetes.

A Recorder resource using a specific tailnet:

apiVersion: tailscale.com/v1alpha1
kind: Recorder
metadata:
	name: example-recorder
spec:
	replicas: 3
	tailnet: example-tailnet
	storage: {}

For more information on Recorder resources, refer to session recording.

A ProxyGroup resource using a specific tailnet:

apiVersion: tailscale.com/v1alpha1
kind: ProxyGroup
metadata:
	name: example-proxygroup
spec:
	replicas: 3
	tailnet: example-tailnet
	type: kube-apiserver

For more information on ProxyGroup resources, refer to the ingress or egress documentation.

Once started and ready, your devices appear across your tailnets in the respective Machines pages.