{"slug":"access-the-kubernetes-control-plane-using-an-api-server-proxy","title":"Access the Kubernetes control plane using an API server proxy","tags":["tailscale","access-control","containers","api"],"agent_summary":"Last validated: Jan 5, 2026","trigger_phrases":[],"runnable":false,"markdown":"\r\n# Access the Kubernetes control plane using an API server proxy\r\n\r\nLast validated: Jan 5, 2026\r\n\r\nAccessing the Kubernetes control plane using the API server proxyis currently [in beta](https://tailscale.com/docs/reference/tailscale-release-stages#beta).\r\n\r\nYou can use the Tailscale Kubernetes operator to expose and access the Kubernetes control plane (kube-apiserver) over Tailscale.\r\n\r\nYou can also record kubectl exec, attach, and debug sessions that are executed via the proxy by [creating and configuring a Recorder](https://tailscale.com/docs/features/kubernetes-operator/how-to/session-recording).\r\n\r\nThe Tailscale API server proxy can run in one of two modes:\r\n\r\n- Auth mode: In auth mode, requests from the tailnet proxied over to the Kubernetes API server are additionally [impersonated](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) using the sender's tailnet identity. Kubernetes RBAC can then be used to configure granular API server permissions for individual tailnet identities or groups.\r\n\r\n- `noauth` mode: In `noauth` mode, requests from the tailnet will be proxied over to the Kubernetes API server but not authenticated. This mechanism can be combined with another authentication/authorization mechanism, such as an authenticating proxy provided by an external IdP or a cloud provider.\r\n\r\n\r\nAdditionally, the Tailscale API server proxy can be deployed in two different ways:\r\n\r\n- As an in-process proxy running within the operator itself. This deployment mode is the easiest to get started with but is limited to a single replica. Any access control policies should use the operator's tags as the destination.\r\n\r\n- As a high availability set of proxies managed by a [`ProxyGroup` of type `kube-apiserver`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability). Any access control policies should use the `ProxyGroup`'s tags as the destination. This deployment mode advertises the same URL from multiple replicas using a new Tailscale feature, Tailscale Services, currently in beta.\r\n\r\n\r\n## [Prerequisites](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#prerequisites)\r\n\r\n- [Set up the Kubernetes Operator](https://tailscale.com/docs/features/kubernetes-operator#setup).\r\n\r\n- [Enable HTTPS](https://tailscale.com/docs/how-to/set-up-https-certificates#configure-https) for your tailnet.\r\n\r\n- Ensure that your [access control policies](https://tailscale.com/docs/features/access-control/acls) allow devices and users to access the API server proxy devices on port 443 over TCP. If you install the API server proxy using helm, this device will be an in-process proxy run on the operator itself. If you install the API server proxy using a `ProxyGroup` resource, this will be devices with the ProxyGroup's tags. For example, if you use the in-process proxy and your operator uses `tag:k8s-operator`, allow access for all tailnet devices tagged with `tag:k8s-readers` using a policy like this:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n\"grants\": [\\\r\n    {\\\r\n      \"src\": [\"tag:k8s-readers\"],\\\r\n      \"dst\": [\"tag:k8s-operator\"],\\\r\n      \"ip\": [\"tcp:443\"]\\\r\n    }\\\r\n]\r\n```\r\n\r\n\r\n\r\n\r\n\r\nYou can use the [visual policy editor](https://tailscale.com/docs/features/visual-editor) to manage your tailnet policy file. Refer to the [visual editor reference](https://tailscale.com/docs/reference/visual-editor) for guidance on using the visual editor.\r\n\r\n\r\nAccess to the proxy over the tailnet does not grant tailnet users any default permissions to access Kubernetes API server resources. Tailnet users will only be able to access API server resources that they have been explicitly authorized to access by [Kubernetes RBAC](https://kubernetes.io/docs/reference/access-authn-authz/rbac).\r\n\r\n## [Configuring the API server proxy in auth mode](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#configuring-the-api-server-proxy-in-auth-mode)\r\n\r\n### [Installation](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#installation)\r\n\r\n#### [Helm](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#helm)\r\n\r\nIf you are installing the Tailscale Kubernetes Operator with [Helm](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm), you can install the proxy in auth mode by passing `--set-string apiServerProxyConfig.mode=true` flag to the install command:\r\n\r\n```shell\r\nhelm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=<OAauthClientId> \\\r\n  --set-string oauth.clientSecret=<OAuthClientSecret> \\\r\n  --set-string apiServerProxyConfig.mode=\"true\" \\\r\n  --wait\r\n```\r\n\r\nIf you want to deploy a [highly available API server proxy](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability) using a `ProxyGroup`, you can reduce the permissions assigned to the operator's service account by instead using `--set-string apiServerProxyConfig.allowImpersonation=true`:\r\n\r\n```shell\r\nhelm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=<OAauthClientId> \\\r\n  --set-string oauth.clientSecret=<OAuthClientSecret> \\\r\n  --set-string apiServerProxyConfig.allowImpersonation=\"true\" \\\r\n  --wait\r\n```\r\n\r\nRefer to [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig) to configure `kubectl` to use the API server proxy.\r\n\r\n#### [Static manifests with `kubectl`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#static-manifests-with-kubectl)\r\n\r\nIf you are installing the Tailscale Kubernetes Operator [using static manifests](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl):\r\n\r\n1. (Optional) If you are using the operator's in-process API server proxy, set the environment variable `APISERVER_PROXY=true` in the deployment manifest.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\nname: APISERVER_PROXY\r\nvalue: \"true\"\r\n```\r\n\r\n2. Download and apply [RBAC for the API server proxy](https://github.com/tailscale/tailscale/blob/main/cmd/k8s-operator/deploy/manifests/authproxy-rbac.yaml) from the [`tailscale/tailscale`](https://github.com/tailscale/tailscale) repository.\r\n\r\n\r\nRefer to [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig) to configure `kubectl` to use the API server proxy.\r\n\r\n### [Configuring authentication and authorization](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#configuring-authentication-and-authorization)\r\n\r\nAPI server proxy in auth mode [impersonates](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation) requests from the tailnet to the Kubernetes API server. You can then use Kubernetes RBAC to control what API server resources tailnet identities can access.\r\n\r\nThe impersonation is applied as follows:\r\n\r\n- If the user who sends a request to the Kubernetes API server using the proxy is in a tailnet user group for which [API server proxy grants](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#impersonating-kubernetes-groups-with-grants) have been configured for that proxy instance, the request will be impersonated as a Kubernetes group specified in the grant. It will also be impersonated as a Kubernetes user whose name matches the tailnet user's name.\r\n- If grants are not used and the node from which the request is sent is [tagged](https://tailscale.com/docs/features/tags), the request will be impersonated as if from a Kubernetes group whose name matches the tag.\r\n- If grants are not used and the node from which the request is sent is not tagged, the request will be impersonated as a Kubernetes user whose name matches the sender's tailnet username.\r\n\r\n### [Impersonating Kubernetes groups with grants](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#impersonating-kubernetes-groups-with-grants)\r\n\r\nYou can use [grants](https://tailscale.com/docs/features/access-control/grants) to configure the Kubernetes API server resources Tailscale user groups can access.\r\n\r\nFor example, to give a tailnet user group `group:prod` cluster admin access and give the tailnet user group `group:k8s-readers` read permission for most Kubernetes resources:\r\n\r\n1. Update your [grants](https://tailscale.com/docs/features/access-control/grants):\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n{\r\n     \"grants\": [\\\r\n       {\\\r\n         \"src\": [\"group:prod\"],\\\r\n         \"dst\": [\"tag:k8s-operator\"],\\\r\n         \"app\": {\\\r\n           \"tailscale.com/cap/kubernetes\": [{\\\r\n             \"impersonate\": {\\\r\n               \"groups\": [\"system:masters\"],\\\r\n             },\\\r\n           }],\\\r\n         },\\\r\n       },\\\r\n       {\\\r\n         \"src\": [\"group:k8s-readers\"],\\\r\n         \"dst\": [\"tag:k8s-operator\"],\\\r\n         \"app\": {\\\r\n           \"tailscale.com/cap/kubernetes\": [{\\\r\n             \"impersonate\": {\\\r\n               \"groups\": [\"tailnet-readers\"],\\\r\n             },\\\r\n           }],\\\r\n         },\\\r\n       }\\\r\n     ],\r\n}\r\n```\r\n\r\n\r\n   - `grants.src` is the [Tailscale user group](https://tailscale.com/docs/reference/syntax/policy-file#groups) the grant applies to.\r\n   - `grants.dst` must be [the tag of the Tailscale Kubernetes Operator](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#prerequisites).\r\n   - `system:masters` is a Kubernetes group with [default RBAC bindings](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) in all clusters. Kubernetes creates a default `ClusterRole``cluster-admin` that lets you perform all actions against all Kubernetes API server resources and a `ClusterRoleBinding``cluster-admin` that binds the `cluster-admin``ClusterRole` to `system:masters` group.\r\n   - `tailnet-readers` is a Kubernetes group that you will bind the [default Kubernetes `view``ClusterRole`](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) to in a following step. (Note that Kubernetes group names do not refer to existing identities in Kubernetes- they do not need to be pre-created to start using them in `(Cluster)RoleBinding`s).\r\n2. Bind `tailnet-readers` to the `view``ClusterRole`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\nkubectl create clusterrolebinding tailnet-readers-view --group=tailnet-readers --clusterrole=view\r\n```\r\n\r\n\r\n#### [Impersonating Kubernetes groups with tagged tailnet nodes](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#impersonating-kubernetes-groups-with-tagged-tailnet-nodes)\r\n\r\nIf the request is sent from a [tagged device](https://tailscale.com/docs/features/tags), it will be impersonated as a [Kubernetes group](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-subjects) whose name matches the tag. For example, a request from a tailnet device tagged with `tag:k8s-readers` will be authenticated by the API server as from a Kubernetes group `tag:k8s-readers`.\r\n\r\nYou can create Kubernetes `(Cluster)Roles` and `(Cluster)RoleBindings` to configure the permissions the group should have or bind an existing `(Cluster)Role` to the group.\r\n\r\nFor example, to grant devices tagged with `tag:k8s-readers` read-only access to most Kubernetes resources, you can bind Kubernetes group `tag:k8s-users` to the [default Kubernetes `view` ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles):\r\n\r\n```shell\r\nkubectl create clusterrolebinding tailnet-readers --group=\"tag:k8s-readers\" --clusterrole=view\r\n```\r\n\r\n#### [Impersonating Kubernetes users](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#impersonating-kubernetes-users)\r\n\r\nIf the request is _not_ sent from a [tagged device](https://tailscale.com/docs/features/tags), it will be impersonated as a Kubernetes user named the same as the sender's tailnet user.\r\n\r\nYou can then create Kubernetes `(Cluster)Roles` and `(Cluster)RoleBindings` to configure the permissions the user should have or bind an existing `(Cluster)Role` to the user.\r\n\r\nFor example, to allow the tailnet user `alice@tailscale.com` read-only access to most Kubernetes resources, bind Kubernetes user `alice@tailscale.com` to the [default Kubernetes `view` ClusterRole](https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles) like so:\r\n\r\n```shell\r\nkubectl create clusterrolebinding alice-view --user=\"alice@tailscale.com\"  --clusterrole=view\r\n```\r\n\r\n## [Configuring API server proxy in `noauth` mode](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#configuring-api-server-proxy-in-noauth-mode)\r\n\r\nThe `noauth` mode of the API server proxy is useful if you want to use Tailscale to provide access to the Kubernetes API server over the tailnet, but want to keep using your existing authentication and authorization mechanism.\r\n\r\n### [Installation](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#installation-1)\r\n\r\n#### [Helm](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#helm-1)\r\n\r\nIf you are installing the Tailscale Kubernetes Operator with [Helm](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm), you can install the proxy in auth mode by passing `--set-string apiServerProxyConfig.mode=noauth` flag to the install command. You can skip setting `apiServerProxyConfig` if you are going to configure the API server proxy using a [`kube-apiserver``ProxyGroup`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability).\r\n\r\n```shell\r\nhelm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=<OAauth client ID> \\\r\n  --set-string oauth.clientSecret=<OAuth client secret> \\\r\n  --set-string apiServerProxyConfig.mode=\"noauth\" \\\r\n  --wait\r\n```\r\n\r\nRefer to [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig) to configure `kubectl` to use the API server proxy.\r\n\r\n#### [Static manifests with `kubectl`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#static-manifests-with-kubectl-1)\r\n\r\nIf you are installing the Tailscale Kubernetes Operator [using static manifests](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl):\r\n\r\n1. (Optional) If you are using the operator's in-process API server proxy, set the environment variable `APISERVER_PROXY=noauth` in the Tailscale Kubernetes Operator deployment manifest.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\nname: APISERVER_PROXY\r\nvalue: \"noauth\"\r\n```\r\n\r\n\r\nRefer to [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig) to configure `kubectl` to use the API server proxy.\r\n\r\n### [Authentication and authorization](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#authentication-and-authorization)\r\n\r\nWhen run in `noauth` mode, the API server proxy exposes the Kubernetes API server to the tailnet but does not provide authentication. You can use the proxy endpoint (`<TailscaleOperatorHostname>:443`) instead of the Kubernetes API server address and set up authentication and authorization over that using any other mechanism (such as another [authenticating proxy](https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy) provided by your managed Kubernetes provider or IdP or similar).\r\n\r\n## [Configuring a high availability API server proxy](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#configuring-a-high-availability-api-server-proxy)\r\n\r\n1. Ensure that your [access control policies](https://tailscale.com/docs/features/access-control/acls) allow devices and users to access the API server proxy devices on both port `80` and `443` over TCP. For example, if you use default tag `tag:k8s` for your `ProxyGroup`, allow access for all tailnet devices tagged with `tag:k8s-readers` using a policy like this:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n\"grants\": [\\\r\n     {\\\r\n       \"src\": [\"tag:k8s-readers\"],\\\r\n       \"dst\": [\"tag:k8s\"],\\\r\n       \"ip\": [\"tcp:80\", \"tcp:443\"]\\\r\n     }\\\r\n]\r\n```\r\n\r\n\r\n\r\n\r\n\r\nYou can use the [visual policy editor](https://tailscale.com/docs/features/visual-editor) to manage your tailnet policy file. Refer to the [visual editor reference](https://tailscale.com/docs/reference/visual-editor) for guidance on using the visual editor.\r\n\r\n2. Update [`autoApprovers`](https://tailscale.com/docs/reference/syntax/policy-file#autoapprovers) in your tailnet policy file to let the `ProxyGroup` proxies advertise Tailscale Services with the tag `tag:k8s`:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```json\r\n     \"autoApprovers\": {\r\n       \"services\": {\r\n         \"tag:k8s\": [\"tag:k8s\"],\r\n       },\r\n     }\r\n```\r\n\r\n3. Apply the following `ProxyGroup` resource to create a set of Tailscale devices that will act as API server proxies. Set `spec.apiServerProxyConfig.mode` to `noauth` if you want it to run in `noauth` mode.\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```yaml\r\napiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n     name: my-cluster\r\nspec:\r\n     type: kube-apiserver\r\n     replicas: 2\r\n     tags: [\"tag:k8s\"]\r\n     kubeAPIServer:\r\n       mode: auth\r\n```\r\n\r\n4. (Optional) Wait for the ProxyGroup to become ready:\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n```shell\r\nkubectl wait proxygroup my-cluster --for=condition=ProxyGroupReady=true\r\n```\r\n\r\n5. Ensure your [client accepts routes](https://tailscale.com/docs/features/subnet-routers#use-your-subnet-routes-from-other-devices). Clients other than Linux accept routes by default.\r\n\r\n\r\nRefer to [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig) to configure `kubectl` to use the API server proxy.\r\n\r\n## [Configuring `kubeconfig`](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#configuring-kubeconfig)\r\n\r\nYou can run the [`tailscale configure kubeconfig`](https://tailscale.com/docs/reference/tailscale-cli#configure) command to configure `kubectl` for authentication using the Tailscale Kubernetes API server proxy.\r\n\r\nBy default, the operator's hostname is `tailscale-operator`:\r\n\r\n```shell\r\ntailscale configure kubeconfig tailscale-operator\r\n```\r\n\r\nOr if you're using a `kube-apiserver``ProxyGroup`, you can use the URL printed in its status field:\r\n\r\n```shell\r\nkubectl get proxygroup my-cluster\r\nNAME         STATUS            URL                                 TYPE             AGE\r\nmy-cluster   ProxyGroupReady   https://my-cluster.tailxyz.ts.net   kube-apiserver   31s\r\n```\r\n\r\n```shell\r\ntailscale configure kubeconfig https://my-cluster.tailxyz.ts.net\r\n```\r\n\r\nThe hostname defaults to the name of the `ProxyGroup`, but you can customize it using the `ProxyGroup` field `spec.kubeAPIServer.hostname`.\r\n\r\n## [Customization](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#customization)\r\n\r\n[Customize the operator and resources it manages](https://tailscale.com/docs/features/kubernetes-operator/how-to/customize).\r\n\r\n## [Troubleshooting](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#troubleshooting)\r\n\r\n[Troubleshoot the operator and resources it manages](https://tailscale.com/docs/reference/troubleshooting/containers/kubernetes-operator).\r\n\r\n## [Limitations](https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy\\#limitations)\r\n\r\n- The API server proxy runs inside the cluster. If your cluster is non-functional or unable to schedule pods, you might lose access to the API server proxy and potentially your cluster.\r\n- The API server proxy requires TLS certificates. When deployed with `ProxyGroup`, the operator will wait for certificates to be provisioned before marking the `ProxyGroup` ready. However, if you are using the operator's in-process proxy, it provisions certificates automatically on the first API call, meaning the first call might be slow or even time out.\r\n","html":"<h1>Access the Kubernetes control plane using an API server proxy</h1>\n<p>Last validated: Jan 5, 2026</p>\n<p>Accessing the Kubernetes control plane using the API server proxyis currently <a href=\"https://tailscale.com/docs/reference/tailscale-release-stages#beta\">in beta</a>.</p>\n<p>You can use the Tailscale Kubernetes operator to expose and access the Kubernetes control plane (kube-apiserver) over Tailscale.</p>\n<p>You can also record kubectl exec, attach, and debug sessions that are executed via the proxy by <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/session-recording\">creating and configuring a Recorder</a>.</p>\n<p>The Tailscale API server proxy can run in one of two modes:</p>\n<ul>\n<li>\n<p>Auth mode: In auth mode, requests from the tailnet proxied over to the Kubernetes API server are additionally <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation\">impersonated</a> using the sender's tailnet identity. Kubernetes RBAC can then be used to configure granular API server permissions for individual tailnet identities or groups.</p>\n</li>\n<li>\n<p><code>noauth</code> mode: In <code>noauth</code> mode, requests from the tailnet will be proxied over to the Kubernetes API server but not authenticated. This mechanism can be combined with another authentication/authorization mechanism, such as an authenticating proxy provided by an external IdP or a cloud provider.</p>\n</li>\n</ul>\n<p>Additionally, the Tailscale API server proxy can be deployed in two different ways:</p>\n<ul>\n<li>\n<p>As an in-process proxy running within the operator itself. This deployment mode is the easiest to get started with but is limited to a single replica. Any access control policies should use the operator's tags as the destination.</p>\n</li>\n<li>\n<p>As a high availability set of proxies managed by a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability\"><code>ProxyGroup</code> of type <code>kube-apiserver</code></a>. Any access control policies should use the <code>ProxyGroup</code>'s tags as the destination. This deployment mode advertises the same URL from multiple replicas using a new Tailscale feature, Tailscale Services, currently in beta.</p>\n</li>\n</ul>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#prerequisites\">Prerequisites</a></h2>\n<ul>\n<li>\n<p><a href=\"https://tailscale.com/docs/features/kubernetes-operator#setup\">Set up the Kubernetes Operator</a>.</p>\n</li>\n<li>\n<p><a href=\"https://tailscale.com/docs/how-to/set-up-https-certificates#configure-https\">Enable HTTPS</a> for your tailnet.</p>\n</li>\n<li>\n<p>Ensure that your <a href=\"https://tailscale.com/docs/features/access-control/acls\">access control policies</a> allow devices and users to access the API server proxy devices on port 443 over TCP. If you install the API server proxy using helm, this device will be an in-process proxy run on the operator itself. If you install the API server proxy using a <code>ProxyGroup</code> resource, this will be devices with the ProxyGroup's tags. For example, if you use the in-process proxy and your operator uses <code>tag:k8s-operator</code>, allow access for all tailnet devices tagged with <code>tag:k8s-readers</code> using a policy like this:</p>\n</li>\n</ul>\n<pre><code class=\"language-json\">\"grants\": [\\\r\n    {\\\r\n      \"src\": [\"tag:k8s-readers\"],\\\r\n      \"dst\": [\"tag:k8s-operator\"],\\\r\n      \"ip\": [\"tcp:443\"]\\\r\n    }\\\r\n]\n</code></pre>\n<p>You can use the <a href=\"https://tailscale.com/docs/features/visual-editor\">visual policy editor</a> to manage your tailnet policy file. Refer to the <a href=\"https://tailscale.com/docs/reference/visual-editor\">visual editor reference</a> for guidance on using the visual editor.</p>\n<p>Access to the proxy over the tailnet does not grant tailnet users any default permissions to access Kubernetes API server resources. Tailnet users will only be able to access API server resources that they have been explicitly authorized to access by <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac\">Kubernetes RBAC</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-the-api-server-proxy-in-auth-mode\">Configuring the API server proxy in auth mode</a></h2>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#installation\">Installation</a></h3>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm\">Helm</a></h4>\n<p>If you are installing the Tailscale Kubernetes Operator with <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm\">Helm</a>, you can install the proxy in auth mode by passing <code>--set-string apiServerProxyConfig.mode=true</code> flag to the install command:</p>\n<pre><code class=\"language-shell\">helm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=&#x3C;OAauthClientId> \\\r\n  --set-string oauth.clientSecret=&#x3C;OAuthClientSecret> \\\r\n  --set-string apiServerProxyConfig.mode=\"true\" \\\r\n  --wait\n</code></pre>\n<p>If you want to deploy a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability\">highly available API server proxy</a> using a <code>ProxyGroup</code>, you can reduce the permissions assigned to the operator's service account by instead using <code>--set-string apiServerProxyConfig.allowImpersonation=true</code>:</p>\n<pre><code class=\"language-shell\">helm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=&#x3C;OAauthClientId> \\\r\n  --set-string oauth.clientSecret=&#x3C;OAuthClientSecret> \\\r\n  --set-string apiServerProxyConfig.allowImpersonation=\"true\" \\\r\n  --wait\n</code></pre>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a> to configure <code>kubectl</code> to use the API server proxy.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl\">Static manifests with <code>kubectl</code></a></h4>\n<p>If you are installing the Tailscale Kubernetes Operator <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl\">using static manifests</a>:</p>\n<ol>\n<li>(Optional) If you are using the operator's in-process API server proxy, set the environment variable <code>APISERVER_PROXY=true</code> in the deployment manifest.</li>\n</ol>\n<pre><code class=\"language-yaml\">name: APISERVER_PROXY\r\nvalue: \"true\"\n</code></pre>\n<ol start=\"2\">\n<li>Download and apply <a href=\"https://github.com/tailscale/tailscale/blob/main/cmd/k8s-operator/deploy/manifests/authproxy-rbac.yaml\">RBAC for the API server proxy</a> from the <a href=\"https://github.com/tailscale/tailscale\"><code>tailscale/tailscale</code></a> repository.</li>\n</ol>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a> to configure <code>kubectl</code> to use the API server proxy.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-authentication-and-authorization\">Configuring authentication and authorization</a></h3>\n<p>API server proxy in auth mode <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#user-impersonation\">impersonates</a> requests from the tailnet to the Kubernetes API server. You can then use Kubernetes RBAC to control what API server resources tailnet identities can access.</p>\n<p>The impersonation is applied as follows:</p>\n<ul>\n<li>If the user who sends a request to the Kubernetes API server using the proxy is in a tailnet user group for which <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#impersonating-kubernetes-groups-with-grants\">API server proxy grants</a> have been configured for that proxy instance, the request will be impersonated as a Kubernetes group specified in the grant. It will also be impersonated as a Kubernetes user whose name matches the tailnet user's name.</li>\n<li>If grants are not used and the node from which the request is sent is <a href=\"https://tailscale.com/docs/features/tags\">tagged</a>, the request will be impersonated as if from a Kubernetes group whose name matches the tag.</li>\n<li>If grants are not used and the node from which the request is sent is not tagged, the request will be impersonated as a Kubernetes user whose name matches the sender's tailnet username.</li>\n</ul>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#impersonating-kubernetes-groups-with-grants\">Impersonating Kubernetes groups with grants</a></h3>\n<p>You can use <a href=\"https://tailscale.com/docs/features/access-control/grants\">grants</a> to configure the Kubernetes API server resources Tailscale user groups can access.</p>\n<p>For example, to give a tailnet user group <code>group:prod</code> cluster admin access and give the tailnet user group <code>group:k8s-readers</code> read permission for most Kubernetes resources:</p>\n<ol>\n<li>Update your <a href=\"https://tailscale.com/docs/features/access-control/grants\">grants</a>:</li>\n</ol>\n<pre><code class=\"language-json\">{\r\n     \"grants\": [\\\r\n       {\\\r\n         \"src\": [\"group:prod\"],\\\r\n         \"dst\": [\"tag:k8s-operator\"],\\\r\n         \"app\": {\\\r\n           \"tailscale.com/cap/kubernetes\": [{\\\r\n             \"impersonate\": {\\\r\n               \"groups\": [\"system:masters\"],\\\r\n             },\\\r\n           }],\\\r\n         },\\\r\n       },\\\r\n       {\\\r\n         \"src\": [\"group:k8s-readers\"],\\\r\n         \"dst\": [\"tag:k8s-operator\"],\\\r\n         \"app\": {\\\r\n           \"tailscale.com/cap/kubernetes\": [{\\\r\n             \"impersonate\": {\\\r\n               \"groups\": [\"tailnet-readers\"],\\\r\n             },\\\r\n           }],\\\r\n         },\\\r\n       }\\\r\n     ],\r\n}\n</code></pre>\n<ul>\n<li><code>grants.src</code> is the <a href=\"https://tailscale.com/docs/reference/syntax/policy-file#groups\">Tailscale user group</a> the grant applies to.</li>\n<li><code>grants.dst</code> must be <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#prerequisites\">the tag of the Tailscale Kubernetes Operator</a>.</li>\n<li><code>system:masters</code> is a Kubernetes group with <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles\">default RBAC bindings</a> in all clusters. Kubernetes creates a default <code>ClusterRole``cluster-admin</code> that lets you perform all actions against all Kubernetes API server resources and a <code>ClusterRoleBinding``cluster-admin</code> that binds the <code>cluster-admin``ClusterRole</code> to <code>system:masters</code> group.</li>\n<li><code>tailnet-readers</code> is a Kubernetes group that you will bind the <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles\">default Kubernetes <code>view``ClusterRole</code></a> to in a following step. (Note that Kubernetes group names do not refer to existing identities in Kubernetes- they do not need to be pre-created to start using them in <code>(Cluster)RoleBinding</code>s).</li>\n</ul>\n<ol start=\"2\">\n<li>Bind <code>tailnet-readers</code> to the <code>view``ClusterRole</code>:</li>\n</ol>\n<pre><code class=\"language-shell\">kubectl create clusterrolebinding tailnet-readers-view --group=tailnet-readers --clusterrole=view\n</code></pre>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#impersonating-kubernetes-groups-with-tagged-tailnet-nodes\">Impersonating Kubernetes groups with tagged tailnet nodes</a></h4>\n<p>If the request is sent from a <a href=\"https://tailscale.com/docs/features/tags\">tagged device</a>, it will be impersonated as a <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac/#referring-to-subjects\">Kubernetes group</a> whose name matches the tag. For example, a request from a tailnet device tagged with <code>tag:k8s-readers</code> will be authenticated by the API server as from a Kubernetes group <code>tag:k8s-readers</code>.</p>\n<p>You can create Kubernetes <code>(Cluster)Roles</code> and <code>(Cluster)RoleBindings</code> to configure the permissions the group should have or bind an existing <code>(Cluster)Role</code> to the group.</p>\n<p>For example, to grant devices tagged with <code>tag:k8s-readers</code> read-only access to most Kubernetes resources, you can bind Kubernetes group <code>tag:k8s-users</code> to the <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles\">default Kubernetes <code>view</code> ClusterRole</a>:</p>\n<pre><code class=\"language-shell\">kubectl create clusterrolebinding tailnet-readers --group=\"tag:k8s-readers\" --clusterrole=view\n</code></pre>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#impersonating-kubernetes-users\">Impersonating Kubernetes users</a></h4>\n<p>If the request is <em>not</em> sent from a <a href=\"https://tailscale.com/docs/features/tags\">tagged device</a>, it will be impersonated as a Kubernetes user named the same as the sender's tailnet user.</p>\n<p>You can then create Kubernetes <code>(Cluster)Roles</code> and <code>(Cluster)RoleBindings</code> to configure the permissions the user should have or bind an existing <code>(Cluster)Role</code> to the user.</p>\n<p>For example, to allow the tailnet user <code>alice@tailscale.com</code> read-only access to most Kubernetes resources, bind Kubernetes user <code>alice@tailscale.com</code> to the <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/rbac/#user-facing-roles\">default Kubernetes <code>view</code> ClusterRole</a> like so:</p>\n<pre><code class=\"language-shell\">kubectl create clusterrolebinding alice-view --user=\"alice@tailscale.com\"  --clusterrole=view\n</code></pre>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-api-server-proxy-in-noauth-mode\">Configuring API server proxy in <code>noauth</code> mode</a></h2>\n<p>The <code>noauth</code> mode of the API server proxy is useful if you want to use Tailscale to provide access to the Kubernetes API server over the tailnet, but want to keep using your existing authentication and authorization mechanism.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#installation-1\">Installation</a></h3>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm-1\">Helm</a></h4>\n<p>If you are installing the Tailscale Kubernetes Operator with <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#helm\">Helm</a>, you can install the proxy in auth mode by passing <code>--set-string apiServerProxyConfig.mode=noauth</code> flag to the install command. You can skip setting <code>apiServerProxyConfig</code> if you are going to configure the API server proxy using a <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#high-availability\"><code>kube-apiserver``ProxyGroup</code></a>.</p>\n<pre><code class=\"language-shell\">helm upgrade \\\r\n  --install \\\r\n  tailscale-operator \\\r\n  tailscale/tailscale-operator \\\r\n  --namespace=tailscale \\\r\n  --create-namespace \\\r\n  --set-string oauth.clientId=&#x3C;OAauth client ID> \\\r\n  --set-string oauth.clientSecret=&#x3C;OAuth client secret> \\\r\n  --set-string apiServerProxyConfig.mode=\"noauth\" \\\r\n  --wait\n</code></pre>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a> to configure <code>kubectl</code> to use the API server proxy.</p>\n<h4><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl-1\">Static manifests with <code>kubectl</code></a></h4>\n<p>If you are installing the Tailscale Kubernetes Operator <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#static-manifests-with-kubectl\">using static manifests</a>:</p>\n<ol>\n<li>(Optional) If you are using the operator's in-process API server proxy, set the environment variable <code>APISERVER_PROXY=noauth</code> in the Tailscale Kubernetes Operator deployment manifest.</li>\n</ol>\n<pre><code class=\"language-yaml\">name: APISERVER_PROXY\r\nvalue: \"noauth\"\n</code></pre>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a> to configure <code>kubectl</code> to use the API server proxy.</p>\n<h3><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#authentication-and-authorization\">Authentication and authorization</a></h3>\n<p>When run in <code>noauth</code> mode, the API server proxy exposes the Kubernetes API server to the tailnet but does not provide authentication. You can use the proxy endpoint (<code>&#x3C;TailscaleOperatorHostname>:443</code>) instead of the Kubernetes API server address and set up authentication and authorization over that using any other mechanism (such as another <a href=\"https://kubernetes.io/docs/reference/access-authn-authz/authentication/#authenticating-proxy\">authenticating proxy</a> provided by your managed Kubernetes provider or IdP or similar).</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-a-high-availability-api-server-proxy\">Configuring a high availability API server proxy</a></h2>\n<ol>\n<li>Ensure that your <a href=\"https://tailscale.com/docs/features/access-control/acls\">access control policies</a> allow devices and users to access the API server proxy devices on both port <code>80</code> and <code>443</code> over TCP. For example, if you use default tag <code>tag:k8s</code> for your <code>ProxyGroup</code>, allow access for all tailnet devices tagged with <code>tag:k8s-readers</code> using a policy like this:</li>\n</ol>\n<pre><code class=\"language-json\">\"grants\": [\\\r\n     {\\\r\n       \"src\": [\"tag:k8s-readers\"],\\\r\n       \"dst\": [\"tag:k8s\"],\\\r\n       \"ip\": [\"tcp:80\", \"tcp:443\"]\\\r\n     }\\\r\n]\n</code></pre>\n<p>You can use the <a href=\"https://tailscale.com/docs/features/visual-editor\">visual policy editor</a> to manage your tailnet policy file. Refer to the <a href=\"https://tailscale.com/docs/reference/visual-editor\">visual editor reference</a> for guidance on using the visual editor.</p>\n<ol start=\"2\">\n<li>Update <a href=\"https://tailscale.com/docs/reference/syntax/policy-file#autoapprovers\"><code>autoApprovers</code></a> in your tailnet policy file to let the <code>ProxyGroup</code> proxies advertise Tailscale Services with the tag <code>tag:k8s</code>:</li>\n</ol>\n<pre><code class=\"language-json\">     \"autoApprovers\": {\r\n       \"services\": {\r\n         \"tag:k8s\": [\"tag:k8s\"],\r\n       },\r\n     }\n</code></pre>\n<ol start=\"3\">\n<li>Apply the following <code>ProxyGroup</code> resource to create a set of Tailscale devices that will act as API server proxies. Set <code>spec.apiServerProxyConfig.mode</code> to <code>noauth</code> if you want it to run in <code>noauth</code> mode.</li>\n</ol>\n<pre><code class=\"language-yaml\">apiVersion: tailscale.com/v1alpha1\r\nkind: ProxyGroup\r\nmetadata:\r\n     name: my-cluster\r\nspec:\r\n     type: kube-apiserver\r\n     replicas: 2\r\n     tags: [\"tag:k8s\"]\r\n     kubeAPIServer:\r\n       mode: auth\n</code></pre>\n<ol start=\"4\">\n<li>(Optional) Wait for the ProxyGroup to become ready:</li>\n</ol>\n<pre><code class=\"language-shell\">kubectl wait proxygroup my-cluster --for=condition=ProxyGroupReady=true\n</code></pre>\n<ol start=\"5\">\n<li>Ensure your <a href=\"https://tailscale.com/docs/features/subnet-routers#use-your-subnet-routes-from-other-devices\">client accepts routes</a>. Clients other than Linux accept routes by default.</li>\n</ol>\n<p>Refer to <a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a> to configure <code>kubectl</code> to use the API server proxy.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#configuring-kubeconfig\">Configuring <code>kubeconfig</code></a></h2>\n<p>You can run the <a href=\"https://tailscale.com/docs/reference/tailscale-cli#configure\"><code>tailscale configure kubeconfig</code></a> command to configure <code>kubectl</code> for authentication using the Tailscale Kubernetes API server proxy.</p>\n<p>By default, the operator's hostname is <code>tailscale-operator</code>:</p>\n<pre><code class=\"language-shell\">tailscale configure kubeconfig tailscale-operator\n</code></pre>\n<p>Or if you're using a <code>kube-apiserver``ProxyGroup</code>, you can use the URL printed in its status field:</p>\n<pre><code class=\"language-shell\">kubectl get proxygroup my-cluster\r\nNAME         STATUS            URL                                 TYPE             AGE\r\nmy-cluster   ProxyGroupReady   https://my-cluster.tailxyz.ts.net   kube-apiserver   31s\n</code></pre>\n<pre><code class=\"language-shell\">tailscale configure kubeconfig https://my-cluster.tailxyz.ts.net\n</code></pre>\n<p>The hostname defaults to the name of the <code>ProxyGroup</code>, but you can customize it using the <code>ProxyGroup</code> field <code>spec.kubeAPIServer.hostname</code>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#customization\">Customization</a></h2>\n<p><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/customize\">Customize the operator and resources it manages</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#troubleshooting\">Troubleshooting</a></h2>\n<p><a href=\"https://tailscale.com/docs/reference/troubleshooting/containers/kubernetes-operator\">Troubleshoot the operator and resources it manages</a>.</p>\n<h2><a href=\"https://tailscale.com/docs/features/kubernetes-operator/how-to/api-server-proxy#limitations\">Limitations</a></h2>\n<ul>\n<li>The API server proxy runs inside the cluster. If your cluster is non-functional or unable to schedule pods, you might lose access to the API server proxy and potentially your cluster.</li>\n<li>The API server proxy requires TLS certificates. When deployed with <code>ProxyGroup</code>, the operator will wait for certificates to be provisioned before marking the <code>ProxyGroup</code> ready. However, if you are using the operator's in-process proxy, it provisions certificates automatically on the first API call, meaning the first call might be slow or even time out.</li>\n</ul>\n"}