Sécurité · 12 min read · Jan 10, 2026
Créer un répertoire sécurisé avec PAM et EncFS
Créer un répertoire sécurisé avec PAM et EncFS
Contenu
. Introduction
. Installation d’encfs
. Installation de pam_script
. Ajustement de la configuration PAM
. Le résultat
Introduction
Je travaille beaucoup avec des programmes qui nécessitent des identifiants.
Exemples de ces programmes :
. mount.cifs
. fusesmb (voir les détails ici)
Maintenant, dans mon réseau (et d’autres), les identifiants fournis lors de la connexion pourraient (et devraient) être utilisés par ces programmes. Comment pouvez-vous récupérer ces identifiants, tout en fournissant suffisamment de sécurité ?
Avec le module PAM pam_script, il est possible de stocker le mot de passe dans un fichier, qui sera utilisé par fusesmb et mount.cifs pour lire le mot de passe.
Pour atteindre la sécurité, on pourrait faire en sorte que l’utilisateur se connectant soit le propriétaire et interdire la lecture/écriture à quiconque d’autre. Supprimez ce fichier lorsque l’utilisateur termine sa session.
C’est suffisant, pour le temps d’exécution. Mais je me demandais, que se passe-t-il si le système plante et que le fichier contenant les identifiants reste sur le disque dur ? Quiconque capable de monter ce disque dur avec par exemple un lifecd peut lire ce fichier !
C’est pourquoi je cherchais un moyen de chiffrer ce fichier.
Avec encfs, c’est très possible ! Au moment de l’exécution, il fournit une interface pour des fichiers et répertoires chiffrés, qui n’existent qu’au moment de l’exécution ! Lorsque le système n’est pas en marche, il n’y a que des fichiers chiffrés, inutiles si vous ne connaissez pas la clé. Et cette clé est exactement le mot de passe (chiffré) ! C’est pourquoi j’ai choisi une combinaison de PAM et Encfs.
Consultez le site Web d’Encfs : http://freshmeat.net/projects/encfs
Cette construction est destinée à offrir une sécurité suffisante pour le temps d’exécution et d’arrêt (après un crash) pour stocker des informations sensibles, et non pour créer un répertoire sécurisé permanent sur votre disque dur pour stocker des documents.
Installation d’encfs
Bien sûr, FUSE doit être installé.
L’installation est très simple :
(regardez le site Web pour rlog qui est requis par EncFs)
tar -xzf encfs-*.tar.gz
cd encfs-*
configure --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/sbin
make
make installAprès l’installation, vous pouvez tester si cela fonctionne :
mkdir -p ~/test/encrypted
mkdir -p ~/test/decrypted
encfs ~/test/encrypted ~/test/decrypted
mount (devrait montrer le montage juste créé)
echo "Ceci est très secret." > ~/test/decrypted/testfileLe répertoire encrypted contient les fichiers chiffrés et reste sur le disque dur après le démontage et/ou l’arrêt. Le répertoire decrypted est l’interface, et disparaît lorsqu’il est démonté et/ou arrêté.
Le fichier testfile devrait apparaître dans le répertoire déchiffré, et sous forme chiffrée dans le répertoire chiffré. Le nom et le contenu du fichier sont chiffrés.
J’ai choisi un répertoire séparé sur la machine locale où pour chaque utilisateur se connectant, un répertoire chiffré (et une interface à celui-ci) sera stocké :
install -m777 -o root -g root /var/lib/encfsNotez les permissions : tout le monde doit pouvoir créer un répertoire ici. Plus loin dans ce document, il est expliqué pourquoi.
Installation de pam_script
L’installation est très simple. Après une commande make, déplacez la bibliothèque dans le répertoire approprié, /lib/security.
tar -xzf pam-script-*.tar.gz
cd pam-script-*
make
mv pam_script.so /lib/security
chown root:root /lib/security/pam_script.so
chmod 755 /lib/security/pam_script.soPam_script.so utilise certains paramètres. Tous sont décrits dans le README dans le répertoire source. Les plus importants sont :
paramètres communs
- runas=#user# : fait en sorte que le script appelé s’exécute en tant qu’utilisateur #user#
paramètres uniquement dans la partie auth
- onauth=/path/to/onauth/script : chemin vers le script qui est exécuté lors de la partie auth
par défaut c’est /etc/security/onauth
uniquement dans la partie session
onsessionopen=/path/to/onsessionopen/script : chemin vers le script qui est exécuté lorsqu’une session (valide) est ouverte
par défaut c’est /etc/security/onsessionopenonsessionclose=/path/to/onsessionclose/script : chemin vers le script qui est exécuté lorsqu’une session est fermée
par défaut c’est /etc/security/onsessionclose
Après l’installation, la chose la plus complexe est de configurer le système pour utiliser ce module.
Ajustement de la configuration PAM
J’ai utilisé pam_script dans la partie auth et dans la partie session du fichier de service pam (login,kde).
D’abord, je décris comment ajuster la partie auth, où pam_script est utilisé plus d’une fois.
La partie auth
Pam_script a la capacité (à partir de la version 0.1.5) d’obtenir le mot de passe fourni lors de la connexion et de le rendre disponible aux scripts via une variable d’environnement PAM_AUTHTOK.
Le but ici est de créer un répertoire sécurisé où des informations confidentielles (comme des identifiants) sont stockées.
Le module est empilé dans la partie auth :
cat /etc/pam.d/login-- snip --
auth required pam_shells.so
auth required pam_script.so expose=1
auth sufficient pam_unix.so use_first_pass
auth sufficient pam_ldap.so use_first_pass
auth required pam_script.so onauth=/etc/security/onauth.failed
auth required pam_deny.soComme vous pouvez le voir, j’utilise pam_scripts.so plusieurs fois :
La première fois pour exécuter un script qui crée un répertoire chiffré (avec encfs) et pour écrire le mot de passe secret dans un fichier dans ce répertoire pour une utilisation par des programmes sensibles aux identifiants comme fusesmb et mount.cifs. Cela se fait juste avant le premier module d’authentification suivant, pam_unix.
La dernière fois pour exécuter un script lorsque l’authentification n’est pas réussie. Lorsque les modules d’authentification précédents échouent (pam_unix et pam_ldap) (et seulement alors), ce module est atteint. Il est nécessaire de démonter le répertoire chiffré et de supprimer les fichiers temporaires.
Notez que le dernier module de tous est pam_deny, qui est vraiment nécessaire. Sans lui, tout le monde peut se connecter. C’est parce que pam_script renvoie toujours “PAM_SUCCESS”, peu importe la valeur de retour des scripts.
N’oubliez pas d’ajouter le drapeau “use_first_pass” au module existant pam_unix.so.
Les scripts
cat /etc/security/onauth#!/bin/bash
retcode=0;
userid=$1
service=$2
authtok=$3
if [ -z "$authtok" ]; then
authtok=$PAM_AUTHTOK
fi;
userproperties=$(getent passwd | grep -m 1 -E "^$userid")
if [ -z "$userproperties" ]; then
#
# userproperties non trouvé : quelque chose ne va pas
#
echo "Utilisateur non trouvé."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
if [ -d /var/lib/encfs ]; then
# créer un sécurisé
if [ ! -d /var/lib/encfs/$userid ]; then
install -m700 -o $uidnr -g $gidnr -d /var/lib/encfs/$userid
fi;
if [ ! -d /var/lib/encfs/$userid/encrypted ]; then
install -m700 -o $uidnr -g $gidnr -d /var/lib/encfs/$userid/encrypted
fi;
if [ ! -d /var/lib/encfs/$userid/unencrypted ]; then
install -m700 -o $uidnr -g $gidnr -d /var/lib/encfs/$userid/unencrypted
fi;
if [ ! -d /var/lib/encfs/$userid/run ]; then
install -m700 -o $uidnr -g $gidnr -d /var/lib/encfs/$userid/run
fi;
#
# testez si le répertoire chiffré n'est pas déjà monté
#
if [ -z "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
#
# créer un programme de fourniture de mot de passe
#
cd /var/lib/encfs/$userid
md5authsum=$(echo $authtok | md5sum | cut -d " " -f 1)
echo "$md5authsum" > run/tmp
echo "$md5authsum" >> run/tmp
chown $uidnr:$gidnr run/tmp
rm -rf encrypted/*
rm -f encrypted/.encfs*
cat run/tmp | encfs -S /var/lib/encfs/$userid/encrypted /var/lib/encfs/$userid/unencrypted -- -o allow_root 1>>/dev/null
fi;
#
# c'est de cela qu'il s'agit : stocker les identifiants dans un fichier
# dans ce cas le mot de passe
#
if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
cd /var/lib/encfs/$userid/unencrypted/
if [ -f password.tmp ]; then
rm password.tmp
fi;
echo $authtok > password.tmp
fi;
fi;
Quelques remarques :
Ce script crée un répertoire chiffré (s’il n’existe pas déjà) avec encfs. Notez l’option -S à encfs : le mot de passe pour ce répertoire chiffré est lu depuis stdin et non demandé.
Ce mot de passe est le même que celui utilisé lors de la connexion.
Le répertoire chiffré est à /var/lib/encfs/$userid.
Le mot de passe est écrit dans un fichier, password.tmp. C’est un fichier temporaire : le mot de passe n’a pas besoin d’être le bon. Plus tard dans le processus, en fonction du succès de la validation, ce fichier est renommé (en password) ou supprimé.
Il est très important de noter que le script est exécuté en tant qu’utilisateur se connectant, et non en tant que root ! Et parce que des programmes comme mount.cifs ont besoin d’accéder à ce répertoire pour lire le fichier de mot de passe, l’option fuse commune allow_root est ajoutée.
#!/bin/bash
userid=$1
service=$2
userproperties=$(getent passwd | grep -m 1 -E "^$userid")
if [ -z "$userproperties" ]; then
#
# userproperties non trouvé : quelque chose ne va pas
#
echo "Utilisateur non trouvé."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
#
# ce script est exécuté lorsque l'authentification a échoué
# un sécurisé chiffré est toujours créé
# donc il est important de supprimer ce sécurisé à nouveau
#
if [ -d /var/lib/encfs ]; then
if [ -d /var/lib/encfs/$userid/unencrypted ]; then
#
# testez si le répertoire chiffré est déjà monté
#
if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
if [ $(w -h $userid | wc -l) -eq 0 ]; then
#
# cet utilisateur n'est pas connecté sur plus de tty's
# juste supprimer tout et démonter le répertoire chiffré
#
rm -rf /var/lib/encfs/$userid/unencrypted/*
fusermount -u /var/lib/encfs/$userid/unencrypted
rm -rf /var/lib/encfs/$userid/encrypted/*
rm -f /var/lib/encfs/$userid/encrypted/.encfs*
else
#
# cet utilisateur est toujours connecté
#
rm -f /var/lib/encfs/$userid/unencrypted/password.tmp
fi;
fi;
if [ -z "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
rm -rf /var/lib/encfs/$userid/encrypted/*
rm -f /var/lib/encfs/$userid/encrypted/.encfs*
rm -rf /var/lib/encfs/$userid/unencrypted/*
fi;
fi;
fi;
Quelques remarques :
Ce script est exécuté lorsque les identifiants fournis ne sont pas valides. Le répertoire chiffré, qui vient d’être configuré, sera supprimé (démonté) à nouveau et vidé. Cela ne se produit que lorsque cet utilisateur n’est pas connecté sur un autre tty.
La partie session
Lorsque la partie session est atteinte, il est certain que les identifiants fournis (mot de passe) sont corrects. Cela signifie que le mot de passe - dans la phase d’authentification stocké dans un fichier temporaire - est correct. Donc une chose à faire dans la phase de session est de déplacer le contenu de password.tmp vers le permanent, password.
Une seconde chose est d’exécuter des scripts qui ont besoin de ces identifiants pour leur propre usage, comme le montage de partages CIFS ou fusesmb.
Il est logique que toute information confidentielle reste à l’intérieur du répertoire sécurisé. C’est de cela qu’il s’agissait au départ !!
Notez que ce module exécute deux scripts par défaut :
. /etc/security/onsessionopen : lorsque une session commence/s’ouvre ;
. /etc/security/onsessionclose : lorsque une session se termine/se ferme.
Je suis le défaut, il n’y a aucune raison de faire autrement.
Mon fichier /etc/pam.d/login (la partie session) ressemble à :
cat /etc/pam.d/login-- snip --
session required pam_mkhomedir.so
session required pam_motd.so
session optional pam_mail.so empty dir=/var/mail
session optional pam_lastlog.so
session required pam_env.so
session required pam_script.so
session required pam_unix.so
session required pam_ldap.soLes scripts
À l’ouverture de session
cat /etc/security/onsessionopen#!/bin/bash
retcode=0;
userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid")
if [ -z "$userproperties" ]; then
#
# userproperties non trouvé : quelque chose ne va pas
#
echo "Utilisateur non trouvé."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
if [ -d /var/lib/encfs/$userid/encrypted ]; then
#
# testez si le répertoire chiffré est monté
#
if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
if [ -f /var/lib/encfs/$userid/unencrypted/password.tmp ]; then
if [ -f /var/lib/encfs/$userid/unencrypted/password ]; then
#
# un ancien fichier de mot de passe trouvé
#
if [ -z "(diff /var/lib/encfs/$userid/unencrypted/password /var/lib/encfs/$userid/unencrypted/password.tmp)" ]; then
#
# nouveau mot de passe et ancien sont les mêmes
#
rm /var/lib/encfs/$userid/unencrypted/password.tmp
else
mv /var/lib/encfs/$userid/unencrypted/password.tmp /var/lib/encfs/$userid/unencrypted/password
fi;
else
#
# mot de passe non trouvé : c'est la première connexion.
# juste déplacer le fichier de mot de passe temporaire vers le restant
#
mv /var/lib/encfs/$userid/unencrypted/password.tmp /var/lib/encfs/$userid/unencrypted/password
fi;
fi;
if [ -d /etc/session.d/pam/onsessionopen ]; then
for script in /etc/session.d/pam/onsessionopen/*.sh; do
if [ -x $script ]; then
eval $script $userid $service
fi
done;
fi;
fi;
fi;
À la fermeture de session
cat >> /etc/security/onsessionclose#!/bin/bash
userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid")
if [ -z "$userproperties" ]; then
#
# userproperties non trouvé : quelque chose ne va pas
#
echo "Utilisateur non trouvé."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
#
# ce script est exécuté lorsque l'authentification a échoué
# un sécurisé chiffré est toujours créé
# donc il est important de supprimer ce sécurisé à nouveau
#
if [ -d /var/lib/encfs ]; then
if [ -d /var/lib/encfs/$userid/unencrypted ]; then
#
# testez si le répertoire chiffré est déjà monté
#
if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
if [ $(w -h $userid | wc -l) -eq 0 ]; then
rm -rf /var/lib/encfs/$service.$userid/unencrypted/*
fusermount -u /var/lib/encfs/$userid/unencrypted
rm -rf /var/lib/encfs/$userid/encrypted/*
rm -f /var/lib/encfs/$userid/encrypted/.encfs*
fi;
else
rm -rf /var/lib/encfs/$userid/encrypted/*
fi;
if [ -d /etc/session.d/pam/onsessionclose ]; then
for script in /etc/session.d/pam/onsessionclose/*.sh; do
if [ -x $script ]; then
eval $script $userid $service
fi
done;
fi;
fi;
fi;Quelques remarques :
. important : les premières versions de shadow (où le programme de connexion fait partie) ne fermaient pas les sessions par défaut (versions antérieures à 4.0.12). Vous devrez ajouter :
CLOSE_SESSIONS yesà /etc/login.defs.
Cette option n’est pas documentée et n’est pas présente dans le fichier login.defs installé par le package Shadow. Vous devrez l’ajouter vous-même.
Dans les versions plus récentes, cette option a été supprimée : la session est toujours fermée.
Le résultat
Le répertoire chiffré contient maintenant les identifiants, qui ne sont disponibles que pour le propriétaire et root. En créant un fichier mount.cifs.conf avec ces valeurs :
touch /var/lib/encfs/$userid/unencrypted/mount.cifs.conf
chmod 600 /var/lib/encfs/$userid/unencrypted/mount.cifs.conf
echo "username=$userid" > /var/lib/encfs/$userid/unencrypted/mount.cifs.conf
echo -n "password=" >> /var/lib/encfs/$userid/unencrypted/mount.cifs.conf
cat /var/lib/encfs/$userid/unencrypted/password >> /var/lib/encfs/$userid/unencrypted/mount.cifs.confMaintenant, le montage d’un partage cifs est possible avec :
/sbin/mount.cifs //fileserver/public /home/sbon/netshares/fileserver/public -o credentails=/var/lib/encfs/sbon/unencrypted/mount.cifs.conf,ip=192.168.0.2où le répertoire /home/sbon/netshares/fileserver/public existe, et il y a un partage “public” disponible sur “fileserver”, un serveur smb/cifs avec le numéro ip 192.168.0.2.
Cette commande doit être exécutée en tant que root. Root doit avoir accès au répertoire chiffré.
Un autre exemple est fusesmb, qui peut utiliser des identifiants pour parcourir le voisinage réseau smb. Cela ne se fait pas en créant un fichier séparé pour les identifiants uniquement, mais dans le fichier de configuration global par utilisateur de fusesmb dans ~/.smb/fusesmb.conf :
(ici je crée un simple fichier de configuration avec uniquement des identifiants)
touch /var/lib/encfs/sbon/unencrypted/fusesmb.conf
chmod 600 /var/lib/encfs/sbon/unencrypted/fusesmb.conf
echo "[global]" > /var/lib/encfs/sbon/unencrypted/fusesmb.conf
echo "username = sbon" >> /var/lib/encfs/sbon/unencrypted/fusesmb.conf
echo -n "password = " >> /var/lib/encfs/sbon/unencrypted/fusesmb.conf
cat /var/lib/encfs/sbon/unencrypted/password >> /var/lib/encfs/sbon/unencrypted/fusesmb.conf
ln -sf /var/lib/encfs/sbon/unencrypted/fusesmb.conf /home/sbon/.smb/fusesmb.conf Le dernier lien est parce que fusesmb (démarré par sbon) s’attend à ce que le fichier de configuration soit là.
Maintenant, démarrez-le avec :
fusesmb /home/sbon/networklors que je suis connecté en tant que moi-même (sbon). Le répertoire /home/sbon/network doit exister.
Recevez de nouveaux articles dans votre boîte de réception.
Aucun spam. Désabonnez-vous à tout moment.