Sicherheit · 11 min read · Jan 10, 2026
Erstellen eines sicheren Verzeichnisses mit PAM und EncFS
Erstellen eines sicheren Verzeichnisses mit PAM und EncFS
Inhalte
. Einführung
. Installation von encfs
. Installation von pam_script
. Anpassen der PAM-Konfiguration
. Das Ergebnis
Einführung
Ich arbeite viel mit Programmen, die Anmeldeinformationen erfordern.
Beispiele für diese Programme sind:
. mount.cifs
. fusesmb (Details hier)
Jetzt könnten (und sollten) in meinem Netzwerk (und anderen) die bei der Anmeldung bereitgestellten Anmeldeinformationen von diesen Programmen verwendet werden. Wie kann man diese Anmeldeinformationen abrufen und dabei genügend Sicherheit bieten?
Mit dem PAM-Modul pam_script ist es möglich, das Passwort in einer Datei zu speichern, die von fusemb und mount.cifs zum Lesen des Passworts verwendet wird.
Um Sicherheit zu erreichen, könnte man den Benutzer, der sich anmeldet, zum Eigentümer machen und das Lesen/Schreiben für alle anderen verweigern. Entfernen Sie diese Datei, wenn der Benutzer seine Sitzung beendet.
Das ist genug für die Laufzeit. Aber ich habe mich gefragt, was passiert, wenn das System abstürzt und die Datei mit den Anmeldeinformationen auf der Festplatte bleibt? Jeder, der in der Lage ist, diese Festplatte mit beispielsweise einem Lifecd zu mounten, kann diese Datei lesen!
Deshalb habe ich nach einer Möglichkeit gesucht, diese Datei zu verschlüsseln.
Mit encfs ist das sehr gut möglich! Zur Laufzeit bietet es eine Schnittstelle zu verschlüsselten Dateien und Verzeichnissen, die nur zur Laufzeit existiert! Wenn das System nicht läuft, gibt es nur verschlüsselte Dateien, die nutzlos sind, wenn man den Schlüssel dafür nicht kennt. Und dieser Schlüssel ist genau das (verschlüsselte) Passwort! Deshalb habe ich mich für eine Kombination aus PAM und Encfs entschieden.
Schauen Sie sich die Website von Encfs an: http://freshmeat.net/projects/encfs
Diese Konstruktion soll genügend Sicherheit für die Lauf- und Ausfallzeit (nach einem Absturz) bieten, um sensible Informationen zu speichern, nicht um ein dauerhaft sicheres Verzeichnis auf Ihrer Festplatte zu erstellen, um Dokumente zu speichern.
Installation von encfs
Natürlich sollte FUSE installiert sein.
Die Installation ist sehr einfach:
(siehe die Website für rlog, das von EncFs benötigt wird)
tar -xzf encfs-*.tar.gz
cd encfs-*
configure --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/sbin
make
make installNach der Installation können Sie testen, ob es funktioniert:
mkdir -p ~/test/encrypted
mkdir -p ~/test/decrypted
encfs ~/test/encrypted ~/test/decrypted
mount (sollte das gerade erstellte Mount anzeigen)
echo "Das ist sehr geheim." > ~/test/decrypted/testfileDas Verzeichnis encrypted enthält die verschlüsselten Dateien und bleibt auf der Festplatte nach dem Unmounten und/oder Herunterfahren. Das Verzeichnis decrypted ist die Schnittstelle dazu und verschwindet beim Unmounten und/oder Herunterfahren.
Die Datei testfile sollte im entschlüsselten Verzeichnis erscheinen und in verschlüsselter Form im verschlüsselten Verzeichnis. Name und Inhalt der Datei sind verschlüsselt.
Ich habe mich für einen separaten Ordner auf der lokalen Maschine entschieden, in dem für jeden Benutzer, der sich anmeldet, ein verschlüsseltes (und eine Schnittstelle dazu) gespeichert wird:
install -m777 -o root -g root /var/lib/encfsBeachten Sie die Berechtigungen: Jeder muss hier ein Verzeichnis erstellen können. Später in diesem Dokument wird erklärt, warum.
Installation von pam_script
Die Installation ist sehr einfach. Nach einem make-Befehl verschieben Sie die Bibliothek in das richtige Verzeichnis, /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 verwendet einige Parameter. Alle sind im README im Quellverzeichnis beschrieben. Wichtig sind:
allgemeine Parameter
- runas=#user#: lässt das aufgerufene Skript als Benutzer #user# ausgeführt werden
Parameter nur im Authentifizierungsteil
- onauth=/path/to/onauth/script: Pfad zum Skript, das im Authentifizierungsteil ausgeführt wird
Standard ist /etc/security/onauth
nur im Sitzungsteil
onsessionopen=/path/to/onsessionopen/script: Pfad zum Skript, das ausgeführt wird, wenn eine (gültige) Sitzung gestartet wird
Standard ist /etc/security/onsessionopenonsessionclose=/path/to/onsessionclose/script: Pfad zum Skript, das ausgeführt wird, wenn eine Sitzung geschlossen wird
Standard ist /etc/security/onsessionclose
Nach der Installation ist das Komplexere, das System so zu konfigurieren, dass es dieses Modul nutzt.
Anpassen der PAM-Konfiguration
Ich habe pam_script im Authentifizierungs- und im Sitzungsteil der pam (login,kde) Dienstdatei verwendet.
Zuerst beschreibe ich, wie man den Authentifizierungsteil anpasst, wo pam_script mehr als einmal verwendet wird.
Der Authentifizierungsteil
Pam_script hat die Fähigkeit (ab Version 0.1.5), das beim Login bereitgestellte Passwort zu erhalten und dieses über eine Umgebungsvariable PAM_AUTHTOK für Skripte verfügbar zu machen.
Der Zweck hier ist, ein sicheres Verzeichnis zu erstellen, in dem vertrauliche Informationen (wie Anmeldeinformationen) gespeichert werden.
Das Modul wird im Authentifizierungsteil gestapelt:
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.soWie Sie sehen können, verwende ich pam_scripts.so mehrfach:
Das erste Mal, um ein Skript auszuführen, das ein verschlüsseltes Verzeichnis (mit encfs) erstellt und das geheime Passwort in einer Datei in diesem Verzeichnis für die Verwendung durch anmeldeinformationssensitive Programme wie fusesmb und mount.cifs schreibt. Dies geschieht direkt vor dem ersten Authentifizierungsmodul, das folgt, pam_unix.
Das letzte Mal, um ein Skript auszuführen, wenn die Authentifizierung nicht erfolgreich ist. Wenn die vorhergehenden Authentifizierungsmodule fehlschlagen (pam_unix und pam_ldap) (und nur dann) wird dieses Modul erreicht. Es ist notwendig, das verschlüsselte Verzeichnis zu unmounten und temporäre Dateien zu entfernen.
Beachten Sie, dass das letzte Modul von allen pam_deny ist, was wirklich notwendig ist. Ohne es könnte jeder sich anmelden. Das liegt daran, dass pam_script immer “PAM_SUCCESS” zurückgibt, egal was der Rückgabewert der Skripte ist.
Vergessen Sie nicht, das Flag “use_first_pass” zu dem bestehenden Modul pam_unix.so hinzuzufügen.
Die Skripte
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
#
# Benutzer nicht gefunden: etwas ist falsch
#
echo "Benutzer nicht gefunden."
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
# erstelle ein sicheres Verzeichnis
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;
#
# teste, ob das verschlüsselte Verzeichnis nicht bereits gemountet ist
#
if [ -z "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
#
# erstelle ein Passwort-bereitstellendes Programm
#
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;
#
# darum geht es: die Anmeldeinformationen in einer Datei zu speichern
# in diesem Fall das Passwort
#
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;
Einige Anmerkungen:
Dieses Skript erstellt ein verschlüsseltes Verzeichnis (falls es nicht bereits existiert) mit encfs. Beachten Sie die -S-Option bei encfs: Das Passwort für dieses verschlüsselte Verzeichnis wird von stdin gelesen und nicht abgefragt.
Dieses Passwort ist dasselbe wie das, das bei der Anmeldung verwendet wird.
Das verschlüsselte Verzeichnis befindet sich unter /var/lib/encfs/$userid.
Das Passwort wird in einer Datei, password.tmp, geschrieben. Dies ist eine temporäre Datei: Das Passwort muss nicht das richtige sein. Später im Prozess wird diese Datei je nach Erfolg der Validierung umbenannt (in password) oder entfernt.
Sehr wichtig zu beachten ist, dass das Skript als der sich anmeldende Benutzer und nicht als root ausgeführt wird! Und da Programme wie mount.cifs später Zugriff auf dieses Verzeichnis benötigen, um die Passwortdatei zu lesen, wird die allgemeine FUSE-Option allow_root hinzugefügt.
#!/bin/bash
userid=$1
service=$2
userproperties=$(getent passwd | grep -m 1 -E "^$userid")
if [ -z "$userproperties" ]; then
#
# Benutzer nicht gefunden: etwas ist falsch
#
echo "Benutzer nicht gefunden."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
#
# dieses Skript wird ausgeführt, wenn die Authentifizierung fehlgeschlagen ist
# ein sicheres verschlüsseltes Verzeichnis wird weiterhin erstellt
# daher ist es wichtig, dieses Verzeichnis wieder zu entfernen
#
if [ -d /var/lib/encfs ]; then
if [ -d /var/lib/encfs/$userid/unencrypted ]; then
#
# teste, ob das verschlüsselte Verzeichnis bereits gemountet ist
#
if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then
if [ $(w -h $userid | wc -l) -eq 0 ]; then
#
# dieser Benutzer ist nicht auf mehr tty's angemeldet
# alles entfernen und das verschlüsselte Verzeichnis unmounten
#
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
#
# dieser Benutzer ist noch angemeldet
#
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;
Einige Anmerkungen:
Dieses Skript wird ausgeführt, wenn die bereitgestellten Anmeldeinformationen nicht gültig sind. Das verschlüsselte Verzeichnis, das gerade eingerichtet wurde, wird wieder entfernt (unmontiert) und geleert. Dies geschieht natürlich nur, wenn dieser Benutzer nicht auf einem anderen tty angemeldet ist.
Der Sitzungsteil
Wenn der Sitzungsteil erreicht wird, ist sicher, dass die bereitgestellten Anmeldeinformationen (Passwort) korrekt sind. Das bedeutet, dass das Passwort - im Authentifizierungsprozess in einer temporären Datei gespeichert - korrekt ist. Eine Sache, die im Sitzungsteil zu tun ist, besteht darin, den Inhalt von password.tmp in die permanente Datei password zu verschieben.
Eine zweite Sache ist das Ausführen von Skripten, die diese Anmeldeinformationen für eigene Zwecke benötigen, wie das Mounten von CIFS-Freigaben oder fusesmb.
Es ist logisch, dass alle vertraulichen Informationen im sicheren Verzeichnis bleiben. Darum ging es schließlich von Anfang an!!
Beachten Sie, dass dieses Modul standardmäßig zwei Skripte ausführt:
. /etc/security/onsessionopen: wenn eine Sitzung gestartet/öffnet;
. /etc/security/onsessionclose: wenn eine Sitzung endet/schließt.
Ich folge dem Standard, es gibt keinen Grund, es anders zu machen.
Meine /etc/pam.d/login-Datei (der Sitzungsteil) sieht so aus:
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.soDie Skripte
Bei Sitzungsöffnung
cat /etc/security/onsessionopen#!/bin/bash
retcode=0;
userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid")
if [ -z "$userproperties" ]; then
#
# Benutzer nicht gefunden: etwas ist falsch
#
echo "Benutzer nicht gefunden."
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
#
# teste, ob das verschlüsselte Verzeichnis gemountet ist
#
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
#
# eine alte Passwortdatei gefunden
#
if [ -z "(diff /var/lib/encfs/$userid/unencrypted/password /var/lib/encfs/$userid/unencrypted/password.tmp)" ]; then
#
# neues Passwort und altes sind gleich
#
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
#
# Passwort nicht gefunden: es ist die erste Anmeldung.
# einfach die temporäre Passwortdatei in die verbleibende verschieben
#
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;
Bei Sitzungsabschluss
cat >> /etc/security/onsessionclose#!/bin/bash
userid=$1
service=$2
userproperties=$(getent passwd | grep -E "^$userid")
if [ -z "$userproperties" ]; then
#
# Benutzer nicht gefunden: etwas ist falsch
#
echo "Benutzer nicht gefunden."
exit
fi;
homedir=$(echo $userproperties | cut -d ":" -f 6);
gidnr=$(echo $userproperties | cut -d ":" -f 4);
uidnr=$(echo $userproperties | cut -d ":" -f 3);
#
# dieses Skript wird ausgeführt, wenn die Authentifizierung fehlgeschlagen ist
# ein sicheres verschlüsseltes Verzeichnis wird weiterhin erstellt
# daher ist es wichtig, dieses Verzeichnis wieder zu entfernen
#
if [ -d /var/lib/encfs ]; then
if [ -d /var/lib/encfs/$userid/unencrypted ]; then
#
# teste, ob das verschlüsselte Verzeichnis bereits gemountet ist
#
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;Einige Anmerkungen:
. wichtig: Frühversionen von shadow (wo das Anmeldeprogramm ein Teil davon ist) schlossen standardmäßig keine Sitzungen (Versionen vor 4.0.12). Sie müssen hinzufügen:
CLOSE_SESSIONS yeszu der /etc/login.defs-Datei.
Diese Option ist nicht dokumentiert und nicht in der von dem Shadow-Paket installierten login.defs-Datei vorhanden. Sie müssen sie selbst hinzufügen.
In neueren Versionen wurde diese Option entfernt: Die Sitzung wird immer geschlossen.
Das Ergebnis
Das verschlüsselte Verzeichnis enthält jetzt die Anmeldeinformationen, die nur für den Eigentümer und root verfügbar sind. Durch Erstellen einer Datei mount.cifs.conf mit diesen Werten:
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.confJetzt ist das Mounten einer CIFS-Freigabe möglich mit:
/sbin/mount.cifs //fileserver/public /home/sbon/netshares/fileserver/public -o credentails=/var/lib/encfs/sbon/unencrypted/mount.cifs.conf,ip=192.168.0.2wo das Verzeichnis /home/sbon/netshares/fileserver/public existiert und eine Freigabe “public” auf “fileserver” verfügbar ist, ein smb/cifs-Server mit der IP-Nummer 192.168.0.2.
Dieser Befehl muss als root ausgeführt werden. Root muss Zugriff auf das verschlüsselte Verzeichnis haben.
Ein weiteres Beispiel ist fusesmb, das Anmeldeinformationen verwenden kann, um das smb-Netzwerk zu durchsuchen. Dies geschieht nicht, indem eine separate Datei nur für die Anmeldeinformationen erstellt wird, sondern in der globalen Benutzerkonfigurationsdatei von fusesmb in ~/.smb/fusesmb.conf:
(hier erstelle ich eine einfache Konfigurationsdatei nur mit Anmeldeinformationen)
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 Der letzte Link ist, weil fusesmb (gestart von sbon) die Konfigurationsdatei dort erwartet.
Jetzt starten Sie es mit:
fusesmb /home/sbon/networkwenn ich als ich selbst (sbon) angemeldet bin. Das Verzeichnis /home/sbon/network muss existieren.
Erhalte neue Beiträge in deinem Posteingang.
Kein Spam. Jederzeit abmelden.