L’authentification PAM fonctionne à la main mais échoue comme service OpenVPN
Une connexion PAM qui fonctionne depuis un shell root et échoue sous systemd désigne l’assistant, pas le mot de passe. Séparez les privilèges, l’accès aux fichiers et SELinux.
L’authentification via PAM peut réussir lorsque vous lancez le client à la main et échouer avec AUTH_FAILED dès que systemd démarre le même profil. Le mot de passe ne change pas entre ces exécutions ; ce qui change, c’est l’ensemble des contraintes autour du processus qui pose la question à PAM. PAM répond via un assistant dont la capacité à modifier ses propres identifiants est exactement ce qu’une unité durcie supprime. Trouvez cet assistant et la frontière dont il a besoin avant de toucher à une liste de capacités.
unix_chkpwd est le binaire qui répond à la question de PAM
Avec l’authentification locale par mot de passe, pam_unix lit rarement le fichier de hachage lui-même. Il exécute unix_chkpwd, que les distributions installent en setuid root ou setgid shadow afin qu’un mot de passe puisse être vérifié au nom d’un processus qui n’a rien à faire en lisant /etc/shadow. Retirez la possibilité d’obtenir cette identité et l’assistant ne peut pas terminer la vérification, donc le module renvoie un simple échec d’authentification.
L’échec ressemble alors à un problème d’identifiants dans chaque journal que le client peut voir. C’est le piège : le client rapporte ce que PAM lui a dit, et PAM rapporte seulement que la pile a dit non. Exécuter l’assistant à la main en root ne prouve rien non plus, car cela exerce un chemin de privilèges que le service n’utilise jamais. Lisez l’unité que systemd a réellement chargée, puis le journal système pour la tentative effectuée. Ces deux vues séparent un problème de bac à sable d’un problème de mot de passe erroné.
Lisez l’unité avant de lire le journal des mots de passe
Une unité empaquetée peut porter un drop-in que vous n’avez pas écrit, et la configuration effective est le résultat fusionné. Affichez l’unité telle que systemd la voit, avec les réglages de bac à sable qui décident si l’assistant peut s’élever lui-même. Une inspection en lecture seule suffit à ce stade.
systemctl cat [email protected]
systemctl show [email protected] -p User -p Group -p CapabilityBoundingSet -p AmbientCapabilities -p NoNewPrivileges
journalctl -u [email protected] -b
La première commande montre d’où viennent l’unité et ses drop-ins, ce qui compte car une surcharge ajoutée il y a des mois survit à la mémoire de sa raison d’être. La seconde affiche les valeurs de bac à sable dont dépendent les deux sections suivantes.
Comparez ce que vous voyez avec un hôte fonctionnel de la même distribution et version. Une différence dans User, CapabilityBoundingSet ou NoNewPrivileges est une piste concrète ; une différence dans les commentaires en prose ne l’est pas. Notez les valeurs avant de changer quoi que ce soit, car une comparaison ultérieure avec une cible mouvante ne prouve rien. Si le service tourne sous un compte non privilégié avec un ensemble bounding vide, l’assistant n’a presque rien avec quoi travailler.
Transformation des identifiants, accès aux fichiers et politique sont trois frontières
Commencez par ce qui se passe pendant exec. Un binaire setuid ou un fichier portant des capacités de fichier déclenche une transformation des identifiants, donc l’identité résultante n’est pas une continuation de l’appelant. L’ensemble bounding plafonne ce qu’un tel binaire peut acquérir, et NoNewPrivileges bloque carrément les gains setuid, setgid et de capacités de fichier. N’importe laquelle de ces trois peut arrêter l’assistant tout en laissant intactes toutes les autres fonctions du service.
Ensuite, séparez le contournement discrétionnaire large de l’accès en lecture étroit. CAP_DAC_OVERRIDE saute les contrôles discrétionnaires presque partout, tandis que CAP_DAC_READ_SEARCH couvre la lecture et le parcours de répertoires avec ses propres pouvoirs supplémentaires. Ce sont des outils différents avec des rayons d’action différents, et aucun n’est une façon d’écrire laisse PAM lire le fichier shadow.
Enfin, demandez si la politique obligatoire autorise l’action tout court. Une capacité Linux ne se substitue pas à SELinux, et en détenir une ne prouve rien sur une règle de type enforcement. Traitez un refus d’accès à un fichier et un refus de capacité comme des preuves différentes, car ils nomment des correctifs différents et souvent des responsables différents. Lisez chaque champ de l’enregistrement plutôt que le seul mot denied. Quel exécutable a agi, dans quel domaine il tournait, quel type de cible il a touché, quelle classe d’objet était impliquée et quelle permission la politique a refusée : chacun resserre la réponse d’une manière différente.
Extrayez le refus du journal d’audit
Sur un hôte en mode appliqué, la trace d’audit est le seul endroit qui enregistre un refus. Interrogez les événements récents et lisez-les par rapport à l’horodatage de la connexion échouée, pas par rapport à l’heure où vous avez commencé à enquêter.
ausearch -m AVC,USER_AVC -ts recent
Un résultat vide n’est pas une preuve d’innocence. Il signifie soit que l’audit ne collecte pas, soit que votre fenêtre a manqué la tentative, et ces deux possibilités doivent être écartées avant d’écarter la politique.
Le guide de dépannage SELinux de Red Hat place les vérifications d’étiquettes et de configuration avant la génération de règles allow, ce qui est aussi le bon ordre pour ce problème. Un assistant mal étiqueté et une lacune de politique produisent des refus similaires mais exigent des réparations différentes. Générer une règle allow pour une erreur d’étiquetage masque le défaut et laisse la mise à jour suivante du paquet le réintroduire. Confirmez l’étiquette de l’assistant installé avant d’écrire la moindre politique.
Prouvez le changement avec une connexion acceptée et une refusée
Ne changez que la frontière que vous avez démontrée, puis testez les deux issues. Un compte qui doit s’authentifier doit réussir, et un compte avec un mauvais mot de passe doit toujours échouer. Un changement qui fait réussir chaque tentative a supprimé l’authentification plutôt que de la réparer.
Effectuez une vraie tentative de connexion et lisez le journal immédiatement après. La ligne qui prouve le correctif est l’entrée pam_unix(openvpn:auth) de cette tentative : elle doit indiquer une authentification réussie, et aucun enregistrement AVC ne doit porter la même seconde.
journalctl -u [email protected] -n 30 --no-pager
ss -tnp | grep openvpn
Un tunnel fonctionnel a aussi besoin d’une reconnexion, car les changements de bac à sable cassent la deuxième connexion plus souvent que la première. Vérifiez la socket établie après la reconnexion et confirmez que la même unité la sert toujours.