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

    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.