Aller au contenu principal

Sécurité de l'agent Navin

Cette page décrit comment l'agent Navin protège l'hôte et son lien avec le Navin Manager. L'agent s'exécute en root car il installe des paquets, des utilisateurs, des unités systemd, des paramètres du noyau et des fichiers de limites ; ces règles bornent ce qu'il peut faire.

Identité et transport​

PropriétéRègle
CléEC P-256, produite sur l'hôte à l'enregistrement, rangée avec sa chaîne de certificats dans agent.pem (0600) ; jamais envoyée
Confiance envers le Managerautorité épinglée par son sha256 (--ca-sha256) ; une autre autorité arrête l'enregistrement avec ca_mismatch ; une adresse sans https est refusée avec insecure_server (http seulement vers cet hôte), le jeton d'amorçage ne traverse donc jamais un réseau en clair
TransportTLS mutuel sur le port 8461 avec le certificat client émis par l'autorité interne
Signature des requêtesNM-HMAC <host_id>:<ts>:<hmac>, HMAC-SHA256 avec le secret de l'agent ; 300 secondes d'écart au plus
RenouvellementPOST /agent/v1/renew avec une nouvelle demande de certificat ; le certificat précédent est révoqué
RévocationHôtes > Agents de nœud > Révoquer : TLS mutuel direct, API et miroir refusés ; connexions existantes fermées au rafraîchissement de révocation
Jeton d'amorçageutilisable un nombre donné de fois pendant une durée donnée ; enroll.env est supprimé après l'enregistrement

Identité client atomique​

Contrat mis à jour le 04/11/2026 pour les sources 1.0.2 actuelles. La version affichée ne suffit pas à prouver cette compatibilité : des builds antérieurs de même version peuvent encore utiliser deux fichiers.

Les agents Go et Python partagent state_dir/agent.pem : chaîne de certificats, puis clé privée non chiffrée, 64 Kio au maximum, fichier régulier privé de mode 0600. Enregistrement et renouvellement valident la paire, écrivent un fichier temporaire privé dans le même répertoire, le synchronisent, le renomment une seule fois, puis synchronisent le répertoire. TLS et pip utilisent un instantané validé. Une connexion TLS déjà établie peut conserver l'ancienne identité jusqu'à sa reconnexion.

  • Mise à niveau : tant que agent.pem est absent, les agents actuels acceptent l'ancienne paire agent.crt et agent.key. L'enregistrement ou le renouvellement réussi publie le nouveau fichier. Aucune migration de base ni conversion manuelle n'est nécessaire dans ce sens. Les tests locaux n'ont migré aucun hôte réel.
  • Refus : si agent.pem existe mais est illisible, mal formé, incohérent, trop grand, accessible au groupe ou aux autres utilisateurs, un lien symbolique ou un fichier non régulier, il est refusé sans retour aux anciens fichiers. Une identité corrompue peut nécessiter une récupération ou un nouvel enrôlement ; supprimer le bundle pour forcer le retour à l'ancienne paire n'est pas une réparation sûre.
  • Ancien binaire et outils externes : les deux anciens fichiers ne sont volontairement plus actualisés. Avant un retour à un ancien binaire ou à un outil exigeant ces chemins, arrêter tous les lecteurs et écrivains, conserver une copie protégée du bundle faisant autorité, puis faire exporter par un opérateur autorisé sa chaîne et sa clé correspondante dans des fichiers protégés. Vérifier la paire et la confiance actuelle du Manager avant redémarrage. Cet export à deux fichiers n'est pas atomique à chaud et n'est pas une fonction de rollback automatique. Préférer un binaire compatible ou un réenrôlement contrôlé.
  • Limites : le répertoire d'état et ses parents doivent rester de confiance. Un échec de synchronisation après renommage peut signaler une erreur alors que le nouveau fichier complet est déjà visible. Les tests locaux ne certifient ni la coupure électrique ni la rotation en production. Le retrait efface les identités nouvelles et anciennes.

Révocation TLS directe et protocole de livraison 2​

Mise à jour du 04/11/2026 pour les sources actuelles. Utiliser le lanceur livré navin-manager serve, pas un serveur ASGI générique : la production refuse les requêtes hors du transport vérifié. Aucun en-tête de proxy ne peut remplacer le certificat pair. L'identité du certificat doit correspondre à l'hôte HMAC pour l'API ; le miroir exige aussi un agent connu et non révoqué, vérifié dans la base.

