Skip to main content
Tailscale cluster egress lets a sandbox on your own CoreWeave Kubernetes Service (CKS) cluster connect to a device on your tailnet. Examples include an internal API, a database in your corporate network, and a model server on a workstation. The Tailscale Kubernetes operator publishes the tailnet device as a Kubernetes Service. A sandbox egress rule grants the sandbox access to the proxy behind that Service. This page is for administrators who run a managed sandbox runner on a CKS cluster. The example uses standalone egress, with the operator installed in the tailscale namespace. Two platform behaviors shape the configuration:
  • Exposing an in-cluster Service through the Tailscale operator lets tailnet devices connect to it. Outbound connections from a Pod to a tailnet device require Tailscale’s cluster egress feature.
  • Sandbox egress rules are allow-only over a default-deny baseline, and EgressRule(any=True) excludes cluster-internal addresses. An in-cluster destination such as a Tailscale proxy is reachable only through a selector or tenant rule.

Prerequisites

  • A CKS cluster with a managed sandbox runner whose installStatus is READY. See Use your own compute.
  • The Tailscale Kubernetes Operator installed on that cluster, with your tailnet policy file configured for CKS. See Deploy the Tailscale Kubernetes Operator.
  • The MagicDNS name of the tailnet device you want to reach, such as db-host.[TAILNET-NAME].ts.net, and the port your service listens on.
  • A runner policy that permits this selector egress rule. An any entitlement never covers selectors, so a policy with a nonempty allowed_egress must carry a selector entitlement that matches in form: it must also set namespace_labels, and its labels must be a subset of the ones the sandbox declares, and its port filter must cover TCP port 8080. See SelectorBlock.
  • The cwsandbox Python SDK configured with credentials for CKS placement, and a sandbox image with curl and getent installed.
  • kubectl access to create or update Services in the default namespace and list Pods in the operator’s namespace.
  • A tailnet policy that allows the egress proxy to connect to the target device and application port.

Create a Tailscale egress Service

Create an ExternalName Service annotated with the tailnet device’s MagicDNS name. The operator creates a proxy Pod and a headless Service in its own namespace, then points the ExternalName Service at that headless Service. The examples use tailscale, as in the linked installation guide; if you installed the operator in another namespace, update the commands and namespace_labels below. Replace [TAILNET-FQDN] with the device’s MagicDNS name. This example creates the Service in default and uses its fully qualified DNS name so sandboxes can connect from other namespaces. It assumes an HTTP service on port 8080 with a /health endpoint; adjust the port and path for your service.
tailnet-egress.yaml
Sandboxes connect to internal-api.default.svc.cluster.local:8080. The short name internal-api:8080 works only from the Service’s namespace. If your cluster uses a DNS suffix other than cluster.local, replace that suffix in the examples. Confirm that the operator created the proxy Pod:
Wait until the proxy is ready. Example output (the generated Pod name varies):

Grant the sandbox egress to the proxy

Select the proxy Pod by label in an EgressRule. The rule requires both label sets:
  • pod_labels identifies the proxy by the Service it fronts, through the operator’s tailscale.com/parent-resource and tailscale.com/parent-resource-ns labels. Include the namespace label so the rule doesn’t also match a proxy for a same-named Service in another namespace.
  • namespace_labels selects the tailscale namespace. Without it, the rule applies only to the sandbox’s own namespace and doesn’t reach a proxy in another namespace.
Set ports to the same port the service listens on. Replace [RUNNER-ID] with the ID of the runner on the cluster where you created the Service. Without runner_ids, CKS placement can use any eligible runner in your organization, including one on a cluster without the proxy.
These selectors and ports are for standalone egress. An egress ProxyGroup uses shared proxy Pods and remaps ports, so this rule isn’t a complete configuration for that mode. See Tailscale’s high-availability egress guide. Cluster DNS stays reachable unless the runner policy denies DNS egress on the dns_egress constraint, so the sandbox resolves the Service name without an additional rule.

Verify the connection

The example prints the HTTP response headers and body, plus any curl errors. For a health endpoint that returns status 200, expect a status line such as HTTP/1.1 200 OK followed by the service’s health response. An HTTP error such as 401 or 404 shows that an HTTP server responded; check application authentication or the requested path. A timeout or connection error can occur between the sandbox and proxy, between the proxy and tailnet device, or at the application. To check DNS and the HTTP exchange separately, run this diagnostic example with your runner ID:
A successful DNS lookup prints at least one address. In the curl output, look for a connection to the proxy address and an HTTP response status. DNS success alone doesn’t confirm that the proxy can reach the target.

Troubleshoot

Last modified on October 28, 2026