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 install

Aprè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/testfile

Le 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/encfs

Notez 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.so

Pam_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/onsessionopen

  • onsessionclose=/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.so

Comme 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.so

Les 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.conf

Maintenant, 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.2

où 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/network

lors que je suis connecté en tant que moi-même (sbon). Le répertoire /home/sbon/network doit exister.

Share: X/Twitter LinkedIn

Recevez de nouveaux articles dans votre boîte de réception.

Aucun spam. Désabonnez-vous à tout moment.