Sin contenedor¶
Cómo ejecutar Evey directamente en un equipo (systemd, un script de inicio o a mano) en lugar de usar la imagen Docker. La imagen es el camino recomendado: trae el sandbox de plugins, el endurecimiento y los entornos de ejecución de los plugins ya preparados. Sin contenedor, tienes que reproducir tú mismo ese nivel de protección: los binarios correctos uno junto a otro, un usuario dedicado que no sea root, el mecanismo de sandbox que admite tu kernel y carpetas de secretos accesibles solo para su propietario. Esta página lo recorre en orden.
Compilar e instalar los binarios¶
Compila los dos binarios Go e instálalos en la misma carpeta: el ejecutor de
plugins busca el lanzador primero en $EVEY_PLUGIN_LAUNCHER, después junto a
su propio ejecutable y por último en el $PATH.
# desde la raíz del repositorio
CGO_ENABLED=0 go build -ldflags="-s -w -X main.version=$(git describe --tags --always) -X main.commit=$(git rev-parse HEAD)" -o evey ./cmd/evey
CGO_ENABLED=0 go build -ldflags="-s -w" -o evey-plugin-launcher ./cmd/evey-plugin-launcher
sudo install -m 0755 evey evey-plugin-launcher /opt/evey/
# opcional: autocompletado del shell y página de manual, los dos generados por el binario
/opt/evey/evey completion bash | sudo tee /etc/bash_completion.d/evey >/dev/null
/opt/evey/evey man | sudo tee /usr/local/share/man/man1/evey.1 >/dev/null
evey version muestra la versión, el commit y la fecha de compilación sin
necesitar ninguna configuración.
La capa seccomp¶
Compila libevey-sandbox.so (un solo archivo C, necesita un compilador C) e
instálalo en la ruta que espera el ejecutor, /app/libevey-sandbox.so:
gcc -shared -fPIC -nostartfiles -o libevey-sandbox.so sandbox/sandbox.c
sudo install -D -m 0644 libevey-sandbox.so /app/libevey-sandbox.so
La ruta está fijada en el ejecutor. Sin ese archivo, los plugins se niegan a
arrancar (cierre por defecto), salvo si el servidor funciona en modo
desarrollo. Esta capa añade una lista de llamadas al sistema prohibidas
(seccomp) para los plugins enlazados dinámicamente, además de Landlock o
bubblewrap. La imagen la guarda en /app con el SDK; un enlace simbólico
también sirve.
Entornos de ejecución y servicios¶
Instala lo que invoque el entrypoint: de tus plugins. El ejecutor reconoce
python3, python, node, php, ruby, perl, lua, bash y sh;
python3 cubre la mayoría de los plugins de la comunidad. Después, los
servicios que usa el servidor:
| Dependencia | Para qué |
|---|---|
| ffmpeg y ffprobe | transcodificación y análisis de archivos; la imagen también incluye los controladores VAAPI y fpcalc (chromaprint) para detectar las intros |
PostgreSQL (servidor más una base de datos) y pg_dump |
la base de datos; pg_dump escribe el volcado automático previo a las migraciones |
| Meilisearch | el índice de búsqueda; sin él, la búsqueda recurre a SQL |
bwrap (bubblewrap) |
solo para el mecanismo de sandbox bubblewrap |
setcap (libcap) |
para dar al lanzador su capacidad de archivo |
La base de datos y el motor de búsqueda integrados son una función del punto
de entrada de la imagen, no del binario: sin contenedor, los ejecutas tú
mismo y apuntas EVEY_DB_HOST y EVEY_MEILI_URL hacia ellos.
Ejecutar con un usuario dedicado que no sea root¶
Nunca ejecutes el servidor como root. Crea un grupo y dos usuarios sin privilegios, como hace la imagen:
sudo groupadd --gid 1000 evey
sudo useradd --system --uid 1000 --gid evey --shell /usr/sbin/nologin evey
sudo useradd --system --uid 1001 --gid evey --shell /usr/sbin/nologin evey-plugin
evey(UID 1000) ejecuta el servidor.evey-plugin(UID 1001) es el usuario al que pasan los plugins cuando la separación de uid está activa. Así, un plugin comprometido acaba como otro usuario sin privilegios, que no puede leer los secretos del servidor por simples permisos de archivo.
Warning
El id del grupo importa: el lanzador hace pasar un plugin al UID 1001 y al
grupo del propio servidor, y rechaza cualquier uid o gid por debajo de
1000. Un grupo creado solo con useradd --system recibe un id de sistema
por debajo de 1000, y entonces los plugins en modo basic se rechazan.
El servidor se marca como no volcable al arrancar (PR_SET_DUMPABLE=0), así
que un plugin que se ejecuta en el mismo equipo no puede leer
/proc/<server-pid>/{mem,environ}.
Elegir el mecanismo de sandbox según tu kernel¶
Define EVEY_PLUGINS_SANDBOX_MODE. auto (el valor por defecto) prueba en
este orden landlock, bubblewrap y basic, y elige el más fuerte que admite el
equipo. Fija un modo explícito si quieres que, en caso de fallo, el plugin no
arranque.
Landlock (recomendado)¶
Una lista de rutas permitidas en el sistema de archivos (un plugin ve su propia carpeta y la carpeta de sockets, nunca tus datos ni tus secretos), más un filtro de salida TCP de Landlock v4. No necesita privilegios, ni montajes, ni espacios de nombres: el lanzador se lo aplica a sí mismo y después ejecuta el plugin.
Landlock tiene que estar compilado en el kernel y en la lista de LSM activos.
El ejecutor prueba landlock_create_ruleset; la prueba falla cuando la
llamada al sistema no existe (kernel anterior a 5.13) o cuando Landlock no
está en la lista activa. Para comprobarlo:
Si falta landlock en esa lista, añádelo a la línea de comandos del kernel y
reinicia (conserva las entradas existentes, la lista cambia según la
distribución):
Después, deja auto o fíjalo:
EVEY_PLUGINS_SANDBOX_MODE=landlock # cierre por defecto: un plugin se rechaza si Landlock no se puede aplicar
landlock pasa -require-landlock al lanzador, que termina con un código
distinto de cero en lugar de ejecutar un plugin sin confinar.
bubblewrap¶
Si Landlock no está disponible, instala bwrap. Pone cada plugin en
espacios de nombres de usuario, pid, uts, ipc y red, con una lista de
montajes permitidos. Necesita espacios de nombres de usuario sin privilegios
y la llamada al sistema mount: es así en la mayoría de los Linux sin
contenedor, pero está bloqueado dentro de un contenedor sin privilegios, y por
eso Landlock es el valor por defecto en contenedor. auto solo elige
bubblewrap cuando falta Landlock y una prueba desechable de bwrap funciona.
EVEY_PLUGINS_SANDBOX_MODE=bubblewrap # espacios de nombres
EVEY_PLUGINS_SANDBOX_MODE=strict # espacios de nombres más la capa seccomp
Comprueba que el equipo permite crear los espacios de nombres y los montajes:
basic (último recurso)¶
EVEY_PLUGINS_SANDBOX_MODE=basic es un cambio de uid más la capa seccomp; el
lanzador, si está presente, sigue instalando su lista seccomp del kernel y
Landlock en la medida de lo posible. No hay confinamiento del sistema de
archivos por rutas: un plugin se ejecuta con el UID 1001 y solo con seccomp.
Úsalo en kernels antiguos o muy restringidos donde no funciona ni Landlock ni
bubblewrap, y cuenta con la separación de uid descrita más abajo para
proteger los secretos.
Un plugin que tiene el permiso subprocess necesita el lanzador incluso en
modo basic: la capa seccomp no sobrevive a un exec de un proceso hijo,
solo el seccomp del kernel que instala el lanzador. Sin el lanzador, un plugin
así se niega a arrancar en lugar de ejecutarse sin confinar.
Mantener los secretos fuera del alcance de un plugin¶
La separación de uid ejecuta cada plugin como evey-plugin (UID 1001),
distinto del servidor (UID 1000), así que un plugin no puede leer
jwt.key, las copias de seguridad ni los registros por simples permisos de
archivo. Es importante en modo basic; con Landlock o bubblewrap, el sistema
de archivos ya está restringido, así que ahí es redundante.
EVEY_PLUGINS_UID_SEPARATION:
| Valor | Comportamiento |
|---|---|
auto (por defecto) |
activa solo cuando el sandbox queda en basic |
on |
siempre, como capa adicional independiente |
off |
nunca |
El cambio de usuario lo hace el lanzador, no el servidor. El servidor sigue sin ser root y sin ninguna capacidad; el lanzador lleva una capacidad de archivo y cambia al UID 1001 justo antes de ejecutar el plugin:
El lanzador rechaza cualquier uid o gid de destino por debajo de 1000. Cuando
no puede cambiar de usuario (falta la capacidad, no_new_privs activado), un
plugin en modo basic se rechaza, porque ahí el uid es su única protección; con
Landlock, registra un aviso y se ejecuta con el uid del servidor.
Warning
La separación de uid es incompatible con no_new_privs. Si el servidor
funciona bajo systemd con NoNewPrivileges=yes, la capacidad de archivo
se ignora al ejecutar: los plugins se rechazan en modo basic y, con
Landlock, la separación de uid se queda en el mismo uid. Elige una de las
dos cosas.
Si en cambio el servidor funciona como root (no recomendado), hace pasar directamente los plugins al UID 1001 y la capacidad no hace falta. La explicación en lenguaje sencillo de cada caso está en Configurar el sandbox de plugins.
Permisos de los archivos secretos¶
Haz lo mismo que la imagen: las carpetas que contienen secretos son accesibles solo para su propietario, así que un plugin que pasa al UID 1001 no puede leerlas ni siquiera sin Landlock.
sudo chown -R evey:evey /var/lib/evey
# el servidor es propietario de plugins/ (ahí extrae las instalaciones); el grupo
# evey, al que pertenece evey-plugin, solo lee y ejecuta los archivos instalados:
sudo chmod 750 /var/lib/evey/plugins
# solo el propietario en las carpetas secretas:
sudo chmod 700 /var/lib/evey/keys /var/lib/evey/logs /var/lib/evey/backups
# la propia clave de firma JWT (generada en 0600 en el primer arranque):
sudo chmod 600 /var/lib/evey/jwt.key
Adapta las rutas a donde apunten las variables EVEY_*_DIR y
EVEY_JWT_PRIVATE_KEY_PATH.
Configurar el entorno¶
Toda la configuración se hace con variables de entorno EVEY_*;
Referencia de configuración tiene la tabla completa.
Puntos propios de una instalación sin contenedor:
- Apunta
EVEY_DB_HOSTyEVEY_MEILI_URLa tu PostgreSQL y a tu Meilisearch.EVEY_DB_PASSWORDno puede ser el valor por defectoevey. - Las rutas por defecto del código Go se eligieron para el contenedor:
define
EVEY_LOG_DIR(por defecto la ruta relativalogs),EVEY_BACKUP_DIR(/data/backups),EVEY_TRANSCODING_CACHE_DIR(/data/transcode),EVEY_TRICKPLAY_CACHE_DIR(/cache/trickplay) yEVEY_JWT_PRIVATE_KEY_PATH(/data/jwt.key) con tus propias carpetas. - El servidor sirve HTTP sin cifrar: pon delante un proxy inverso para TLS,
con una URL externa en
https://y el proxy en Proxies de confianza (Administración → Acceso remoto;EVEY_SERVER_BASE_URLyEVEY_TRUSTED_PROXIESson los valores de respaldo). Consulta Configuraciones de proxy inverso. - El servidor abre dos puertos, y solo uno puede quedar expuesto.
EVEY_SERVER_PORT(por defecto9090) es la escucha gRPC nativa; la API HTTP a la que se conectan tus clientes y tu proxy inverso usa ese puerto más uno (9091). El control de acceso remoto, que decide si los clientes de fuera de tu red local pueden conectarse, está en la cadena HTTP y no cubre la escucha gRPC. Por eso esta solo escucha en la interfaz local por defecto (EVEY_GRPC_BIND=127.0.0.1). Si tienes un motivo para publicarla, defineEVEY_GRPC_BIND=0.0.0.0; el servidor avisa al arrancar de que el control no se le aplica, y entonces tienes que protegerla tú con un cortafuegos. - Las migraciones se ejecutan al arrancar; no hay un paso de migración aparte.
- Los límites de recursos de los plugins (
EVEY_PLUGINS_MEMORY_MB,_PIDS_MAX,_DISK_MAX_MB,_CPU_NICE) y el modo de sandbox se pueden cambiar en marcha desde Administración → Plugins → Límites de recursos; los valores del entorno son los valores iniciales. - El reinicio del servidor desde el panel de administración depende del supervisor de la imagen y se indica como no disponible sin contenedor: reinicia el servicio tú mismo.
Verificar el sandbox¶
El servidor registra el mecanismo que eligió. Cuando arranque el primer plugin, busca:
- una vez, para
auto:plugin sandbox auto-detection complete selected_mode=landlock(obubblewrap,basic); - en cada arranque de plugin:
plugin sandbox applied sandbox_mode=landlock plugin_id=...; - el aviso que indica un problema si esperabas Landlock:
plugin sandbox auto-detection fell back to basic mode: no per-path filesystem isolation available ..., que significa que no se encontró ni Landlock ni unbwrapque funcione. Vuelve a revisar la sección sobre los mecanismos de sandbox.
Confirma la parte del kernel por separado:
cat /sys/kernel/security/lsm # muestra "landlock"
grep Seccomp: /proc/<plugin-pid>/status # 2 = hay un filtro seccomp activo en el plugin
Una línea Seccomp: 2 en un proceso de plugin en marcha confirma que el
filtro del kernel está instalado. Con EVEY_PLUGINS_SANDBOX_MODE=landlock y
Landlock sin aplicar, el plugin se niega a arrancar: es el cierre por defecto
funcionando como debe.
Para las copias de seguridad, las actualizaciones y los comandos de
recuperación, las páginas del contenedor sirven tal cual:
Copias de seguridad y actualizaciones,
Recuperación y Línea de comandos
describen el mismo binario evey admin.