Le transport prépare un nouveau contexte CA/CRL toutes les 5 secondes. Échec de rafraîchissement, CRL expirée ou instantané âgé de plus de 15 secondes : nouveaux handshakes refusés et connexions agents existantes fermées. Les connexions révoquées sont fermées au rafraîchissement suivant ; les requêtes sont également vérifiées en base. Ces intervalles sont des budgets de surveillance, pas une borne absolue si l'OS ou la boucle événementielle se bloque. La révocation n'annule pas une réponse ou un effet déjà accepté.

Le protocole 2 exige la capacité delivery_protocols: [2], une enveloppe signée, un token de tentative et son SHA256 complet. L'ACK précède la persistance de started et l'effet ; journaux et résultats sont liés à la tentative. Un ACK perdu peut être retenté avant exécution, un reçu terminal peut être renvoyé, et un effet commencé sans reçu reste indéterminé. Ne pas supprimer les journaux ni rejouer une tâche incertaine sous un nouvel identifiant. Les journaux de livraison Go et Python ont des formats distincts : changer d'implémentation avec du travail en cours ou non acquitté n'est pas pris en charge.

V093 (générations scheduler) et V094 (protocole 2) exigent une maintenance coordonnée : anciennes répliques Manager arrêtées et binaires agents mis à niveau. Les anciens clients de livraison sont refusés, pas acceptés silencieusement. Ces changements de sources et leurs tests n'ont migré aucun environnement client. Voir le contrat exact du protocole (navin-manager/CONTRACT.md).

Limites d'exécution​

  • Aucun shell distant. command.run, les contrôles de santé command, preflight.run, smoke.run et le pilote process ne lancent qu'un programme absolu listé dans allowed_commands ou dont le chemin réel se trouve dans les racines autorisées, à partir de sa liste d'arguments. /bin/sh -c ... est refusé avec command_not_allowed.
  • Garde des chemins. Chaque chemin écrit se trouve sous une racine autorisée (allowed_roots, par défaut /etc/navin, /opt/navin, /var/lib/navin, /var/log/navin, /run/navin, /etc/systemd/system/navin-*, /etc/sysctl.d/90-navin-*, /etc/security/limits.d/90-navin-*, /etc/containers/systemd/navin-*). Un chemin comportant un lien symbolique, un composant .. ou situé hors de toute racine échoue avec path_not_allowed.
  • Archives. Les noms absolus, .., les périphériques, les FIFO et les liens qui sortent de la destination sont refusés avec archive_unsafe avant toute écriture ; un contenu déclaré au-delà de 200 000 entrées ou de 64 Gio échoue avec archive_too_large, au-delà de l'espace libre moins 1 Gio avec disk_space_low.
  • Téléchargements. Un fichier n'est utilisé qu'après vérification de son sha256 ; sinon checksum_mismatch. Un téléchargement s'arrête au-delà de 64 Gio (download_too_large) ou quand il resterait moins de 1 Gio libre (disk_space_low).
  • Secrets. Les valeurs de sensitive_env, les secrets des tests fonctionnels et les clés des certificats sont remplacés par ****** dans chaque ligne de journal et chaque résultat. Le contenu des tâches est scellé dans la base du Manager.

Durcissement de l'unité​

navin-manager-agent.service garde un durcissement compatible avec dnf, apt, podman et systemctl : ProtectHome=read-only, PrivateTmp=yes, ProtectKernelModules=yes, ProtectKernelLogs=yes, ProtectClock=yes, ProtectHostname=yes, RestrictRealtime=yes, LockPersonality=yes, KeyringMode=private, RestrictAddressFamilies=AF_UNIX AF_INET AF_INET6 AF_NETLINK, SystemCallArchitectures=native, UMask=0027.

Liste de contrôle​

ContrôleCommande
Répertoire d'état privéstat -c '%a %U' /var/lib/navin-manager-agent affiche 700 root
enroll.env supprimé après l'enregistrementtest ! -e /etc/navin-manager-agent/enroll.env
Commandes limitéesallowed_commands d'agent.json ne contient que les programmes absolus attendus
Manager en productionnavin-manager check réussit (certificats clients exigés)
attention

Ajouter un répertoire large comme /usr/bin à allowed_roots, ou un shell à allowed_commands, permet au Manager de lancer n'importe quel programme de ce répertoire en root sur l'hôte.