Why I want to use Tailscale

Tailscale is a VPN service that makes it easy to create secure networks and connections between devices. The main reason I want to use Tailscale is that I need a secure and private way to access services that should not be publicly accessible. Tailscale allows me to create a virtual private network (VPN) where my devices and services can communicate securely over the internet, without exposing them to the public.

How to create your own Tailscale account with OpenId Connect (OIDC)?

This use case has already been described in my previous blog post How to set up a Tailscale account with OIDC?.

How to deploy Tailscale Operator in Kubernetes?

I decided to deploy the Tailscale Operator which manages the Tailscale Custom Resource Definitions (CRDs) in my Kubernetes cluster. For the deployment, I used the Helm chart provided by Tailscale. However, I created it as a rainbow chart to include my custom values like syncing the credentials from my 1Password vault. Here is an example of my values.yaml file:

Chart.yaml

1
2
3
4
5
6
7
8
9
apiVersion: v2
name: tailscale
version: 1.0.0

dependencies:
  - name: tailscale-operator
    version: 1.92.5
    repository: https://pkgs.tailscale.com/helmcharts
    alias: tso

values.yaml

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
tailscaleOperator:
  oauth:
    onePasswordItemPath: "vaults/<my-vault-uuid>/items/<my-item-uuid>"
    restartOnChange: true
tso:
  operatorConfig:
    image:
      repository: ghcr.io/tailscale/k8s-operator
      # tag: "1.92.5" # will be set by the dependency
      pullPolicy: IfNotPresent
    resources:
      limits:
        cpu: 100m
        memory: 128Mi
      requests:
        cpu: 50m
        memory: 64Mi

Update your access control settings in Tailscale

To allow the Tailscale Operator to join your Tailscale network, you need to update your access control settings in Tailscale. Navigate to the Tailscale Admin Console - Tags section. Add a new tag called tag:k8s-operator and allow devices with this tag to join your network.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
{
  ...
  "tagOwners": {
    "tag:k8s-operator": [],
    "tag:k8s": [
      "tag:k8s-operator"
    ]
  },
  ...
}

How to get the OAuth credentials?

Open Tailscale and navigate to the “Settings” page. Under the “Trust credentials” section, create new credentials. Choose “OAuth” as the type and enter “Kubernetes Operator” as the description.

As you can see, I set the onePasswordItemPath to sync the OAuth credentials from my 1Password vault. This way, I can securely manage my Tailscale OAuth credentials without hardcoding them in the Helm values. Therefore, I want that the operator reads the credentials from a secret which is synced from 1Password. My secret looks like this:

Consider that the secret must be called operator-oauth and must be created in the same namespace where the Tailscale. Also, the keys must be named client_id and client_secret. Read more

1
2
3
4
5
6
7
8
9
apiVersion: v1
data:
  client_id: <base-64-encoded-client-id>
  client_secret: <base-64-encoded-client-secret>
kind: Secret
metadata:
  name: operator-oauth
  namespace: tailscale
type: Opaque

Granting additional permissions to the Tailscale Operator

One small note, you need to give the Tailscale operator a bit more permissions to create the necessary resources. Therefore, I also added a namespace resource in my templates folder of the rainbow chart:

I use argo-cd hooks to ensure that the namespace is created before any other resources are applied. If you are using helm, you can use helm hooks instead.

1
2
3
4
5
6
7
8
apiVersion: v1
kind: Namespace
metadata:
  name: tailscale
  annotations:
    argocd.argoproj.io/hook: PreSync # ensures the namespace is created before other resources are applied
  labels:
    pod-security.kubernetes.io/enforce: privileged # adds the privileged policy to the namespace

After creating the rainbow chart, I deployed it to my Kubernetes cluster using Argo CD.

How to access Kubernetes applications through Tailscale?

To access Kubernetes applications through Tailscale, I used the Tailscale Ingress Controller. This controller allows me to expose my Kubernetes services to the Tailscale network securely. Here is an example of how I configured the Ingress Controller:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  defaultBackend:
    service:
      name: my-service
      port:
        number: 8000
  ingressClassName: tailscale # ensures that the Tailscale Ingress Controller handles this ingress
  rules:
    - host: myservice.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 8000
  tls:
    - hosts:
        - myservice.example.com
      secretName: my-service-tls

Accessing the application through Tailscale

To access my Kubernetes application through Tailscale, I first need to ensure that my Tailscale client is running on my client. Then, I have to create a CNAME DNS record that points to the Tailscale IP address of my Kubernetes cluster. This way, when I access myservice.example.com, the request is routed through Tailscale to my Kubernetes cluster. Get the Tailscale DNS name of your Kubernetes cluster from the Tailscale Admin Console under Machines. Open the entry for your service and search for Full domain. Copy the value and create the CNAME record in your DNS provider:

1
2
3
4
CNAME myservice.example.com -> <tailscale-dns-name-of-k8s-cluster>

# Example:
CNAME myservice.example.com -> my-service.tail12345.ts.net

Consider that DNS propagation might take some time depending on your DNS provider. You can use tools like dig to check if the DNS record has propagated:

1
dig +short myservice.example.com

And that’s it! Now I can access my Kubernetes applications securely through Tailscale.

Conclusion

In this blog post, I explained how I set up Tailscale in my Kubernetes cluster using the Tailscale Operator and how I access my Kubernetes applications through Tailscale using the Tailscale Ingress Controller. Tailscale provides a secure and private way to connect to services without exposing them to the public internet. I hope this guide helps you set up Tailscale in your own Kubernetes cluster! Thanks to Josh Noll for his great guide on this topic.

Additional resources