Sans conteneur¶
Comment faire tourner Evey directement sur un hôte (systemd, un script d'init, ou à la main) au lieu de l'image Docker. L'image est la voie recommandée : elle livre la sandbox des plugins, le durcissement et les runtimes des plugins déjà configurés. Se passer du conteneur signifie reproduire cette configuration vous-même : les bons binaires côte à côte, un utilisateur dédié non root, le moteur de sandbox que votre noyau prend en charge, et des dossiers de secrets réservés à leur propriétaire. Cette page présente ces étapes dans l'ordre.
Construire et installer les binaires¶
Construisez les deux binaires Go et installez-les dans le même dossier : le
lanceur de plugins cherche le launcher d'abord dans $EVEY_PLUGIN_LAUNCHER,
puis à côté de son propre exécutable, puis dans $PATH.
# depuis la racine du dépôt
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/
# facultatif : la complétion shell et la page de manuel, toutes deux imprimées par le binaire
/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 affiche la version, le commit et la date de construction sans
aucune configuration.
Le module seccomp¶
Construisez libevey-sandbox.so (un seul fichier C, il faut un compilateur
C) et installez-la au chemin que le lanceur attend, /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
Le chemin est fixé dans le lanceur. Sans ce fichier, les plugins refusent de
démarrer (refus par défaut) sauf si le serveur tourne en mode développement. Le
module ajoute une liste de refus seccomp pour les plugins liés dynamiquement,
par-dessus Landlock ou bubblewrap. L'image la garde sous /app avec le SDK ;
un lien symbolique convient aussi.
Runtimes et services¶
Installez ce que le entrypoint: de vos plugins invoque. Le lanceur
reconnaît python3, python, node, php, ruby, perl, lua, bash
et sh ; python3 couvre la plupart des plugins communautaires. Puis les
services avec lesquels le serveur communique :
| Dépendance | Pourquoi |
|---|---|
| ffmpeg et ffprobe | transcodage, analyse ; l'image embarque aussi les pilotes VAAPI et fpcalc (chromaprint) pour la détection des génériques |
PostgreSQL (serveur plus une base) et pg_dump |
la base ; pg_dump écrit le dump automatique de pré-migration |
| Meilisearch | l'index de recherche ; sans lui la recherche se replie sur SQL |
bwrap (bubblewrap) |
uniquement pour le moteur de sandbox bubblewrap |
setcap (libcap) |
pour accorder au launcher sa capability de fichier |
La base et le moteur de recherche embarqués sont une fonction du point
d'entrée de l'image, pas du binaire : sans conteneur, vous faites tourner les
deux vous-même et indiquez leur adresse dans EVEY_DB_HOST et EVEY_MEILI_URL.
Tourner sous un utilisateur dédié non root¶
Ne lancez jamais le serveur en root. Créez un groupe et deux utilisateurs sans privilège, comme le fait l'image :
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) fait tourner le serveur.evey-plugin(UID 1001) est l'utilisateur vers lequel les plugins sont abaissés quand la séparation d'uid est active, pour qu'un plugin compromis se retrouve sous un autre utilisateur sans privilège, incapable de lire les secrets du serveur par simples permissions de fichiers.
Warning
L'identifiant du groupe compte : le launcher abaisse un plugin vers l'UID
1001 et vers le groupe du serveur lui-même, et refuse tout uid ou gid
inférieur à 1000. Un groupe créé par useradd --system seul reçoit un
identifiant système inférieur à 1000, et les plugins en mode basic sont
alors refusés.
Le serveur se marque non « dumpable » au démarrage (PR_SET_DUMPABLE=0),
donc un plugin voisin ne peut pas lire /proc/<pid-du-serveur>/{mem,environ}.
Choisir le moteur de sandbox pour votre noyau¶
Définissez EVEY_PLUGINS_SANDBOX_MODE. auto (la valeur par défaut) résout
dans l'ordre landlock, bubblewrap, basic et retient le plus fort que l'hôte
prend en charge. Fixez un mode explicitement quand vous voulez qu'un plugin soit
refusé si ce mode n'est pas disponible.
Landlock (recommandé)¶
Une liste blanche de chemins (un plugin voit son propre dossier et le dossier de socket, jamais vos données ni vos secrets) plus un filtre de sortie TCP Landlock v4. Il ne demande ni privilège, ni montage, ni espace de noms : le launcher se l'applique à lui-même, puis exécute le plugin.
Landlock doit être compilé dans le noyau et présent dans la liste des LSM
actifs. Le lanceur sonde landlock_create_ruleset ; la sonde échoue quand
l'appel système est absent (noyau antérieur à 5.13) ou quand Landlock n'est
pas dans la liste active. Vérifiez :
Si landlock manque dans cette liste, ajoutez-le sur la ligne de commande du
noyau et redémarrez (gardez les entrées existantes, la liste varie selon la
distribution) :
Puis gardez auto ou figez le mode :
EVEY_PLUGINS_SANDBOX_MODE=landlock # échec fermé : un plugin est refusé quand Landlock ne peut pas être imposé
landlock passe -require-landlock au launcher, qui sort avec un code non
nul plutôt que de lancer un plugin sans confinement.
bubblewrap¶
Quand Landlock n'est pas disponible, installez bwrap. Il place chaque
plugin dans des espaces de noms utilisateur, pid, uts, ipc et réseau avec
une liste blanche de montages. Il lui faut les espaces de noms utilisateur
non privilégiés et l'appel système mount, ce qui est le cas sur la plupart des
Linux sans conteneur mais bloqué dans un conteneur non privilégié, ce qui explique
que Landlock soit le défaut du conteneur. auto ne retient bubblewrap que si
Landlock est absent et qu'un test bwrap ponctuel réussit.
EVEY_PLUGINS_SANDBOX_MODE=bubblewrap # espaces de noms
EVEY_PLUGINS_SANDBOX_MODE=strict # espaces de noms plus la cale seccomp
Vérifiez que l'hôte autorise la mise en place des espaces de noms et du montage :
basic (dernier recours)¶
EVEY_PLUGINS_SANDBOX_MODE=basic est un abaissement d'uid plus le module
seccomp ; le launcher, quand il est présent, installe quand même sa liste de
refus seccomp noyau et un Landlock appliqué au mieux. Il n'y a aucun confinement de
fichiers par chemin : un plugin tourne sous l'UID 1001 avec seccomp seul.
Réservez-le aux noyaux anciens ou verrouillés où ni Landlock ni bubblewrap ne
fonctionnent, et comptez sur la séparation d'uid ci-dessous pour protéger les
secrets.
Un plugin doté de la permission subprocess exige le launcher même en mode
basic : le module n'est plus actif après l'exec d'un processus enfant,
seul le seccomp noyau du launcher le reste. Sans le launcher, un tel plugin refuse de
démarrer plutôt que de tourner sans confinement.
Garder les secrets hors de portée d'un plugin¶
La séparation d'uid fait tourner chaque plugin sous evey-plugin (UID
1001), distinct du serveur (UID 1000), pour qu'un plugin ne puisse pas lire
jwt.key, les sauvegardes ou les journaux par simples permissions de
fichiers. Elle compte en mode basic ; sous Landlock ou bubblewrap le
système de fichiers est déjà isolé, elle y est redondante.
EVEY_PLUGINS_UID_SEPARATION :
| Valeur | Comportement |
|---|---|
auto (défaut) |
active seulement quand la sandbox se résout en basic |
on |
toujours, comme couche indépendante supplémentaire |
off |
jamais |
L'abaissement est fait par le launcher, pas par le serveur. Le serveur reste non root et sans aucune capability ; le launcher porte une seule capability de fichier et bascule vers l'UID 1001 juste avant d'exécuter le plugin :
Le launcher refuse tout uid ou gid cible inférieur à 1000. Quand il ne peut
pas abaisser (capability absente, no_new_privs positionné), un plugin en
mode basic est refusé, puisque l'uid y est sa seule protection ; sous
Landlock il journalise un avertissement et tourne sous l'uid du serveur.
Warning
La séparation d'uid est incompatible avec no_new_privs. Si le serveur
tourne sous systemd avec NoNewPrivileges=yes, la capability de fichier
est ignorée à l'exec : les plugins sont refusés en mode basic, et sous
Landlock le plugin tourne sous le même uid que le serveur. Choisissez l'un ou
l'autre.
Si le serveur tourne en root à la place (déconseillé), il abaisse lui-même les plugins vers 1001 et la capability n'est pas nécessaire. Le tableau en langage courant, scénario par scénario, est dans Sandbox des plugins.
Permissions des fichiers secrets¶
Reproduisez la configuration de l'image : les dossiers qui contiennent des secrets sont réservés à leur propriétaire, pour qu'un plugin abaissé vers l'UID 1001 ne puisse pas les lire même sans Landlock.
sudo chown -R evey:evey /var/lib/evey
# le serveur possède plugins/ (il y extrait les installations) ; le groupe evey,
# dont evey-plugin fait partie, ne fait que lire et exécuter les fichiers installés :
sudo chmod 750 /var/lib/evey/plugins
# propriétaire seul sur les dossiers de secrets :
sudo chmod 700 /var/lib/evey/keys /var/lib/evey/logs /var/lib/evey/backups
# la clé de signature JWT elle-même (générée en 0600 au premier démarrage) :
sudo chmod 600 /var/lib/evey/jwt.key
Adaptez les chemins à l'endroit où pointent les variables EVEY_*_DIR et
EVEY_JWT_PRIVATE_KEY_PATH.
Configurer l'environnement¶
Toute la configuration passe par des variables d'environnement EVEY_* ;
Configuration contient le tableau complet. Points propres à une
installation sans conteneur :
- Indiquez dans
EVEY_DB_HOSTetEVEY_MEILI_URLl'adresse de vos PostgreSQL et Meilisearch.EVEY_DB_PASSWORDne doit pas être la valeur par défautevey. - Les chemins par défaut du code ont été choisis pour le conteneur :
réglez
EVEY_LOG_DIR(par défaut le chemin relatiflogs),EVEY_BACKUP_DIR(/data/backups),EVEY_TRANSCODING_CACHE_DIR(/data/transcode),EVEY_TRICKPLAY_CACHE_DIR(/cache/trickplay) etEVEY_JWT_PRIVATE_KEY_PATH(/data/jwt.key) vers vos propres dossiers. - Le serveur sert du HTTP en clair : mettez un proxy inverse devant pour le
TLS, avec une URL externe en
https://et le proxy dans Proxys de confiance (Administration → Accès distant ;EVEY_SERVER_BASE_URLetEVEY_TRUSTED_PROXIESsont les replis). Voir Proxy inverse. - Le serveur ouvre deux ports, et un seul peut être exposé.
EVEY_SERVER_PORT(9090par défaut) est l'écoute gRPC native ; l'API HTTP qu'utilisent vos clients et votre proxy inverse est ce port plus un (9091). Le contrôle d'accès distant, qui décide si des clients hors de votre LAN peuvent se connecter, est intégré à la chaîne HTTP et ne couvre pas l'écoute gRPC, qui se lie donc par défaut à la boucle locale seule (EVEY_GRPC_BIND=127.0.0.1). Si vous avez une raison de la publier, définissezEVEY_GRPC_BIND=0.0.0.0; le serveur avertit au démarrage que le contrôle ne s'y applique pas, et le pare-feu est alors à votre charge. - Les migrations tournent au démarrage ; il n'y a pas d'étape de migration séparée.
- Les plafonds de ressources des plugins (
EVEY_PLUGINS_MEMORY_MB,_PIDS_MAX,_DISK_MAX_MB,_CPU_NICE) et le mode de sandbox se modifient à chaud depuis Administration → Plugins → Limites de ressources ; les valeurs d'environnement sont les défauts initiaux. - Le redémarrage du serveur depuis le panneau d'admin s'appuie sur le superviseur de l'image et se déclare indisponible hors conteneur : redémarrez le service vous-même.
Vérifier la sandbox¶
Le serveur journalise le moteur qu'il a résolu. Après le premier démarrage de plugin, cherchez :
- une fois, pour
auto:plugin sandbox auto-detection complete selected_mode=landlock(oububblewrap,basic) ; - à chaque démarrage de plugin :
plugin sandbox applied sandbox_mode=landlock plugin_id=...; - l'avertissement qui signale un problème quand vous attendiez
Landlock :
plugin sandbox auto-detection fell back to basic mode: no per-path filesystem isolation available ..., qui signifie que ni Landlock ni unbwrapfonctionnel n'ont été trouvés. Revérifiez la section sur les moteurs ci-dessus.
Confirmez le côté noyau indépendamment :
cat /sys/kernel/security/lsm # liste "landlock"
grep Seccomp: /proc/<pid-du-plugin>/status # 2 = un filtre seccomp est actif sur le plugin
Une ligne Seccomp: 2 sur un processus de plugin en cours d'exécution confirme que le
filtre noyau est installé. Avec EVEY_PLUGINS_SANDBOX_MODE=landlock et
Landlock non imposé, le plugin refuse de démarrer : c'est le refus par défaut
prévu qui s'applique.
Pour les sauvegardes, les mises à jour et les commandes de récupération, les
pages du conteneur s'appliquent telles quelles :
Sauvegardes et mises à jour, Récupération
et la Ligne de commande décrivent le même binaire
evey admin.