使用PAM和EncFS创建安全目录

使用PAM和EncFS创建安全目录

内容

。 介绍
。 安装encfs
。 安装pam_script
。 调整PAM配置
。 结果

介绍

我做的工作很多与需要凭证的程序
这些计划的例子有:
。 mount.cifs
。 fusesmb( 在这里寻找细节)

现在,在我的网络(和其他人)中,登录时提供的凭据可以(并且应该)由这些程序使用。 如何检索这些凭据,提供足够的安全性?
使用PAM模块pam_script可以将密码存储在一个文件中,这将被fusembmount.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必须存在。

赞(52) 打赏
未经允许不得转载:优客志 » 系统运维
分享到:

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

微信扫一扫打赏