docs: UFW k3s API admin allowlist procedure for host-operator
Add reusable protocol, wire it in ROLE.yaml, and document the current railiance01 allowlist plus quick commands in the pilot access-plan.
This commit is contained in:
parent
48443a9abb
commit
06037b0486
4 changed files with 182 additions and 2 deletions
|
|
@ -131,6 +131,18 @@ kaizen-agentic engagement close-session eng-coulomb-railiance01-ho-001 \
|
||||||
--success --duty standard_review --summary "..." --time 120 --quality 0.8
|
--success --duty standard_review --summary "..." --time 120 --quality 0.8
|
||||||
```
|
```
|
||||||
|
|
||||||
|
### UFW k3s API admin allowlist
|
||||||
|
|
||||||
|
After remediation, port **6443** is allowlist-only. Procedure:
|
||||||
|
|
||||||
|
- Role protocol: [`roles/host-operator/protocols/ufw-admin-allowlist.md`](../../roles/host-operator/protocols/ufw-admin-allowlist.md)
|
||||||
|
- Pilot table + quick commands: engagement `access-plan.md`
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -4 -s ifconfig.me; echo # on admin laptop
|
||||||
|
ssh railiance01 "sudo ufw allow from <PUBLIC_IP> to any port 6443 proto tcp comment 'k3s-api-admin-<label>'"
|
||||||
|
```
|
||||||
|
|
||||||
### Open human decisions from pilot (not supplier code)
|
### Open human decisions from pilot (not supplier code)
|
||||||
|
|
||||||
1. Add RAM and/or temporary swap on railiance01
|
1. Add RAM and/or temporary swap on railiance01
|
||||||
|
|
|
||||||
|
|
@ -34,14 +34,56 @@
|
||||||
- API keys / DB passwords → **OpenBao** via `warden route` (not this agent)
|
- API keys / DB passwords → **OpenBao** via `warden route` (not this agent)
|
||||||
- Do **not** message ops-warden for secret values
|
- Do **not** message ops-warden for secret values
|
||||||
|
|
||||||
|
## UFW k3s API admin allowlist (6443)
|
||||||
|
|
||||||
|
**Policy (since 2026-07-16 remediation):** port **6443/tcp** is **not** open to the
|
||||||
|
world. Remote k3s API / `kubectl` against the public IP works only from allowlisted
|
||||||
|
admin public IPs. **SSH (22) remains open Anywhere.**
|
||||||
|
|
||||||
|
**Full procedure:**
|
||||||
|
[`roles/host-operator/protocols/ufw-admin-allowlist.md`](../../../roles/host-operator/protocols/ufw-admin-allowlist.md)
|
||||||
|
|
||||||
|
### Current allowlist (update when changing UFW)
|
||||||
|
|
||||||
|
| Public IP | Label | Added | Notes |
|
||||||
|
|-----------|-------|-------|-------|
|
||||||
|
| 89.244.90.246 | k3s-api-operator-current | 2026-07-16 | Session IP during P4 remediation |
|
||||||
|
| 85.132.220.102 | k3s-api-operator-hist | 2026-07-16 | Historical login IP |
|
||||||
|
|
||||||
|
### Quick commands (railiance01)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Discover your public IP (on the admin laptop)
|
||||||
|
curl -4 -s ifconfig.me; echo
|
||||||
|
|
||||||
|
# List rules
|
||||||
|
ssh railiance01 'sudo ufw status numbered verbose'
|
||||||
|
|
||||||
|
# Add admin
|
||||||
|
ssh railiance01 "sudo ufw allow from <PUBLIC_IP> to any port 6443 proto tcp comment 'k3s-api-admin-<label>'"
|
||||||
|
|
||||||
|
# Remove: use rule number from status numbered
|
||||||
|
ssh railiance01 'sudo ufw delete <N>'
|
||||||
|
```
|
||||||
|
|
||||||
|
After any change: update the table above and append a line to the verification log.
|
||||||
|
Class: **`firewall_change`** — record approval for production changes.
|
||||||
|
|
||||||
|
**Not required for:** local `sudo k3s kubectl` on the host, or API access only via SSH tunnel.
|
||||||
|
|
||||||
|
**8472/udp:** world-open rule removed (single-node). Re-add only if multi-node flannel peers need it.
|
||||||
|
|
||||||
|
UFW backup from remediation: `/etc/ufw/user.rules.bak.20260716` on host.
|
||||||
|
|
||||||
## Verification log
|
## Verification log
|
||||||
|
|
||||||
| Date | Result | Notes |
|
| Date | Result | Notes |
|
||||||
|------|--------|-------|
|
|------|--------|-------|
|
||||||
| 2026-07-16 | **OK** | ICMP OK; `ssh railiance01` interactive-non-batch shell OK; host_observe assessment completed (RU-01) |
|
| 2026-07-16 | **OK** | ICMP OK; `ssh railiance01` shell OK; host_observe assessment (RU-01) |
|
||||||
|
| 2026-07-16 | **OK** | UFW 6443 restricted to allowlist; 8472 closed externally (P4) |
|
||||||
|
|
||||||
## Revocation
|
## Revocation
|
||||||
|
|
||||||
| Date | Action |
|
| Date | Action |
|
||||||
|------|--------|
|
|------|--------|
|
||||||
| _open_ | On ramp-down: stop renewing agent certs/keys used for this engagement; set schedule disabled; mark here |
|
| _open_ | On ramp-down: stop renewing agent certs/keys used for this engagement; set schedule disabled; remove temporary admin UFW rules if desired; mark here |
|
||||||
|
|
|
||||||
|
|
@ -26,6 +26,9 @@ spec:
|
||||||
- agent: host-operator
|
- agent: host-operator
|
||||||
slug: load-workload-review
|
slug: load-workload-review
|
||||||
path: roles/host-operator/protocols/load-workload-review.md
|
path: roles/host-operator/protocols/load-workload-review.md
|
||||||
|
- agent: host-operator
|
||||||
|
slug: ufw-admin-allowlist
|
||||||
|
path: roles/host-operator/protocols/ufw-admin-allowlist.md
|
||||||
memory_template: memory-template.md
|
memory_template: memory-template.md
|
||||||
default_cadence:
|
default_cadence:
|
||||||
health_review: daily
|
health_review: daily
|
||||||
|
|
|
||||||
123
roles/host-operator/protocols/ufw-admin-allowlist.md
Normal file
123
roles/host-operator/protocols/ufw-admin-allowlist.md
Normal file
|
|
@ -0,0 +1,123 @@
|
||||||
|
---
|
||||||
|
agent: host-operator
|
||||||
|
slug: ufw-admin-allowlist
|
||||||
|
title: UFW k3s API admin allowlist
|
||||||
|
version: 0.1.0
|
||||||
|
last_updated: "2026-07-16"
|
||||||
|
---
|
||||||
|
|
||||||
|
# UFW admin allowlist (k3s API / port 6443)
|
||||||
|
|
||||||
|
## Purpose
|
||||||
|
|
||||||
|
After world-open `6443/tcp` is removed, remote `kubectl` / k3s API access works only
|
||||||
|
from **explicitly allowlisted public IPs**. This procedure adds, lists, and removes
|
||||||
|
admin IPs safely.
|
||||||
|
|
||||||
|
**Access class:** `firewall_change` — requires recorded human approval on production.
|
||||||
|
|
||||||
|
## When to use
|
||||||
|
|
||||||
|
- New admin laptop / office / mobile network needs direct API access to the node
|
||||||
|
- Admin public IP changed (ISP / travel)
|
||||||
|
- CI or jump host must hit public `:6443` (prefer SSH tunnel when possible)
|
||||||
|
|
||||||
|
## When not needed
|
||||||
|
|
||||||
|
- SSH into the host and run `sudo k3s kubectl …` locally
|
||||||
|
- Access only via SSH tunnel / ops-bridge (SSH already open)
|
||||||
|
- IP is already listed in `ufw status`
|
||||||
|
|
||||||
|
## Preconditions
|
||||||
|
|
||||||
|
- SSH access to the host as an operator with passwordless or approved sudo
|
||||||
|
- Approver recorded for `firewall_change` on production hosts
|
||||||
|
- Target public IP known (see Discover IP)
|
||||||
|
|
||||||
|
## Discover IP (from the admin machine)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -4 -s ifconfig.me; echo
|
||||||
|
# or
|
||||||
|
curl -4 -s https://api.ipify.org; echo
|
||||||
|
```
|
||||||
|
|
||||||
|
Use the **public IPv4**, not a private LAN address (unless that is how the host sees you).
|
||||||
|
|
||||||
|
## List current rules
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh <host> 'sudo ufw status numbered verbose'
|
||||||
|
```
|
||||||
|
|
||||||
|
Note OpenSSH should remain `Anywhere` (or your org policy). k3s API lines look like:
|
||||||
|
|
||||||
|
```text
|
||||||
|
6443/tcp ALLOW IN <ip> # k3s-api-admin-<label>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Add an admin IP
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh <host> "sudo ufw allow from <PUBLIC_IP> to any port 6443 proto tcp comment 'k3s-api-admin-<label>'"
|
||||||
|
ssh <host> 'sudo ufw status numbered'
|
||||||
|
```
|
||||||
|
|
||||||
|
Example:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh railiance01 "sudo ufw allow from 203.0.113.50 to any port 6443 proto tcp comment 'k3s-api-admin-home'"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Verify
|
||||||
|
|
||||||
|
From the admin machine (with kubeconfig pointing at the public API):
|
||||||
|
|
||||||
|
```bash
|
||||||
|
kubectl get node
|
||||||
|
# or
|
||||||
|
curl -sk --max-time 5 https://<host-ip>:6443/version
|
||||||
|
```
|
||||||
|
|
||||||
|
## Remove a stale admin IP
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh <host> 'sudo ufw status numbered'
|
||||||
|
# identify rule number N for the stale IP
|
||||||
|
ssh <host> 'sudo ufw delete N' # confirm when prompted, or: echo y | sudo ufw delete N
|
||||||
|
```
|
||||||
|
|
||||||
|
Prefer deleting by number to avoid removing the wrong rule.
|
||||||
|
|
||||||
|
## Rollback (emergency: restore world-open API — last resort)
|
||||||
|
|
||||||
|
Only if lockout of all admins is worse than temporary exposure:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
ssh <host> 'sudo ufw allow 6443/tcp comment temporary-world-open-k3s-api'
|
||||||
|
# re-establish allowlist, then:
|
||||||
|
ssh <host> 'sudo ufw delete allow 6443/tcp'
|
||||||
|
```
|
||||||
|
|
||||||
|
Prefer fixing allowlist IPs over world-open.
|
||||||
|
|
||||||
|
## Optional: IPv6
|
||||||
|
|
||||||
|
If admins use IPv6 to the host:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
sudo ufw allow from <PUBLIC_IPV6> to any port 6443 proto tcp comment 'k3s-api-admin-<label>-v6'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Engagement bookkeeping
|
||||||
|
|
||||||
|
After changes:
|
||||||
|
|
||||||
|
1. Update `access-plan.md` allowlist table (IP, label, date, who)
|
||||||
|
2. Append session log / close-session summary (no secrets)
|
||||||
|
3. Note in vault Watch Points if IPs are dynamic
|
||||||
|
|
||||||
|
## Related
|
||||||
|
|
||||||
|
- host-operator privilege gate (`firewall_change`)
|
||||||
|
- Pilot reference: `engagements/pilots/eng-coulomb-railiance01-ho-001/access-plan.md`
|
||||||
Loading…
Add table
Add a link
Reference in a new issue