Sharing Services Across Tailnets (Day 24)
Using Tailscale's Kubernetes operator to share specific services across tailnets without inviting users directly to the network, while maintaining DNS.
So I needed to share some services with friends outside my tailnet, but:
- Didn't want to add users directly to my tailnet
- Preferred not to add public records to Cloudflare (keep using my self-hosted DNS)
The Setup
The current infrastructure setup includes:
- Traefik as the root reverse proxy in Kubernetes
- A LoadBalancer service (traefik's) using a private, non-tailscale-routable IP
- Self-hosted DNS server
The Solution
After doing some research and trials, the approach I went with was to expose the Traefik LoadBalancer service directly to Tailscale using their Kubernetes operator.
And tailscale does include a blog post on how to do this, I recommend checking it out.
1. Installing the Operator
Important: Create an OAuth client in the Tailscale console with Devices Core
and Auth Keys
write scopes first, (see the full post here).
Install the Tailscale operator using Helm:
- Add
https://pkgs.tailscale.com/helmcharts
to your local Helm repositories:
helm repo add tailscale https://pkgs.tailscale.com/helmcharts
- Update your local Helm cache:
helm repo update
- Install the operator passing the OAuth client credentials:
helm upgrade \
--install \
tailscale-operator \
tailscale/tailscale-operator \
--namespace=tailscale \
--create-namespace \
--set-string oauth.clientId="<client_id>" \
--set-string oauth.clientSecret="<client_secret>" \
--wait
Can be added to be part of helmfile template or argo deployment
2. Exposing the Service
With the operator running, exposing a service is as simple as adding an annotation:
annotations:
tailscale.com/expose: "true"
3. Sharing Access
From the Tailscale console:
- Share both the Traefik node and DNS server
- Users can then set their Tailscale DNS to use the shared DNS server
- For more granular control, users can use Tailscale's split DNS to route only specific domains
4. ACL Configuration
One useful thing is to set up ACLs to restrict what autogroup:shared
and specific tags
(the operator is a tagged device) can access.
This ensures users only have access to the services you explicitly want to share.
So
The benefits are essentially:
- Users don't need direct access to your tailnet
- DNS resolution works seamlessly (I deployed a new separate DNS server with a limited amount of records just for tailnet shares)
- No need for public DNS records
- Fine-grained access control through Tailscale ACLs
- Services remain secure behind Tailscale's encryption