Make the k3s API tunnel-only (ADR-005), stop declaring Flannel VXLAN open to Anywhere, tag the base role so firewall can be scoped, and schedule the Goss declared-vs-live check. CoulombCore sets ufw_manage false so a converge cannot enable UFW there. T02 still needs operator approval for make converge-firewall HOST=Railiance01.
58 lines
2.1 KiB
Markdown
58 lines
2.1 KiB
Markdown
# ADR-005 — k3s API is tunnel-only
|
|
|
|
**Status:** Accepted
|
|
**Date:** 2026-08-15
|
|
**Deciders:** implementation of RAIL-HO-WP-0009-T04
|
|
**Workplans:** `RAIL-HO-WP-0009`
|
|
|
|
---
|
|
|
|
## Context
|
|
|
|
Operator addresses on this network rotate with the ISP lease. A public UFW
|
|
allowlist for `6443/tcp` is therefore a treadmill:
|
|
|
|
- miss a rotation and `kubectl` breaks mid-session
|
|
- leave the old grant standing and it becomes a grant to a stranger
|
|
- hand-add the new address and the declaration drifts again
|
|
|
|
That cycle produced this workplan. The live allowlist drifted by hand *during
|
|
the session that was fixing allowlist drift*, and again before the next
|
|
session (`89.244.90.248` appeared undeclared). On 2026-08-15 the workstation
|
|
egress address was `85.132.220.102` — already on the revoked list as a
|
|
"historic" operator address.
|
|
|
|
`docs/deploy-stack.md` already documents API access over the ops-bridge SSH
|
|
tunnel for CoulombCore (`k3s-api-coulombcore`, local port 16443). The same
|
|
tunnel already exists for Railiance01 (`k3s-api-railiance01`, local port
|
|
16444). SSH itself stays public, so the host remains recoverable.
|
|
|
|
## Decision
|
|
|
|
The public k3s API allowlist is **empty**. Operator and agent `kubectl` access
|
|
uses the ops-bridge tunnels:
|
|
|
|
| Cluster | Tunnel | Local port | Remote |
|
|
|-------------|-------------------------|------------|--------|
|
|
| CoulombCore | `k3s-api-coulombcore` | 16443 | 6443 |
|
|
| Railiance01 | `k3s-api-railiance01` | 16444 | 6443 |
|
|
|
|
```bash
|
|
bridge up k3s-api-railiance01
|
|
# kubeconfig server: https://127.0.0.1:16444
|
|
```
|
|
|
|
Trade: every operator `kubectl` action depends on ops-bridge. That is accepted.
|
|
A rotating public allowlist is the worse dependency.
|
|
|
|
Emergency break-glass remains SSH: `ssh railiance01 -- sudo k3s kubectl …`.
|
|
Do not re-open `6443/tcp` to Anywhere.
|
|
|
|
## Consequences
|
|
|
|
- `k3s_api_allowed_sources` stays `[]`.
|
|
- Former public grants live in `k3s_api_revoked_sources` so a firewall-tagged
|
|
converge deletes them.
|
|
- Goss asserts the 6443 allowlist size is exactly the declared length (zero)
|
|
and that no revoked address remains.
|
|
- Amending this ADR is required before adding any new public 6443 source.
|