Private Access Without a Public Load Balancer
Internal tools, admin APIs, staging backends: most teams run a few services that should never sit behind a public endpoint, yet engineers still need to reach them from their laptops. The classic answers are a bastion host, a VPN appliance, or an IP allowlist on a public load balancer. All three add infrastructure to maintain and tend to open more of the network than anyone intended.
Tailscale handles the connectivity. On Kubernetes, the hard part is deciding what your tailnet can reach once it is connected to the cluster.
Two choices decide whether the setup stays safe. The first is using a subnet router when one service was enough, which puts every IP in the advertised range on the tailnet, pods and databases included. The second is keeping Tailscale's default allow-all policy, which lets every device on the tailnet reach every proxy the operator creates.
Pick the Pattern First
The Tailscale Kubernetes Operator supports three ways to connect a cluster to a tailnet. Choose one before installing anything, then design the access policy around it.
- Expose one service. An annotation on the service's Kubernetes
Servicecreates a dedicated tailnet device. Only that service is reachable, and only on its declared ports. This is the right default. - Subnet router. A
Connectoradvertises a whole CIDR. Every pod, every RDS instance, and every peered VPC in that range becomes reachable. Use it only for people who need network-level access. - Egress. The cluster calls a machine that lives only on the tailnet. Nothing comes in.

How It Fits Into Qovery
There is no custom integration. The operator runs as a regular Qovery Helm service, and you expose services with features you already use:
- Helm service: the official
tailscale-operatorchart runs in its own environment, one per cluster, with a pinned version, so every upgrade is a reviewed change. - Secret variables: the Tailscale OAuth credentials are stored as Qovery secrets and injected into the chart values at deploy time, so they never appear in the override file.
- Annotation groups: exposing a service is a matter of attaching an annotation group to it. Detach the group and redeploy, and the tailnet device disappears.
- Tailscale grants: a short policy restricts each exposed service to the group that needs it, on the ports it needs.
At the end, one Qovery application is reachable at a stable tailnet hostname, only on its declared ports, and only by the team you choose. The rest of the VPC stays off the tailnet.
Tested End to End
I built this setup on a Qovery-managed EKS cluster, hit the real failure modes (OAuth scopes, tag ownership, the default allow-all policy), and documented the fixes. The full walkthrough covers the tailnet preparation, the Helm service configuration, the annotation groups, per-service tags, the optional subnet router and egress patterns, and a troubleshooting table for the errors you are most likely to see.
Follow the Step-by-Step Tutorial
The full tutorial is in the Qovery documentation:




