Tailscale: MagicDNS Detail
Level 3 (Detail) — Naming contracts, .ts.net domain, workload DNS resolution.
Concept
Tailscale MagicDNS assigns .ts.net hostnames to every device on the tailnet. The tailnet for TazLab is magellanic-gondola.ts.net, so every device gets a FQDN like <device-name>.magellanic-gondola.ts.net.
Current Device Names
| Device | MagicDNS FQDN | Tags |
|---|---|---|
lushycorp-vault | lushycorp-vault.magellanic-gondola.ts.net | tag:tazlab-vault, tag:vault-api |
tazlab-k8s-control-plane-01 | tazlab-k8s-control-plane-01.magellanic-gondola.ts.net | tag:tazlab-k8s |
| TazPod (operator) | ephemeral, no stable name | tag:tazpod |
Naming Evolution
| Phase | Name | Type | Status |
|---|---|---|---|
| Original | lushycorp-vm.ts.tazlab.net | MagicDNS (device name) | Superseded |
| Custom alias | lushycorp-api.ts.tazlab.net | Runtime TLS config | Debt (TD-020), retired |
| Current | lushycorp-vault | MagicDNS (device name) | Active |
| Current FQDN | lushycorp-vault.magellanic-gondola.ts.net | MagicDNS | Active |
Custom Alias Problem
The alias lushycorp-api.ts.tazlab.net was defined only in the Vault runtime TLS configuration, not in Tailscale DNS. This means:
- It is not lifecycle-stable: after a destroy/recreate, the tailnet IP changes and the alias must be manually updated
- It is not Tailscale-owned: the
.ts.tazlab.netsubdomain is not registered in the global DNS hierarchy - It requires bespoke DNS glue to work, adding complexity
The preferred direction is to converge onto lushycorp-vault.magellanic-gondola.ts.net which IS lifecycle-stable and Tailscale-managed.
Workload DNS Resolution (Current — ExternalName Egress Proxy)
Since 15-tailscale-operator-hardening (2026-05-09), the architecture uses the native Tailscale Kubernetes Operator DNS path, replacing the earlier relay DaemonSet.
Architecture: ExternalName + DNSConfig
The Operator provides DNS resolution for MagicDNS names via:
- ExternalName Service — target nodes like Vault are declared as
ExternalNameservices with annotationtailscale.com/tailnet-fqdn - Egress Proxy — for each ExternalName, the Operator creates a dedicated egress proxy pod in the
tailscalenamespace - DNSConfig — the Operator’s nameserver auto-registers A records mapping MagicDNS names to proxy pod IPs
- CoreDNS forwarding — user-managed CoreDNS (
10.96.0.10) forwardsts.netto the nameserver’s ClusterIP10.108.193.103
pod → CoreDNS (10.96.0.10)
→ forward ts.net → nameserver Service (10.108.193.103)
→ nameserver pod (DNSConfig CRD)
→ egress proxy pod (connected to tailnet)
→ target: lushycorp-vault.magellanic-gondola.ts.net
CoreDNS Hardening on Talos
Talos v1.12+ uses Server-Side Apply — the built-in CoreDNS controller overwrites any manual ConfigMap changes. Implemented “Disable & Replace”:
cluster.coreDNS.disabled: truein Talos configmachine.kubelet.clusterDNS: ["10.96.0.10"]on all nodes- User-managed CoreDNS stack (SA, RBAC, ConfigMap, Deployment, Service) deployed via Terraform
inlineManifest
Previous Approach (decommissioned)
Before 15-tailscale-operator-hardening, a hostNetwork CoreDNS relay DaemonSet on port 5353 used a static hosts plugin mapping (lushycorp-vault → 100.82.13.87). Replaced because the ExternalName egress proxy approach is the enterprise-correct Operator-native solution — no static mappings, no relay management, no Corefile patches.
Verified Behavior (2026-05-09)
- Pod using standard cluster DNS resolves
lushycorp-vault.magellanic-gondola.ts.netto egress proxy pod IP - Traffic flows through the proxy into the tailnet, reaching Vault securely
- No relay DaemonSet, no static host mappings, no
kubectlpatches increate.sh
See Also
- Topic: Vault Contract
- Topic: Cluster Integration
- Detail: Talos Bridge Detail
- Debt: TD-020 (custom alias, retired)
- CRISP:
15-tailscale-operator-hardening - Hub: Tailscale