One door in: a jump host for my k3s cluster
Every laptop that holds cluster credentials is a door left unlocked. After a podman toolbox era, my homelab got a real answer: one jump host, and nothing else that can reach the cluster.
The shape of it
jmp — an Ubuntu box on the admin VLAN, holding the only kubeconfig that exists. Workstations connect over SSH (per-machine keys, password kept as a deliberate fallback); the jump connects out to the cluster and the internet, and accepts nothing inbound except SSH from the LAN:
sudo ufw default deny incoming
sudo ufw default allow outgoing
sudo ufw allow from 10.22.10.0/24 to any port 22 proto tcp
Plus a small SSH drop-in (PermitRootLogin no, AllowUsers). No fail2ban — the box is LAN-only and the threat model doesn’t justify the moving part.
Getting the kubeconfig — without ever opening a file on the nodes
ssh -t jsh@10.22.50.121 "sudo cat /etc/rancher/k3s/k3s.yaml" > ~/.kube/config
sed -i 's|https://127.0.0.1:6443|https://10.22.50.120:6443|' ~/.kube/config
The API VIP answers on 6443 (pure keepalived VRRP, no HAProxy in front), so the one-line rewrite is all that stands between the fresh kubeconfig and a healthy kubectl get nodes.
Tooling that actually earns its keep
kubectl, k9s, git, lazygit, neovim, dnsutils — and tmux, because a dropped WiFi during a tcpdump session on a node is a ruined experiment. Every work session starts inside one. Plus the familiar dotfiles: k alias with tab completion, and a 20-line vimrc that makes YAML behave. One file, symlinked into both vim and neovim.
What it buys
Node SSH and the API now have exactly two sources: the jump, and a break-glass path. Locking the nodes themselves behind those two sources (ufw on top of Cilium, applied one node at a time) is the careful sequel to this story — but the direction is set: fewer doors, one hallway.