Après la baisse des privilèges : quels fichiers OpenVPN fonctionnent encore ?
Les descripteurs ouverts avant la baisse continuent de fonctionner ; les chemins rouverts ensuite non. Décidez lequel des trois fichiers d’exécution votre configuration doit rouvrir.
Une longue durée de fonctionnement prouve seulement que le démarrage a réussi avec les privilèges que le démon possédait à cet instant. Les défaillances qui comptent ici arrivent plus tard : un nouveau client se connecte, une liste de révocation est remplacée, un script auxiliaire doit écrire un fichier. Chacune est une ouverture nouvelle effectuée par le compte non privilégié, avec sa propre question de permissions et son propre message d’erreur. Trois décisions séparent une configuration qui continue de fonctionner d’une qui échoue au prochain événement.
Séparez ce qui a été chargé tôt de ce qui est ouvert plus tard
Un descripteur est une poignée sur une description de fichier ouverte, et le mode d’accès a été fixé lors de la création de cette description. Changer l’utilisateur du processus ensuite ne ferme pas la poignée, ce qui explique qu’un fichier de clé lu en root continue de fonctionner après la baisse. Le mode ne change pas non plus : une poignée ouverte en lecture ne devient pas inscriptible, et une poignée inscriptible n’est pas révoquée simplement parce que le compte a perdu ses droits sur le chemin. Ces deux faits expliquent l’essentiel du comportement surprenant de ces rapports.
L’autre moitié est la mémoire. Un démon peut analyser un certificat, conserver la matière analysée et fermer le fichier ; ce qui reste utilisé est une donnée, pas un fichier ouvert. Le trafic continu ne prouve donc ni qu’un descripteur est ouvert, ni que le nom de chemin est atteignable. Il prouve que la matière nécessaire à la session courante a été obtenue plus tôt.
Une ouverture ultérieure est une autre transaction. Elle s’exécute avec les identifiants courants, le contexte de sécurité courant et la vue de montage courante, si bien qu’un chemin lisible au démarrage peut être refusé à la connexion suivante. La rotation ajoute un piège : écrire un nouveau fichier sur le même nom de chemin laisse un descripteur existant attaché à l’ancien objet, si bien qu’un rechargement peut sembler réussir alors que le démon utilise encore le contenu précédent. Comparez l’inode détenu par le processus avec celui du disque avant de croire à une rotation.
Nommez les trois lectures d’exécution et le moment de chacune
Trois ressources sont normalement ouvertes bien après l’initialisation, et elles échouent à des moments différents. Un fichier de configuration propre à un client est lu lorsque ce client se connecte, il peut donc casser pour un utilisateur tandis que les autres continuent. Les données de révocation sont consultées pendant l’authentification du pair et de nouveau lorsque le fichier est remplacé. Un répertoire temporaire n’est touché que lorsqu’un script ou un greffon écrit quelque chose.
Aucune des trois n’appartient au chemin de démarrage, ce qui explique qu’un serveur sain pendant des semaines puisse échouer à la connexion suivante. La catégorie nomme aussi le propriétaire du correctif : les deux premières sont des droits de lecture sur la configuration sous le compte du démon, et la troisième est un emplacement inscriptible à l’usage étroit.
| Path reopened later | What triggers the open | First sign when it fails |
|---|---|---|
| Client configuration file | A connection for that client identity | One client rejected while others connect |
| Revocation data | Peer authentication, including after replacement | Revoked and valid peers both refused |
| Script or plugin temporary directory | A helper needs to create a file | The helper exits with a path error |
persist-key répond à une question plus étroite qu’on ne le suppose. Il garde le fichier de clé ouvert pendant les réinitialisations documentées SIGUSR1 et ping-restart, et il ne fait rien pour les fichiers CCD, les données de révocation, les exécutables auxiliaires ou un redémarrage complet du processus. Ceux-ci suivent toujours leurs propres chemins d’ouverture, sous le compte qui tourne à ce moment-là.
Confirmez le compte et la vue qu’il a réellement
Demandez au démon en cours quel compte il utilise au lieu de faire confiance au fichier d’unité, puis comparez la réponse avec ce que l’unité définit. Un écart est la première chose à résoudre, car chaque vérification de permissions ultérieure s’exécute comme celui que le processus est réellement. Parcourez ensuite le chemin composant par composant ; la traversée est évaluée à chaque niveau, donc un fichier lisible dans un répertoire non traversable reste illisible. Le mode final du fichier est la dernière question, pas la première.
Les espaces de noms et les bacs à sable de service ajoutent des frontières que la propriété et les bits de mode ne décrivent pas. Un chemin visible dans votre shell peut être absent ou en lecture seule dans un chroot, un espace de noms de montage ou une unité qui masque les répertoires personnels. Les modules de sécurité ajoutent une couche de plus, si bien qu’un fichier qui semble lisible peut encore être refusé à l’ouverture.
ps -o user:12,pid,args -C openvpn
systemctl show -p User -p Group -p ProtectHome -p RootDirectory [email protected]
sudo -u openvpn namei -l /etc/openvpn/ccd/aliceUne lecture réussie dans le shell de l’administrateur ne teste aucune de ces conditions combinées. Exécutez la vérification avec le compte du démon, avec le même espace de noms et le même bac à sable, ou acceptez que le résultat décrive votre shell et non le serveur. La troisième commande est la version bon marché de ce test : elle affiche le mode de chaque composant et échoue au premier que le compte du démon ne peut pas traverser.
Accordez l’écriture d’exécution dans un répertoire dédié
La lecture n’est que la moitié de l’inventaire. Un script auxiliaire peut avoir besoin de créer un fichier d’état, un greffon peut avoir besoin d’écrire un état à côté de sa configuration, et ces écritures ne sont pas couvertes par le fait de rendre l’arbre de configuration inscriptible. Donnez au répertoire concerné le droit d’écriture que sa fonction exige, avec un propriétaire et un mode que vous pouvez expliquer. Préférez l’accès en lecture seule pour tout ce qui n’est que lu.
Gardez les permissions de la clé privée séparées des fichiers de politique. Une clé qui doit être relue après une réinitialisation a une exigence différente d’un fichier client lu à chaque connexion, et un seul mode permissif pour les deux accorde plus d’accès que le problème ne le demande. Un compte de démon dédié à propriété étroite est plus facile à auditer qu’un groupe large. Lorsque la clé doit survivre aux réinitialisations, persist-key supprime la relecture au lieu d’élargir le répertoire.
Décidez à partir de l’événement que vous pouvez reproduire
Un tunnel actif prouve un seul chemin dans le code. L’événement qui a besoin du fichier est le seul test qui couvre l’ouverture qui vous intéresse, qu’il s’agisse d’une nouvelle connexion client, d’un fichier de révocation remplacé, d’une réinitialisation douce autorisée ou d’un redémarrage planifié. Choisissez l’événement, exécutez-le et gardez la première erreur plutôt que la dernière.
Pour une réinitialisation douce, un signal et le journal de l’unité montrent si la clé a été relue. Envoyez le signal, puis lisez les dernières lignes écrites par l’unité :
systemctl kill -s SIGUSR1 [email protected]
journalctl -u [email protected] -n 40 --no-pagerNe concluez pas qu’un démon compromis ne peut plus modifier de fichiers simplement parce que les privilèges ont été abaissés. Ce qu’il peut encore dépend de ses identifiants restants, de ses capacités, des répertoires où il peut écrire et de tout descripteur inscriptible qu’il détient encore. La réduction des privilèges resserre l’autorité, et l’inventaire des ouvertures d’exécution montre jusqu’où. Écrivez cette frontière à côté de la configuration pour que la personne suivante n’ait pas à la redécouvrir.