qdrant, act_runner y fail2ban MUEREN — y el sustituto del último no puede correr todavía

Decisión del usuario sobre lo que quedaba del censo:

· `qdrant` (:6333/:6334) — es la base vectorial de `gioser_api`, y ese backend es un FÓSIL
  (api.gioser.net da 502 permanente desde el §6.9). Una base sin consumidor no se muda. La receta
  queda en el catálogo, que no es lo mismo que la imagen, y eso NO es deuda.
· `act_runner` (:41027) — runner de CI, binario suelto que nadie provee. Si mañana hace falta CI,
  entra por receta y no por un binario copiado.
· `fail2ban` — **tawasuyu ya tiene el sustituto y es mejor**: `shared/cortafuegos` (SDD-ENTRADA §1)
  no mira logs con un daemon, usa DOS SETS DINÁMICOS DEL KERNEL (`ban4`/`ban6`, `flags dynamic`,
  `timeout`) con `limit rate over N/minute` POR IP de origen. El ban lo aplica nftables sin proceso
  y sin latencia.

🧨 PERO EL SUSTITUTO NO ARRANCA: `nft list ruleset` da «cache initialization failed: Invalid
argument». `nft 1.1.6` está instalado y sellado; lo que falta está un piso más abajo, en el
`.config` que publica el artefacto del kernel:

    CONFIG_NETFILTER=y · CONFIG_NF_CONNTRACK=y · **# CONFIG_NF_TABLES is not set**
    y la causa: **# CONFIG_NETFILTER_ADVANCED is not set** (NF_TABLES cuelga de ella)

Es la lección del §6.4 muro 1 otra vez: la receta dice lo que se CAMBIÓ; sólo el `.config` sellado
dice lo que QUEDÓ. `linux-generic` sale de `make defconfig` y defconfig apaga NETFILTER_ADVANCED.

⇒ HOY LA CAJA NO TIENE CORTAFUEGOS DE NINGUNA CLASE, con :22022, :2345, :1137, :80 y :443
públicos. Hay que decirlo entero. La cura es un kernel con NETFILTER_ADVANCED + NF_TABLES (trabajo
del SDD 22) y termina en un reinicio de producción.

MITIGACIÓN HECHA HOY, que no depende del kernel: el `sshd` ofrecía `password` y
`keyboard-interactive` —su config eran CUATRO líneas y ninguna hablaba de autenticación, así que
regía el default de OpenSSH— que es justo la puerta que fail2ban cerraba. Ahora es sólo claves, con
cuatro controles: la clave entra, :22022 y :2345 contestan `Permission denied (publickey)` sin
ofrecer contraseña, y el `git ls-remote` por SSH sigue andando.

La lección: una defensa se muda con su CAPACIDAD, no con su nombre. Decidir «fail2ban muere porque
tenemos algo mejor» es correcto Y deja un hueco abierto hasta que ese algo mejor pueda ejecutarse.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sergio
2026-09-15 20:28:29 +00:00
co-authored by Claude Opus 5
parent 0a7afebe9c
commit 4753a991f1
+45
View File
@@ -1733,6 +1733,51 @@ eligió es peor que una sin hora, porque nadie lo mira.
consistente, o sea que el respaldo habría copiado la sqlite a lo bruto. *Un paquete declarado no
es un paquete instalado: en una caja viva, lo que vale es lo que el `upgrade` proyectó.*
### 6.30 ⚰️ Tres servicios que MUEREN — y el cortafuegos que no puede correr todavía *(2026-09-15)*
Decisión del usuario sobre lo que quedaba del censo, y las tres son «no se muda»:
| servicio | por qué muere |
|---|---|
| **`qdrant`** (`:6333`, `:6334`) | es la base vectorial de `gioser_api`, y **ese backend es un fósil**: `api.gioser.net` da 502 permanente desde el §6.9. Una base sin consumidor no se muda. La receta `recipes/qdrant.toml` queda en el catálogo —**catálogo ≠ imagen**, y eso no es deuda—, pero no entra en ningún perfil. |
| **`act_runner`** (`:41027`) | el runner de CI del gitea, un binario suelto en `~/.local/bin` que nadie provee. Muere con la caja; si mañana hace falta CI, entra por receta y no por un binario copiado. |
| **`fail2ban-server`** | **tawasuyu ya tiene el sustituto**, y es mejor: `shared/cortafuegos` (§1 de su SDD-ENTRADA) no mira logs con un daemon, usa **dos sets dinámicos del kernel** (`ban4`/`ban6`, `flags dynamic`, `timeout`) con `limit rate over N/minute` **por IP de origen**. El ban lo aplica nftables sin proceso y sin latencia; fail2ban es un daemon de Python leyendo ficheros para hacer lo mismo peor. |
#### 🧨 Pero el sustituto NO PUEDE CORRER: el kernel de la caja no trae `nf_tables`
$ nft list ruleset
netlink: Error: cache initialization failed: Invalid argument
`nft 1.1.6` **está instalado** (`nftables` es raíz de `perfil.servidor` y está sellado). Lo que falta
está un piso más abajo, en el `.config` que el artefacto publica:
CONFIG_NETFILTER=y ← sí
CONFIG_NF_CONNTRACK=y ← sí
# CONFIG_NF_TABLES is not set ← AQUÍ
# CONFIG_NETFILTER_ADVANCED is not set ← y ésta es la causa: NF_TABLES cuelga de ella
Es otra vez la lección del §6.4 muro 1: **la receta dice lo que se CAMBIÓ; sólo el `.config` sellado
dice lo que QUEDÓ**. `linux-generic` sale de un `make defconfig`, y defconfig deja `NETFILTER_ADVANCED`
apagado, que arrastra a `NF_TABLES` con él.
**Hoy la caja no tiene cortafuegos de ninguna clase**: ni fail2ban (que no se muda), ni el
sustituto (que no arranca), ni una regla. Con `:22022`, `:2345`, `:1137`, `:80` y `:443` públicos,
eso hay que decirlo entero y no dejarlo implícito. La cura es un kernel con
`CONFIG_NETFILTER_ADVANCED=y` + `NF_TABLES` (y `NFT_CT`, `NFT_LIMIT`, `NFT_COUNTER`, `NFT_LOG`),
que es trabajo del SDD 22 y termina en un **reinicio de la caja de producción**.
#### La mitigación que NO depende del kernel, hecha hoy
El `sshd` de la caja ofrecía `password` y `keyboard-interactive` — su config eran **cuatro líneas**
y ninguna decía nada de autenticación, así que regía el default de OpenSSH. Sin cortafuegos y sin
fail2ban, eso es exactamente la puerta que aquéllos cerraban. Ahora es **sólo claves**, con los
cuatro controles corridos: la clave entra ✅, `:22022` contesta `Permission denied (publickey)` sin
ofrecer contraseña ✅, `:2345` igual ✅, y el `git ls-remote` por SSH sigue funcionando ✅.
**Lo que enseña:** *una defensa que se muda tiene que mudarse con su capacidad, no con su nombre*.
Decidir «fail2ban muere porque tenemos algo mejor» es correcto **y** deja un hueco abierto hasta que
ese algo mejor pueda ejecutarse. Entre la decisión y la capacidad hay un kernel de por medio.
## 7. Reusar los scripts que ya existen, y no escribir de nuevo
Pedido explícito del usuario. El inventario de lo que ya hace el trabajo: