Get started
© 2024

Kubernetes operator

The Tailscale Kubernetes operator lets you:

Tailscale Kubernetes operator is available for all plans.
Kubernetes operator is currently in beta. To try it, follow the steps below to enable it for your network using Tailscale v1.50 or later.

Setting up the Kubernetes operator


Tailscale Kubernetes Operator must be configured with OAuth client credentials. The operator uses these credentials to manage devices via Tailscale API and to create auth keys for itself and the devices it manages.

  1. In your tailnet policy file, create the ACL tags tag:k8s-operator and tag:k8s, and make tag:k8s-operator an owner of tag:k8s. If you want your Services to be exposed with tags other than the default tag:k8s, create those as well and make tag:k8s-operator an owner.

    "tagOwners": {
       "tag:k8s-operator": [],
       "tag:k8s": ["tag:k8s-operator"],
  2. Create an OAuth client in the OAuth clients page of the admin console. Create the client with Devices write scope and the tag tag:k8s-operator.


A default operator installation creates a tailscale namespace, an operator Deployment in the tailscale namespace, RBAC for the operator, and ProxyClass and Connector Custom Resource Definitions.


Tailscale Kubernetes Operator's Helm charts are available from two chart repositories.

The repository contains well-tested charts for stable Tailscale versions.

Helm charts and container images for a new stable Tailscale version are released a few days after the official release. This is done to avoid releasing image versions with potential bugs in the core Linux client or core libraries.

The repository contains charts with the very latest changes, published in between official releases.

The charts in both repositories are different versions of the same chart and you can upgrade from one to the other.

To install the latest Kubernetes Tailscale operator from in tailscale namespace:

  1. Add to your local Helm repositories:

    helm repo add tailscale
  2. Update your local Helm cache:

    helm repo update
  3. Install the operator passing the OAuth client credentials that you created earlier:

    helm upgrade \
      --install \
      tailscale-operator \
      tailscale/tailscale-operator \
      --namespace=tailscale \
      --create-namespace \
      --set-string oauth.clientId=<OAauth client ID> \
      --set-string oauth.clientSecret=<OAuth client secret> \

Static manifests with kubectl

  1. Download the Tailscale Kubernetes operator manifest file from the tailscale/tailscale repo.

  2. Edit your version of the manifest file:

    1. Find # SET CLIENT ID HERE and replace it with your OAuth client ID.
    2. Find # SET CLIENT SECRET HERE and replace it with your OAuth client secret. The OAuth client secret is case-sensitive.

    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
  3. Apply the edited file to your Kubernetes cluster:

    kubectl apply -f manifest.yaml


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.

Supported versions

Operator and proxies

Tailscale recommends that you use the same version for the operator and the proxies, because majority of our tests run against the same versions.

The operator supports proxies running a Tailscale version up to four minor versions earlier than the operator's version. The operator does not support proxies running a Tailscale version later than the operator's version.

Kubernetes versions

The earliest supported version of Kubernetes is v1.23.0.

CNI compatibility

The operator creates proxies that configure custom routing and forwarding rules in each proxy Pod's network namespace only. Because the proxying is implemented in the proxy Pod's namespace, the routing and firewall configuration on the Node (for example, using iptables, eBPF, or any other mechanism) doesn't affect the proxies. This means that the proxies work with most CNI configurations out of the box.

Cilium in kube-proxy replacement mode

You must enable bypassing socket load balancer in Pods' namespaces if you run Cilium in kube-proxy replacement mode and want to do one or more of the following:

This is needed because when Cilium runs in kube-proxy replacement mode with the socket load balancing in Pods' namespaces enabled, connections from Pods to ClusterIPs go over a TCP socket (instead of going out via Pods' veth devices) and thus bypasses Tailscale firewall rules that are attached to netfilter hooks.


Learn how to customize the operator and resources it manages.


Learn how to troubleshoot the operator and resources it manages.


  • There are no dashboards or metrics. We are interested to hear what metrics you would find useful — do reach out.
  • The container images, charts or manifests are not signed. We are working on this.
  • The static manifests are currently only available from tailscale/tailscale codebase. We are working to improve this flow.



In the context of this document, a proxy is the Tailscale node deployed for each user-configured component that the operator manages (such as a Tailscale Ingress or a Connector). The proxy is deployed as a StatefulSet in the operator's namespace (defaults to tailscale). The StatefulSets name is prefixed by a portion of the configured component's name.

If you need to reliably refer to the proxy's StatefulSet, you can use label selectors. For example, to find StatefulSet for a Tailscale Ingress resource named ts-ingress in prod namespace , you can run:

$ kubectl get statefulset \
  --namespace tailscale \

The label is set to svc for a Service and to connector for a Connector. The labels are also propagated to the Pod.