En un runner self-hosted la acción necesita lo mismo que en uno de GitHub: root, para instalar el bloqueo nftables. Lo consigue de una de estas dos formas, en este orden:
| Cómo | Qué necesita | Cómo se ejecuta el sidecar |
|---|---|---|
sudo | El usuario del job puede usar sudo sin contraseña (sudo -n true funciona) | Como un proceso root en el host |
| Docker | El usuario del job llega al daemon de Docker (pertenece al grupo docker) | En un contenedor privilegiado con la red del host, a partir de una imagen local vacía (no se descarga nada), con el / del host montado en solo lectura |
Sin ninguna de las dos, la acción arranca igualmente el proxy, pero sin el bloqueo: solo se informa de lo que pasa por HTTPS_PROXY y, en enforce, solo eso se rechaza; las herramientas que ignoran las variables de proxy y los contenedores no quedan cubiertos. Pon lock: "on" para que el paso falle en ese caso. Cuando hay root pero el bloqueo no se puede instalar (falta nft, por ejemplo), enforce hace fallar el paso.
Requisitos
- Linux en x64 o arm64, con nftables (
nften/usr/sbin,/sbino/usr/bin) y un kernel que lo soporte, e iproute2 (ip). bash,curl,gzip,sha256sumysudoodockeren elPATHdel job.- Para el seguimiento de Docker: el socket del daemon y el bridge
docker0. - El usuario del job en el runner no es root (el bloqueo afecta a los sockets de ese usuario; la acción se niega a bloquear el uid 0).
Ejemplo
jobs:
test:
runs-on: [self-hosted, linux, x64]
steps:
- uses: actions/checkout@v5
- uses: openwaf-dev/egress-action@v0.3.2
with:
lock: "on"
containers: track
- run: make testHosts compartidos
Varios runners pueden compartir host si cada uno usa su propio usuario:
- El bloqueo es una tabla nftables por usuario (
egress_ci_<uid>) que solo afecta a los sockets de ese usuario y a las subredes de las redes Docker de ese job. Los jobs de otro usuario del runner no se ven afectados. - Los puertos del sidecar son fijos por usuario, por debajo del rango efímero; si están ocupados, pasa a los siguientes libres.
- Usa
containers: track, nuncalock-all:lock-allrechaza el tráfico fuera de la política del job actual de cualquier contenedor, también el de los demás jobs. - Un runner que da a cada slot de jobs su propio socket de Docker en
DOCKER_HOSTsigue funcionando: el socket del job reenvía a él.
Ejecuta cada runner de un host con su propio usuario: dos runners del mismo usuario en un host compartirían la tabla del bloqueo.
Qué significa root aquí
La acción necesita root para bloquear el job, y el job tiene ese mismo root: un paso que ejecute sudo nft delete table … o que use el grupo docker para arrancar un contenedor privilegiado puede quitar el bloqueo. En un runner self-hosted, el grupo docker equivale a root. Egress CI hace visible y más difícil la exfiltración por parte de una dependencia o una herramienta; no contiene a un paso que se propone escaparse. Ver límites.
Runners efímeros
En los runners que empiezan limpios en cada job (efímeros o just-in-time, VMs con autoescalado), lock-all es seguro y no hay nada que limpiar entre jobs. En los runners persistentes, el paso posterior (que se ejecuta aunque falle un paso) quita el bloqueo, el sidecar y el builder del job; conserva la caché de BuildKit del builder, hasta 4 GB, para el siguiente job del mismo usuario.