使用PAM和EncFS创建安全目录
内容
。 介绍
。 安装encfs
。 安装pam_script
。 调整PAM配置
。 结果
介绍
我做的工作很多与需要凭证的程序
这些计划的例子有:
。 mount.cifs
。 fusesmb( 在这里寻找细节)
现在,在我的网络(和其他人)中,登录时提供的凭据可以(并且应该)由这些程序使用。 如何检索这些凭据,提供足够的安全性?
使用PAM模块pam_script可以将密码存储在一个文件中,这将被fusemb和mount.cifs用来读取密码。
为了实现安全性,可以让用户登录所有者并拒绝任何人的读/写。 当用户结束他/她的会话时,删除该文件。
这对于运行时是足够的。 但是我很想知道,但是如果系统崩溃了,并且具有凭据的文件保留在硬盘驱动器上? 任何能够安装这个硬盘的人,例如lifecd,都可以读取这个文件!
这就是为什么我正在寻找一个加密这个文件的原因。
与encfs这是非常可能的! 在运行时,它提供加密文件和目录的接口,这只能在运行时存在! 当系统没有运行时,只有加密的文件,当你不知道它的关键时就没用。 这个密钥正是(加密)密码! 这就是为什么我选择了PAM和Encfs的组合。
寻找Encfs的网站:http: //freshmeat.net/projects/encfs
这种结构旨在为运行和停机时间(崩溃后)提供足够的安全性来存储敏感信息,而不是在硬盘上创建永久的安全目录以存储文档。
安装encfs
当然应该安装FUSE。
安装非常简单:
(请查看EncF所需的rlog网站)
tar -xzf encfs-*.tar.gz
cd encfs-*
configure --prefix=/usr --sysconfdir=/etc --libexecdir=/usr/sbin
make
make install
安装后,您可以测试它是否工作:
mkdir -p ~/test/encrypted
mkdir -p ~/test/decrypted
encfs ~/test/encrypted ~/test/decrypted
mount (should show the just created mount)
echo "This is very secret." > ~/test/decrypted/testfile
加密的目录包含加密的文件,并在卸载和/或关闭后保留在硬盘上。 解密的目录是它的接口,并在卸载和/或关闭时消失。
文件测试文件应出现在解密的目录中,并以加密的形式出现在加密目录中。 文件的名称和内容被加密。
我在本地机器中选择了一个单独的地图,每个用户登录加密(和它的接口)将被存储:
install -m777 -o root -g root /var/lib/encfs
注意权限:每个人都必须能够在这里创建一个目录。 本文后面解释了为什么。
安装pam_script
安装非常简单。 make命令后,将库移动到/ 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使用一些参数。 所有这些都在源目录的README中描述。 重要的是:
常用参数
- runas =#user#:使脚本调用为user#user#
参数仅在auth部分
- onauth = / path / to / onauth / script:在auth部分中运行的脚本路径
默认是/ etc / security / onauth
只在会话部分
- onsessionopen = / path / to / onsessionopen / script:启动(有效)会话时运行的脚本路径
默认是/ etc / security / onsessionopen
- onsessionclose = / path / to / onsessionclose / script:在会话关闭时运行的脚本路径
默认为/ etc / security / onsessionclose
安装后,更复杂的是配置系统以利用此模块。
调整PAM配置
我在pam(login,kde)服务文件的认证和会话部分中使用了pam_script。
首先我将描述如何调整auth部分,其中pam_script被多次使用。
认证部分
Pam_script有能力(从版本0.1.5)获取登录时提供的密码,并通过一个环境变量PAM_AUTHTOK可用于脚本。
这里的目的是创建一个安全的目录,其中存储有机密信息(如凭证)。
该模块堆叠在authpart中:
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
你可以看到我多次使用pam_scripts.so:
- 第一次运行一个创建加密目录(使用encfs)的脚本,并将秘密密码写入此目录中的文件,以供凭证敏感程序(如fusesmb和mount.cifs)使用。 这是在第一个auth模块之前完成的,pam_unix之后。
- 最后一次在认证不成功时运行脚本。 当前面的authmodules失败(pam_unix和pam_ldap)(只有这样)到达该模块。 卸载加密目录并删除临时文件是非常重要的。
- 请注意,所有的最后一个模块是pam_deny ,是非常必要的。 没有它,每个人都可以登录。 这是因为pam_script始终返回“PAM_SUCCESS”,无论脚本的返回值如何。
不要忘记在现有模块pam_unix.so中添加“use_first_pass”标志。
脚本
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 not found: something wrong # echo "User not found." 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 # create a safe 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; # # test the encrypted directory is not already mounted # if [ -z "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then # # create a password-provide-program # 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; # # this is what's all about: storing the credentials in a file # in this case the password # 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;
一些言论:
此脚本使用encfs创建加密目录(如果它不存在)。 注意encfs上的-S选项:此加密目录的密码从stdin读取,而不是被推荐。
此密码与登录时使用的密码相同。
加密目录在/ var / lib / encfs / $ userid 。
密码被写入一个文件password.tmp 。 这是一个临时文件:密码不一定是正确的。 在此过程中,根据验证的成功,这个文件被重命名(密码)或删除。
非常重要的是注意到脚本是以用户登录的方式执行的,而不是root用户! 而由于以后的程序,如mount.cifs需要访问这个目录才能读取密码文件,所以添加了常见的fuseoption allow_root 。
#!/bin/bash userid=$1 service=$2 userproperties=$(getent passwd | grep -m 1 -E "^$userid") if [ -z "$userproperties" ]; then # # userproperties not found: something wrong # echo "User not found." exit fi; homedir=$(echo $userproperties | cut -d ":" -f 6); gidnr=$(echo $userproperties | cut -d ":" -f 4); uidnr=$(echo $userproperties | cut -d ":" -f 3); # # this script is run when the authentication failed # a safe encrypted is still created # so it's important to remove this safe again # if [ -d /var/lib/encfs ]; then if [ -d /var/lib/encfs/$userid/unencrypted ]; then # # test the encrypted directory is not already mounted # if [ -n "$(mount | grep -w /var/lib/encfs/$userid/unencrypted )" ]; then if [ $(w -h $userid | wc -l) -eq 0 ]; then # # this user is not logged in on more tty's # just remove everything and umount the encrypted directory # 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 # # this user is still logged in # 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;
一些言论:
当提供的凭证无效时,执行此脚本。 刚刚安装的加密目录将被再次删除(卸载)并清除。 这当然只有当这个用户没有登录任何其他的tty。
会话部分
当达到会话部分时,确保所提供的凭据(密码)正确。 这意味着密码 - 在存储在临时文件中的auth fase中 - 是正确的。 所以在会话中要做的一件事是将password.tmp的内容移动到永久密码 。
第二件事是运行脚本,需要这些凭据供自己使用,例如安装CIFS共享或fusesmb。
任何机密信息都保留在安全目录中是合乎逻辑的。 这是所有关于首先!
请注意,此模块默认运行两个脚本:
。 / etc / security / onsessionopen :当会话开始/打开时;
。 / etc / security / onsessionclose :会话结束/关闭时。
我按照默认,没有理由去做。
我的/etc/pam.d/login文件(sessionpart)看起来像:
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
脚本
会话打开
cat /etc/security/onsessionopen
#!/bin/bash retcode=0; userid=$1 service=$2 userproperties=$(getent passwd | grep -E "^$userid") if [ -z "$userproperties" ]; then # # userproperties not found: something wrong # echo "User not found." 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 # # test the encrypted directory is mounted # 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 # # an old passwordfile found # if [ -z "(diff /var/lib/encfs/$userid/unencrypted/password /var/lib/encfs/$userid/unencrypted/password.tmp)" ]; then # # new password and old one are the same # 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 # # password not found : it's the first login. # just move the temporary passwordfile to the remaining # 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;
会话关闭
cat >> /etc/security/onsessionclose
#!/bin/bash userid=$1 service=$2 userproperties=$(getent passwd | grep -E "^$userid") if [ -z "$userproperties" ]; then # # userproperties not found: something wrong # echo "User not found." exit fi; homedir=$(echo $userproperties | cut -d ":" -f 6); gidnr=$(echo $userproperties | cut -d ":" -f 4); uidnr=$(echo $userproperties | cut -d ":" -f 3); # # this script is run when the authentication failed # a safe encrypted is still created # so it's important to remove this safe again # if [ -d /var/lib/encfs ]; then if [ -d /var/lib/encfs/$userid/unencrypted ]; then # # test the encrypted directory is already mounted # 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;
一些言论:
。 重要的是:早期版本的影子(登录程序的一部分)没有关闭默认会话(4.0.12之前的版本)。 你必须添加:
CLOSE_SESSIONS yes
到/etc/login.defs文件。
该选项没有记录,并且不存在于Shadow包安装的login.defs文件中。 你必须自己添加。
在较新版本中,此选项被删除:会话始终关闭。
结果
加密目录现在包含只对所有者和root可用的凭据。 通过使用以下值创建一个文件mount.cifs.conf :
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
现在可以通过以下方式安装cifs共享:
/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
目录/ home / sbon / netshares / fileserver / public确实存在,而且这是“fileserver”上可用的共享“public”,一个IP地址为192.168.0.2的smb / cifs服务器。
此命令必须以root身份运行。 根需要访问加密的目录。
另一个例子是fusesmb ,它可以使用凭据浏览smb网络邻居。 这不是通过仅为凭据创建单独的文件,而是在〜/ .smb / fusesmb.conf中的fusesmb的全局每用户配置文件中:
(这里我创建一个简单的配置文件,只有凭据)
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
最后一个链接是因为fusesmb(由sbon启动)期望配置文件在那里。
现在开始:
fusesmb /home/sbon/network
当我以自己的身份登录时(sbon)。 目录/ home / sbon / network必须存在。