Exposing Kubernetes Services with Tailscale

Recently I ran into a problem. I have a local cluster at home and one in the cloud, and I wanted to talk from the one cluster to another, potentially exposing the service through normal Kubernetes means, so that my Ingress Controller works as with services directly deployed on the external cluster.

Setup

To solve this problem, it took a deeper dive into the tailscale-operator. Installing it and using the magic `expose` annotation was already half of the problem solved. 

service:
type: ClusterIP
port: 3001
annotations: {
tailscale.com/expose: "true"
}

This simple annotation to a service exposes it directly to the Tailscale subnet. But how do I connect now from my external cluster to there? For this, we again create a service like this:

kind: Service
metadata:
annotations:
tailscale.com/tailnet-fqdn: test.tailscale-subnet.net
name: test-svc
spec:
externalName: placeholder # any value - will be overwritten by operator
type: ExternalName

We just need to set the correct Tailnet fully qualified domain name, and it already started working. Going on from there, a normal IngressRoute (since I am using Traefik as my controller) can be used to expose the service to the public net.

apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: test-route
namespace: default
spec:
entryPoints:
- websecure
routes:
- kind: Rule
match: Host(`test.domain.dev`)
priority: 10
services:
- name: test-svc
port: 3001
tls:
certResolver: cert-resolver

Thanks to the recent advancement with the operator, this was a breeze to set up. With this setup I can use my own Ingress Controller and do not need to rely on funnel.

Resources/Links

https://tailscale.com/kb/1236/kubernetes-operator

https://tailscale.com/kb/1438/kubernetes-operator-cluster-egress

https://tailscale.com/kb/1440/kubernetes-operator-cloud-services