|
| 1 | +# Minimal Worker VM Installation |
| 2 | +**Goal:** Join a hospital-side VM to a MicroK8s cluster as a **worker** using **Tailscale-only** networking (no public MicroK8s ports). |
| 3 | +**Security posture:** If host firewall policy is strict, keep inbound closed and allow only the minimum required traffic on `tailscale0`. |
| 4 | +--- |
| 5 | + |
| 6 | +## 0) Variables (set these) |
| 7 | +- `MASTER_TS` = the master VM's Tailscale IPv4 (e.g., `100.x.y.z`) |
| 8 | +- `TS_AUTHKEY` = short-lived, **one-off** Tailscale auth key (ideally tagged) |
| 9 | + |
| 10 | +Example: |
| 11 | +```bash |
| 12 | +export MASTER_TS="100.108.97.6" |
| 13 | +export TS_AUTHKEY="tskey-auth-REDACTED" |
| 14 | +``` |
| 15 | + |
| 16 | +--- |
| 17 | + |
| 18 | +## 1) Install MicroK8s and Tailscale (worker VM) |
| 19 | + |
| 20 | +```bash |
| 21 | +sudo snap install microk8s --classic --channel=1.33/stable |
| 22 | +curl -fsSL https://tailscale.com/install.sh | sh |
| 23 | +``` |
| 24 | + |
| 25 | +--- |
| 26 | + |
| 27 | +## 2) Join the Tailnet (worker VM) |
| 28 | + |
| 29 | +**Note:** `--accept-dns=false` prevents changing hospital DNS settings. |
| 30 | + |
| 31 | +```bash |
| 32 | +sudo tailscale up --auth-key="$TS_AUTHKEY" --accept-dns=false |
| 33 | +tailscale ip -4 |
| 34 | +tailscale status |
| 35 | +``` |
| 36 | + |
| 37 | +--- |
| 38 | + |
| 39 | +## 3) UFW minimum rules (explicit split: public network vs Tailnet) |
| 40 | + |
| 41 | +Apply this section only if the hospital VM enforces UFW with restrictive defaults. |
| 42 | +Assumed baseline policy: `sudo ufw default deny incoming` and a controlled outbound policy per hospital standard. |
| 43 | + |
| 44 | +Rule scope in this section: |
| 45 | +- **Public network rules**: not bound to `tailscale0`; used only so the Tailscale client can establish/maintain connectivity. |
| 46 | +- **Tailnet-only rules**: explicitly bound to `tailscale0`; these carry MicroK8s node traffic. |
| 47 | + |
| 48 | +### 3.1 Public network outbound rules (Tailscale client only) |
| 49 | + |
| 50 | +```bash |
| 51 | +# Public egress needed by the Tailscale daemon for control/relay/connectivity |
| 52 | +sudo ufw allow out 443/tcp |
| 53 | +sudo ufw allow out 80/tcp |
| 54 | +sudo ufw allow out 3478/udp |
| 55 | +sudo ufw allow out 41641/udp |
| 56 | +``` |
| 57 | + |
| 58 | +**Important:** These are **public-network egress-only** exceptions. They are not MicroK8s service ports and they are not opened inbound. |
| 59 | + |
| 60 | +### 3.2 Tailnet-only: worker -> master (MicroK8s join + API) |
| 61 | + |
| 62 | +```bash |
| 63 | +# Restricted to tailscale0 and to the master Tailscale IP |
| 64 | +sudo ufw allow out on tailscale0 to "$MASTER_TS" port 25000 proto tcp # cluster-agent |
| 65 | +sudo ufw allow out on tailscale0 to "$MASTER_TS" port 16443 proto tcp # Kubernetes API (MicroK8s) |
| 66 | +``` |
| 67 | + |
| 68 | +### 3.3 Tailnet-only: master/cluster -> worker (kubelet secure port) |
| 69 | + |
| 70 | +```bash |
| 71 | +# Restricted to tailscale0 and master Tailscale IP |
| 72 | +sudo ufw allow in on tailscale0 from "$MASTER_TS" to any port 10250 proto tcp |
| 73 | +``` |
| 74 | + |
| 75 | +### 3.4 Tailnet-only: Calico VXLAN dataplane between nodes |
| 76 | + |
| 77 | +```bash |
| 78 | +# Calico VXLAN is UDP 4789 between nodes, only on tailscale0 |
| 79 | +sudo ufw allow in on tailscale0 to any port 4789 proto udp |
| 80 | +sudo ufw allow out on tailscale0 to any port 4789 proto udp |
| 81 | +``` |
| 82 | + |
| 83 | +**Scope note:** VXLAN is node-to-node traffic, so `4789/udp` applies to all cluster node peers reachable on `tailscale0`, not only the master. |
| 84 | +Use Tailscale ACLs/tags to ensure only authorized worker/master nodes can join that Tailnet segment. |
| 85 | + |
| 86 | +**Dependency note:** These VXLAN rules are valid when the cluster backend is Calico VXLAN. If the backend changes (for example IPIP or WireGuard), ports/protocols must be adjusted by the cluster operator. |
| 87 | + |
| 88 | +### 3.5 Reload and verify UFW rules |
| 89 | + |
| 90 | +```bash |
| 91 | +sudo ufw reload |
| 92 | +sudo ufw status verbose |
| 93 | +sudo ufw status numbered |
| 94 | +``` |
| 95 | + |
| 96 | +--- |
| 97 | + |
| 98 | +## 4) Connectivity checks (before `microk8s join`) |
| 99 | + |
| 100 | +```bash |
| 101 | +tailscale ping "$MASTER_TS" |
| 102 | + |
| 103 | +# Optional reachability checks to master |
| 104 | +nc -vz -w2 "$MASTER_TS" 25000 |
| 105 | +nc -vz -w2 "$MASTER_TS" 16443 |
| 106 | +``` |
| 107 | + |
| 108 | +Expected: |
| 109 | + |
| 110 | +* `tailscale ping` replies (no timeout) |
| 111 | +* `nc` to 25000 and 16443 succeeds |
| 112 | + |
| 113 | +--- |
| 114 | + |
| 115 | +## 5) Join MicroK8s as a worker |
| 116 | + |
| 117 | +Run the join command provided securely by the master operator (short-lived / one-time): |
| 118 | + |
| 119 | +```bash |
| 120 | +sudo microk8s join <MASTER_TS>:25000/<token>/<hash> --worker |
| 121 | +``` |
0 commit comments