---
title: "The bastion is a pattern, not a box"
date: 2026-07-03
summary: "Admin credentials accumulate on whatever machine you happen to work from, until your daily driver is the real control plane of the fleet. A bastion fixes that — not by being special hardware, but by being the one place the keys live and the discipline that they never leave it."
tags: ["security", "operations", "homelab", "tailscale", "access"]
hero: "/blog/bastion-is-a-pattern.webp?v=1"
heroAlt: "A lone illuminated harbour pilot station on a dark sea, thin beams of cyan and magenta light reaching out to distant vessels — the charts and keys stay at the station, the ships only transit past it."
draft: false
---


Here's the uncomfortable default: your fleet's admin credentials live wherever you last needed them. A
kubeconfig on the laptop, another copy on the desktop, an age key pasted onto a third machine "just for one
decrypt", SSH keys sprouting wherever a clone was convenient. Nobody decided this. It accumulates.

Which means your **daily driver is the real control plane** — the machine that browses the web, opens email
attachments and runs whatever you installed last week is also the machine that can wipe a cluster. Lose it,
rebuild it, or compromise it, and you've done all three to the fleet.

The inversion is old and it still works: pick *one* point, put every key there, and make the rule that they
never leave it. Not a hardened appliance. A pattern.

<!-- DIAGRAM: one bastion node holding keys/contexts/repos, lines out to the clusters + git; laptops connect only THROUGH it -->
![One operator control point holding the keys, with everything driven through it](/diagrams/bastion-is-a-pattern.svg?v=1)

## Everything transits, nothing homes anywhere else

Think of a harbour pilot station. Every ship entering the harbour is guided by a pilot, but the charts and the
local knowledge never board the ships — they stay at the station, and the vessels transit past it. That's the
whole design: the dangerous knowledge has exactly one home, and traffic comes *to* it.

Mine is nothing special on purpose: a small Debian VM — four cores, no GPU passthrough, because a bastion needs
none. What makes it the bastion is what it holds. One kubeconfig with a context for every cluster. The
talosconfig for the OS layer beneath them. The SOPS age key that decrypts the fleet's secrets, sitting in
exactly one place at `~/.config/sops/age/keys.txt`. A checkout of every ops repo. And a toolchain pinned
deliberately — `talosctl` matched to the fleet's live Talos version, because a drifted client against a
production node is how apply-time surprises happen.

None of that is exotic. The pattern is the *singularity* of it: ask "where can the fleet be driven from?" and
the answer is one hostname, and auditing that answer takes a minute.

## The bastion is defined by what it refuses

The keys that live there matter less than the keys that were *refused*. When this box was stood up to take
over the operator role from an older machine — before that machine's wipe and rebirth as a GPU node — the
login credentials for my agent tooling were deliberately not copied across. Fresh auth on the new box beats a
credential that has now existed in two places, because the whole point collapses the moment "one place"
becomes "two, temporarily".

The stand-up also proved the pattern's diagnostic value. Every repo cloned fine — and then a push failed,
because the git remotes resolved through SSH host aliases that only existed on the *old* machine. Access had
been quietly welded to one particular computer for months, and nothing noticed while that computer was always
there. Consolidating forces the question: is this credential something the operator point holds, or something
one box happens to have? The fix was the pattern applied properly — a new key generated *on* the bastion,
registered once, never exported.

## The one that costs an evening

The bastion has to be reachable off-LAN, so it joined the tailnet as a subnet router, advertising its own
network. Here's the trap: it also sat *inside* a subnet another router already advertised — and bringing it
up with `--accept-routes` made it accept the overlay route *for its own LAN*. Local replies went into the
tunnel instead of out the NIC. ARP stayed healthy, every TCP connection died, and SSH to the box that holds
all the keys went dark.

The rule that falls out: a node on the only LAN **advertises routes but never accepts them** — it reaches that
network natively. And the recovery is itself a bastion lesson: you get back in *out-of-band*, through the
hypervisor console. The control point must sit on infrastructure you can still reach when the network lies.

## The principle

A bastion isn't a product you install; it's a property you enforce: **the set of places your keys exist has
exactly one member.** Any box can hold the role — a VM, a spare NUC, a cloud instance — and the role can move,
the way this one inherited it from a machine headed for a wipe. What never moves casually is the material
itself. Ships come and go all day.

The charts never leave the station.

*Live as a four-core Debian VM at 10.0.11.11 — one kubeconfig, one talosconfig, one age key, every ops repo —
driving a five-cluster Talos fleet, reachable over the tailnet as its second subnet router.*
