Kubernetes operator
The Tailscale Kubernetes operator allows you to expose services in your Kubernetes cluster to your Tailscale network, and use an authentication proxy for secure connectivity to the Kubernetes control plane. Once installed, you can mark services in your cluster as Tailscale-accessible, and the operator will take care of the plumbing to add those services as nodes on your tailnet.
Setting up the Kubernetes operator
-
In your tailnet policy file, create the ACL tags
tag:k8s-operator
andtag:k8s
, and maketag:k8s-operator
an owner oftag:k8s
. If you want your services to be exposed with tags other than the defaulttag:k8s
, create those as well and maketag:k8s-operator
an owner."tagOwners": { "tag:k8s-operator": [], "tag:k8s": ["tag:k8s-operator"], }
-
Create an OAuth client in the OAuth clients page of the admin console. Create the client with
Devices
write scope and the tagtag:k8s-operator
. -
Download the Tailscale Kubernetes operator manifest file from the tailscale/tailscale repo.
-
Edit your version of the manifest file:
- Find
# SET CLIENT ID HERE
and replace it with your OAuth client ID. - Find
# SET CLIENT SECRET HERE
and replace it with your OAuth client secret.
For both the client ID and secret, quote the value, to avoid any potential yaml misinterpretation of unquoted strings. For example, use:
client_id: "k123456CNTRL" client_secret: "tskey-client-k123456CNTRL-abcdef"
instead of:
client_id: k123456CNTRL client_secret: tskey-client-k123456CNTRL-abcdef
- Find
-
Apply the edited file to your Kubernetes cluster:
kubectl apply -f manifest.yaml
This creates the “tailscale” namespace in your cluster, and deploys the Tailscale operator within it.
-
Verify that the Tailscale operator has joined your tailnet. Open the Machines page of the admin console and look for a node named tailscale-operator, tagged with the
tag:k8s-operator
tag. It may take a minute or two for the operator to join your tailnet, due to the time required to download and start the container image in Kubernetes.
Using the Kubernetes operator
You can expose a Kubernetes service over Tailscale in two ways: by making it a LoadBalancer
type with the tailscale
loadBalancerClass
, or by annotating an existing service.
Exposing a service using loadBalancerClass
Edit the service you want to expose and make it a load balancer:
- Set
spec.type
toLoadBalancer
. - Set
spec.loadBalancerClass
totailscale
.
Once provisioning is complete, the service’s status will show the
fully-qualified domain name of the service in your tailnet. You can view the
service’s status by running kubectl get service <service name>
.
You should also see a new node with that name appear in the Machines page of the admin console.
Exposing a service using annotations
If the service you want to expose already exists, you can expose it to Tailscale using object annotations.
Edit the service and under metadata.annotations
, add the annotation
tailscale.com/expose
with the value "true"
. Note that "true"
is quoted
because annotation values are strings, and an unquoted true
will be
incorrectly interpreted as a boolean.
In this mode, Kubernetes doesn’t tell you the Tailscale machine name. You can look
up the node in the Machines of the admin console to learn
its machine name. By default, the machine name of an exposed service is
<k8s-namespace>-<k8s-servicename>
.
Using a custom machine name
If you want the service to have a machine name other than the default
<k8s-namespace>-<k8s-servicename>
, you can provide your own machine name by
setting the tailscale.com/hostname
annotation on the service, with your
desired machine name as the value.
Machine names are subject to the constraints of DNS: they can be up to 63 characters
long, must start and end with a letter, and consist of only letters, numbers,
and -
.
Customizing tags
By default, services join your tailnet tagged with tag:k8s
. You can request a
different set of tags by setting the tailscale.com/tags
annotation on the
service, with your desired tags (comma-separated) as the value.
For example, setting tailscale.com/tags = tag:foo,tag:bar
will result in the
tailnet node having the tags tag:foo
and tag:bar
.
The Tailscale operator must be a tag owner of all the specified tags: if you want
to expose a service with tag:foo,tag:bar
, the tagOwners
section of the
tailnet policy file must list tag:k8s-operator
as one
of the owners of both tag:foo
and tag:bar
.
Enabling an auth proxy
A Tailscale Kubernetes auth proxy allows users to expose and access their Kubernetes control plane (kube-apiserver) over Tailscale. When a user tries to access the Kubernetes control plane over Tailscale, they will hit the kube-apiserver with the same user identity that they have in Tailscale. For example, alice@example.com
will have the user alice@example.com
in an auth proxy. To use a Tailscale Kubernetes auth proxy, you also need to enable HTTPS for your tailnet.
To configure the auth proxy:
-
In your Tailscale Kubernetes operator.yml file, add the following lines to the
env
section:name: AUTH_PROXY value: "true"
The kube-apiserver is automatically discovered by the operator.
-
Apply the changes from the example to your operator’s manifest file.
apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: name: tailscale-auth-proxy rules: - apiGroups: [""] resources: ["users"] verbs: ["impersonate"] --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: tailscale-auth-proxy subjects: - kind: ServiceAccount name: operator namespace: tailscale roleRef: kind: ClusterRole name: tailscale-auth-proxy apiGroup: rbac.authorization.k8s.io
-
Add an access rule in your tailnet’s policy file to grant access to the auth proxy over Tailscale.
-
Use the
tailscale configure kubeconfig <hostname-or-fqdn>
CLI command to configure your localkubeconfig
file to manage how to authenticate to kubectl as the Tailscale Kubernetes auth proxy. -
Run the following command to grant a user the Kubernetes cluster-admin role in your cluster.
kubectl create clusterrolebinding --clusterrole cluster-admin --user alice@example alice@example
To validate the auth proxy allows you to access the kube-apiserver over Tailscale:
- Run the
kubectl get pods -A
command to run another test and verify that you have authorization.NAMESPACE NAME READY STATUS RESTARTS AGE kube-system cilium-6b2x8 1/1 Running 0 28d kube-system cilium-operator-759999b555-qbsrk 1/1 Running 3 (21d ago) 29d kube-system coredns-7697897646-4vh2l 1/1 Running 0 29d kube-system coredns-7697897646-rshwm 1/1 Running 0 29d kube-system cpc-bridge-proxy-xksns 1/1 Running 0 29d kube-system csi-do-node-k5snn 2/2 Running 0 29d kube-system do-node-agent-n8nrr 1/1 Running 0 29d kube-system konnectivity-agent-k846g 1/1 Running 0 29d kube-system kube-proxy-lgzr9 1/1 Running 0 29d tailscale operator-6b94c54478-n6tmc 1/1 Running 0 14d
Cleanup
Any of the following actions remove the service from your tailnet:
- Delete the service entirely.
- If you are using the
tailscale.com/expose
annotation, remove the annotation. - If you are using
type=LoadBalancer
, settype
back toClusterIP
, or removeloadBalancerClass=tailscale
.
Note that deletion is a one-way operation: deleting a service’s Tailscale node in the admin console does not clean up the Kubernetes state associated with that service.
Limitations
The alpha Tailscale operator has the following known issues and limitations that we plan to address.
- The auth proxy runs inside of the cluster. If your cluster is non-functional or is unable to schedule pods, you may lose access to the auth proxy.
- Only development (“unstable”) builds are usable for now, as the operator depends on some changes that happened after the release of Tailscale v1.36.
- There are no deployment options other than applying manifest.yaml. Let us know what other deployment methods you would like!
- Tags are only considered during initial provisioning. That is, editing
tailscale.com/tags
on an already exposed service doesn’t update the tags until you clean up and re-expose the service. - The requested machine name is only considered during initial provisioning. That
is, editing
tailscale.com/hostname
on an already exposed service doesn’t update the machine name until you clean up and re-expose the service. - There are no automated updates. The operator and proxy pods will not update automatically to newer Tailscale releases as they become available.
- There are no dashboards or metrics.