Files
takana/scripts/foco-egress-remoto.sh
Sergio 212b304b60 atuq §6.5: el foco por cgroup MEDIDO — y corregido el propio documento
La fila de la tabla se leía como «bloquear sitios». El cortafuegos NO sabe de sitios: su política de
egress tiene UNA dimensión, qué cgroup sale, y ninguna de destino (leído en UnidadRed, no supuesto).
El foco que estas piezas dan es «el navegador no sale», con todo lo local andando — promesa más
honesta, además: una lista de dominios se esquiva con un espejo; un cgroup sin egress no.

Medido con nuestro propio nft, en el LXC donde somos root:
  linea-base exit=0 · control exit=0 · foco exit=1
Tres medidas y no una: la línea base porque un harness roto se lee igual que un foco que funciona, y
el control porque un reglaset que niega de más tampoco se distingue. `--broken-rules` abre egress al
cgroup en foco y el guardián falla nombrándolo (sale 1). Verificado en los dos sentidos.

Restricciones reales que salieron de medir: crear un cgroup pide root (EPERM incluso en un userns con
CAP_ALL), y `nft -c` no es sintaxis — resuelve el path del cgroup contra la máquina viva.

⚠ Y lo que rompí en el camino, documentado: `/sys/fs/cgroup` está montado SHARED, así que desmontar
la copia de un --rbind se propaga al montaje real. Dejé al worker sin cgroup2 dos veces, en silencio.
Remontado y jerarquía intacta. Ahora todo va en un mount namespace propio (--propagation private),
sin `umount -l` antes de un rm -rf, y con /proc/mounts consultado antes de borrar.

Tres falsos positivos más que cazó el harness, todos con cara de éxito: un gmp viejo tomado por
`ls store/*-gmp` (sin .so ⇒ nada conectaba, y el lab del hub lo tapaba), /sbin fuera del PATH del
chroot (sin `ip`, loopback caído), y un COMENTARIO que se ejecutó — backticks dentro de un heredoc
sin comillas corrieron `ip`/`ifconfig` en el host y pegaron su salida en el guión generado.
2026-09-10 22:55:10 +00:00

50 lines
2.3 KiB
Bash
Executable File

#!/usr/bin/env bash
# Corre `test-foco-egress.sh` donde SÍ hay root: empaqueta los artefactos VIGENTES, los manda al
# worker y trae el veredicto.
#
# scripts/foco-egress-remoto.sh [--broken-rules] [host] (host default: 1º de scripts/farm/.fleet)
#
# ⚠ Los artefactos se resuelven con `takana hash`, NO con `ls store/*-gmp`. La diferencia no es
# estética: el store guarda artefactos VIEJOS con el mismo nombre, y la primera corrida de esto
# empaquetó un `gmp` de otra época que sólo traía `libgmp.a` ⇒ `libnftables.so` no relocaba. En el
# hub no se veía porque el lab tiene su propia libgmp y la tapaba. Sellado ≠ vigente.
set -euo pipefail
cd "$(dirname "$0")/.."
ROTO=""
if [ "${1:-}" = "--broken-rules" ]; then ROTO="--broken-rules"; shift; fi
HOST="${1:-}"
if [ -z "$HOST" ]; then
HOST="$(awk 'NR==1{print $1}' scripts/farm/.fleet 2>/dev/null || true)"
[ -n "$HOST" ] || { echo "✗ no hay host: pasalo por argumento o poné uno en scripts/farm/.fleet" >&2; exit 2; }
fi
LLAVE="${SSH_KEY:-$HOME/.ssh/github5}"
TAKANA=./target/release/takana
TMP="$(mktemp -d)"; trap 'rm -rf "$TMP"' EXIT
echo "== artefactos vigentes"
DIRS=()
for r in nftables libmnl libnftnl gmp; do
h="$($TAKANA --store ./store hash "recipes/$r.toml" | tail -1)"; h="${h#b3:}"
d="store/$h-$r"
[ -d "$d" ] || { echo "✗ $r vigente no está sellado ($d) — construilo antes" >&2; exit 1; }
[ -n "$(ls -A "$d")" ] || { echo "✗ $r vigente está VACÍO: eso no es un artefacto, es un nombre" >&2; exit 1; }
echo " $r${h:0:12}"
DIRS+=("$h-$r")
done
tar czf "$TMP/artefactos-nft.tar.gz" -C store "${DIRS[@]}"
echo "== enviando a $HOST"
scp -i "$LLAVE" -o StrictHostKeyChecking=no -q \
scripts/test-foco-egress.sh .dev-fs/alpine-minirootfs.tar.gz "$TMP/artefactos-nft.tar.gz" \
"root@$HOST:/root/"
# `set -e` mataría el script antes de leer $? de un ssh que falla, y entonces el veredicto ROJO del
# guardián llegaría como si nunca hubiera corrido. Se captura explícitamente.
SALIDA=0
ssh -i "$LLAVE" -o BatchMode=yes "root@$HOST" \
"bash /root/test-foco-egress.sh --rootfs /root/alpine-minirootfs.tar.gz --artifacts /root/artefactos-nft.tar.gz $ROTO" \
|| SALIDA=$?
ssh -i "$LLAVE" -o BatchMode=yes "root@$HOST" \
'rm -f /root/test-foco-egress.sh /root/alpine-minirootfs.tar.gz /root/artefactos-nft.tar.gz' || true
exit $SALIDA