Linux教程

Linux操作系统(十):Linux账号管理与ACL权限设置

本文主要是介绍Linux操作系统(十):Linux账号管理与ACL权限设置,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
  • 账号管理
  • 主机详细权限规划ACL
  • 用户身份切换
  • 用户特殊shell与PAM模块
  • 主机上用户信息传递
  • CentOS7环境下大量创建账号

 一、关于本文内容的导读

这部分不涉及具体内容的解析,只是作为浏览和查找相关知识点的引导内容,采用【主题 | 命令 | 对应内容小节编号】三个关键信息的组合模式,依照这些信息可以快速查找到相关详细的示例和解析。

当我们使用账号登入Linux系统时,会发生什么?终端或者远程连接的网络进程会基于系统提供的登入接口,将用户的名称和密码交给这个接口,管理这个接口的相关进程会去查询/etc/passwd的用户信息,通过用户名查找到用户的UID,然后通过用户的UID去查询验证/etc/shadow中的密码。

有了用户身份的确认才能给用户使用资源和使用资源的权限做管理,在管理用户权限中除了用户的UID以外还有一个GID的概念,即用户组(群)。与用户GID密切相关的两个文件是/etc/group和/etc/gshadow,它们支持了用户可以使用除自身的文件资源以外还可以使用通过群组授权的资源。

通过用户身份和权限的设置,可以有效的合理的管理和分配系统资源给各个用户使用,这对于系统管理非常重要。所以管理用户的账户是使用Linux系统的基础,这一篇博客重点介绍用户的账号的管理相关操作和权限设置相关的内容。

修改用户账户的命令 | usermod | 2.1 | 2.2
创建新用户或更新默认默认新用户信息 | useradd | 2.2
管理用户的密码 | passwd | 2.2
修改用户密码信息 | chage | 2.2 | 更新用户密码过期信息
修改用户账户 | usermod | 2.2
删除用户账户 | userdel | 2.2
查看用户ID信息 | id | 2.3
查看用户信息 | finger | 2.3
设置用户finger通讯信息 | chfn | 2.3
查看和设置用户的shell | chsh | 2.3
新增用户组 | groupadd | 2.3
修改用户组名称和GID数值的工具 | groupmod | 2.3
删除用户组 | groupdel | 2.3
管理用户组 | gpasswd | 2.3
设置文件访问控制列表 | setfacl | 3.1
获取文件访问控制列表 | getfacl | 3.2
切换用户 | su | 4.1
使用其他用户身份执行命令 | sudo | 4.2
编辑/etc/sudoers文件 | visudo | 4.2
查看最近的用户登入信息 | last | 6.1
查看当前登入的用户及其中在进行的操作 | w | 6.1
查看当前登入的用户 | who | 6.1
查看用户的登入信息 | lastlog | 6.1
向指定的用户发送消息 | write | 6.2
向系统上所有用户群发消息 | wall | 6.2
调节用户终端的写访问权限 | mesg | 6.2
发送和接收邮件 | mail | 6.3
检查密码文件的完整性 | pwck | 7.1
密码转换的相关工具 | pwconv | pwunconv | chpasswd | 7.1

 二、账号管理

2.1用户账号及其相关文件结构的解析

/etc/passwd文件结构:

在这个文件中每行代表一个用户的账号相关数据,每个具体的数据之间使用冒号":"间隔,下面我们就来看一个用户账号的信息也就是/etc/passwd中每一行都有拿一些数据,我们可以通过相关的文件数据读取工具将/etc/passwd中的数据读取到终端上,cat或head等工具都可以,然后基于一行数据逐个数据字段来解析:

 head -n 4 /etc/passwd
 root:x:0:0:root:/root:/bin/bash
 bin:x:1:1:bin:/bin:/sbin/nologin
 daemon:x:2:2:daemon:/sbin:/sbin/nologin
 adm:x:3:4:adm:/var/adm:/sbin/nologin

就以第一行数据来看,通过":"间隔开的字段有七个,下面就来了解这七个字段的数据分别代表什么:

1.账号名称:用于用户识别用户身份,方便用户记忆和识别。
2.密码:由于passwd中并不保存密码,而是由【x】这个字符替代,这是因为早期的Unix系统的密码就放在【x】这个字段上,真正的密码实际上存储在/etc/shadow文件中。
3.UID:用于系统实际识别用户身份的编号,系统中并不使用账号字符串来识别使用,账号名称只是为了方便用户记忆和使用而已。UID为了方便管理和识别用户身份,Linux给不同的用户设定了一些取值范围,后面详细介绍。
4.GID:表示用户的群组编号,用于用户群组及其权限的管理。
5.用户信息说明:这个数据没什么固定的标准含义,主要用来提供给用户和系统管理员更加z
6.用户home目录
7.shell:每个用户登入都会获得一个shell来与系统进行沟通,这个字段就是当前用户登入系统使用的shell类型,比如root时bash、adm是nologin,在bash那篇博客中讲个nologin的shell是不需要登入的。

 然后接着补充以下UID的取值范围:

0:这是系统管理员的UID,一个系统上管理员可以不只有一个,也就是说可能有多个用户名同时使用0这个UID。虽然可以有多个管理员,但不建议这么做。

1~999:这部分UID是保留给系统使用的ID,默认1000以下的数值保留给系统使用。由于系统上面启动一些服务使用较小的权限去运行,以保证系统的安全性,所以这些UID的对应的账户是不可登入的,也就是说它们获得的shell是nologin。在这部分保留UID中通常还被划分为两大类:1~200是由系统发行版本自行建立的系统账号、201~999若用户由系统账号的需求,可以使用的UID。

1000~60000:这部分UID是给普通用户使用的,随着硬件设备性能的不断提升和需求的不断增多,UID的最大值已经可以支持到2^32-1的范围。

 /etc/shadow文件结构:

这个文件是用来管理用户账号密码,其实一开始用户密码就存在passwd的第二个字段上,由于很程序的运行和权限有关的操作都需要使用passwd,所以passwd的权限设置是-rw-r--r--,所以很多程序都可以去读取passwd,虽然用户密码是通过加密再写在passwd的第二个字段上的,但是加密后的密码还是有被暴力破解的风险。因为上述的原因,后来就将用户账号密码的管理就独立移到了shadow中,在shadow包含了一系列账号密码关系的信息,下面就来看看这些信息的内容及解析:

 head -n 4 /etc/shadow
 root:$6$AGZMONJrgTvV6C6A$kCLEhhUovrFUeA6d283mJdS0wtkRUvxWLy2V.4An8wW9VtRnqLliZzb1GoTIZDDpYHNXpgintQFF24IiKE45m/::0:99999:7:::
 bin:*:18353:0:99999:7:::
 daemon:*:18353:0:99999:7:::
 adm:*:18353:0:99999:7:::

shadow跟passwd一样,也是一行数据表示一个用户的账号信息,也是用":"间隔每个字段,下面就来看这些字段分别表达的含义:

1.账号名称
2.密码
3.最近修改密码的日期
4.密码不可被修改的天数(相对第三个字段计数)
5.密码需要重新修改的天数(相对第三个字段计数)
6.密码需要修改期限前的警告天数(相对第五个字段计数)
7.密码过期后的账号宽限时间(相对第五个字段计数)
8.账号失效日期
9.保留字段

关于shadow中的账号信息字段根据名称就可以很清晰的理解它们的作用,后面管理账号就是基于这些信息展开的。

/etc/group文件结构:

这个文件中的数据就是用户组的信息,下面来看它的具体数据和结构内容:

 head -n 4 /etc/group
 root:x:0:
 bin:x:1:
 daemon:x:2:
 sys:x:3:

跟passwd一样,每一行数据表示一个用户组信息:

1.组名:
2.用户组密码
3.GID
4.此用户组支持的账号名称:在前面文件权限相关博客中介绍过一个用户可以加入多个用户组,每个用户组加入一个用户就会将用户名添加到这个字段上,没有用户名之间使用逗号间隔。

关于用户组的管理这里需要做一些概念解析,包括初始用户组、有效用户组、支持用户组、次要用户组。

初始用户组:还记得passwd中的第四栏字段的GID吧,当用户登入时就会拥有这个用户组,这就是所谓的初始用户组。

支持用户组:当我们要获得其他用户创建的用户组的相关权限,我们就要将自己的用户加入到对应的用户组中,也就是将用户名添加到group文件的第四栏字段中。

有效用户组:所谓有效用户组就是当前如果你要创建新的文件时,这个新文件的就会使用这个有效用户组作为该文件的用户组。

次要用户组:所谓次要用户组就是当前用户拥有的自身的用户组以外的用户组,也就是将自己的用户名添加到其他用户的用户组的第四栏上,这时用户拥有的其他用户组。次要用户组也是支持用户组。

这里来了解几个跟用户组有关的命令:

 usermod -a -G users dmtsai  #这行命令表示将用户dmtsai添加到users用户组中,详细参考man文档

 groups  #查看当前用户的有效用户组和支持用户组,也就是当前用户加入的所有用户组。

 newgrp [当前用户如加入的任意用户组名]  #设置当前用户的有效用户组,可以将当前加入的任意用户组设置为自己的有效用户组

/etc/gshadow的文件结构:

这个文件的作用与shadow类似,它是用户组的密码文件,下面来看看他都有哪些字段:

1.组名
2.密码栏:如果开头为!表示无合法密码,所以五用户组管理员。
3.用户组管理员的账号
4.加入该用户组的所有用户账号:与/etc/group一样。

2.2新增、设置、删除用户

前面2.1介绍了用户相关的数据文件,接着就来看这些数据可以通过什么方式被添加到这些文件中,然后数据如何修改、删除,以实现用户账户的管理。这一部分就来介绍实现这些操作的相关命令,如新增用户的useradd、管理用户及密码的【passwd | chage | usermod】、删除用户的userdel。

useradd命令的语法:

 useradd [-u UID] [-g 初始用户组] [-G 次要用户组] [-mMref] [-c 说明栏] [-d home目录绝对路径] [-s shell] 使用者账号名

上面这些命令的选项基本都对应了passwd文件的相关字段,非常好理解,没有明显的体现出其功能的选项就是[-mMref],这其中有一些是限制性功能,有一些是与shadow文件里面字段相关的选项,下面就逐个来解析它们:

-u:用于设置新用户的UID,相关设置参考前面介绍的UID取值范围;
-g:用于设置新用户的初始用户组,这个设置的数据对应passwd中的第四栏信息;
-G:用于设置新用户的次要用户组,这个设置的数据对应group中的第四栏信息;
-c:用于设置用户的一些说明信息,这个设置的数据对应passwd中的第五栏信息;
-d:用于设置用户的home目录,注意设置的路径必须是绝对路径,这个设置的数据对应passwd中的第六栏信息;
-s:用于设置用的shell类型;
-m:表示必须要设置用户home目录(一般账号默认值)
-M:表示不要设置用户的home目录(系统账号默认值)
-r:建立一个系统的账号,这个账号的UID会有限制(具体参考/etc/login.defs)
-e:用于设置用户的账号有效日,格式为【YYYY-MM-DD】,这个数据对应了shadow中的第八栏信息;
-f:用于设置用户账号密码的失效宽限期,0表示理立即失效,-1表示永远不失效;

通过上面对useradd命令选项的介绍,怎么使用基本就非常清晰了,这里再来说明以下创建一个用户以后,前面提到的passwd、shadow、group等系统数据会有那些变化,下面逐个介绍:

1.在/etc/passwd文件中会添加一行用户数据;

2.在/etc/passwd文件中也会添加一行账号密码参数信息,但尚未设置密码;

3.在/etc/group文件中也会添加一个与用户名一摸一样的组名;

4.在/home目录下会新建一个与用户名同名的用户home目录,权限默认为700;

 基于useradd命令创建一个用户的示例:

 useradd -u 1500 -g users vbird  #创建一个用户名为vbird的普通用户

 ll -d /home/vbird  #查看刚刚创建的vbird用户home目录:drwx------. 3 vbird users 78 7月  23 15:46 /home/vbird

 grep vbird /etc/passwd /etc/shadow /etc/group  #查看刚刚创建的vbird用户在系统管理用户的相关文件中的数据

 /etc/passwd:vbird:x:1500:100::/home/vbird:/bin/bash
 /etc/shadow:vbird:!!:19196:0:99999:7:::

通过上面的示例可以看到创建一个用户的基本操作,其中有两个需要注意的细节,这个用户创建时并没有设置账号密码,这个会在密码管理相关的内容部分介绍,然后是在/etc/group中没有用户同名的用户组,这是因为在创建用户时指定了一个用户组,所以就不会使用默认的用户名创建用户组,示例中的用户组可以通过grep users /etc/group命令查看确认。然后下面再看创建一个系统用户的示例:

 useradd -r vbird2  #创建系统用户vbird2

 ll -d /home/vbird2  #由于创建的是系统用户,所以不默认主动创建用户名同名的home目录

 grep vbird2 /etc/passwd /etc/shadow /etc/group  #查看用户相关的数据

 /etc/passwd:vbird2:x:383:383::/home/vbird2:/bin/bash
/etc/shadow:vbird2:!!:19196::::::
/etc/group:vbird2:x:383:

通过以上的两个示例可以基本了解useradd创建用户的基本默认机制,这些默认的配置是由/etc/default/useradd提供的,可以使用文本内容查看工具自行查看,这里就不赘述了,关于useradd命令的详细内容还可以查看man文档,接着来了解用户密码管理及相关工具的使用。

passwd命令的语法:

 passwd [--stdin] [账号名称]  #所有用户可使用这个语法来修改自己的密码

 passwd [-l] [-u] [-stdin] [-S] [-n 日数] [-x 日数] [-w 日数] [-i 日期]   #这个语法是提供给root用来管理密码相关设置的

passwd命令的选项及参数解析:

--stdin:可以通过来自前一个管道的数据,作为密码输入;
-l:表示Lock的意思,会将/etc/shadow第二栏最前面加上!使密码失效;
-u:与-l相对,是unlock的意思;
-S:列出密码相关参数,即shadow文件内的大部分信息;
-n:后面接天数,shadow的第四栏,表示表示多少天不可修改密码;
-x:后面接天数,shadow的第五栏,表示多少天内需要修改密码;
-w:后面接天数,shadow的第六栏,表示密码过期前多少天会有警告信息;
-i:后面接日期,shadow的第七栏,表示密码失效日期;

还记得在使用useradd中示例创建的用户吧,创建的用户都没有设置密码,这里就通过passwd来设置密码作为示例:

 passwd vbird  #在root权限下设置,执行这行密码以后就会提示输入密码两次,输入两次一样的密码以后就可以成功设置用户的密码了

 echo "abc123dd" | passwd --stdin vibird  #这个操作同样可以实现给新用户设置密码,好处是不需要重复输入,坏处是这个密码会跟着历史命令被记录在/root/.bast_history中

如果要修改密码,就是在用户登入下直接执行passwd命令,不需要任何选项,它会提示先输入原密码再输入两次新密码就可以了,这里就不演示了。在设置密码的时候可以同时通过相关选项设置密码的其他数据,比如过期天数等,感觉也没有演示的必要,不过修改密码过期信息还有一个独立的命令chage还是有必要了解下:

chage命令的语法:

 chage [-ldEImMW] 账号名

chage命令的选项及参数解析:

-l:列出该账号的详细密码参数;
-d:后面接日期,用于修改shadow第三栏(最近一次修改密码的日期),格式YYYY-MM-DD;
-E:后面接日期,用于修改shadow第八栏(账号失效日),格式YYYY-MM-DD;
-I:后面接天数,用于修改shadow第七栏(密码失效日期);
-m:后面接天数,用于修改shadow第四栏(密码最短保留天数);
-M:后面接天数,用于修改shadow第五栏(密码多久需要进行修改);
-W:后面接天数,用于修改shadow第六栏(密码过期前警告日期);

关于chage命令的一般的应用非常简单,这里演示一个让新用户第一次登入必须修改密码的应用:

 useradd agetest  #创建新用户账号

 echo "agetest" | passwd --stdin agetest  #设置与用户名一致的密码,方便修改

 chage -d 0 agetest  #这个设置会将账号最后一次修改密码的日期设置为1970/1/1,所以账号第一次登入密码就过期

 chage -l agetest | head -n 3  #查看这个账号的密码信息

修改用户账户信息的usermod命令的语法:

 usermod [-cdegGlsuLU] username

usermod命令的选项与参数解析:

-c:用于设置账号说明,对应/etc/passwd第五栏;
-d:用于设置用户home目录,对应/etc/passwd的第六栏;
-e:用于设置账号失效日期,对应/etc/shadow的第八栏;
-f:用于设置密码失效日,对应/etc/shadow的第七栏;
-g:用于设置初始用户组,对应/etc/passwd的第四栏,即设置GID;
-G:用于设置次要用户组,对应/etc/group中该用户组的第四栏,会将当前用户的名称添加到用户组的成员中;
-a:与-G配合实现次要用户组支持,而非设置;
-l:用于设置账号名称,即修改账号名称,对应/etc/passwd的第一栏;
-s:用于设置shell类型,即/etc/passwd的第七栏;
-u:用于设置UID数字,对应/etc/passwd第三栏;
-L:暂时将使用者的密码冻结,让该用户无法登入,本质上仅修改/etc/shadow的密码栏;
-U:将/etc/shadow的密码栏的感叹号(!)拿掉,解锁;

关于usermod命令其实算是一个账号综合性管理工具,与前面的几个命令的功能很多都重合,也就没有必要演示了,最后来看一下如何删除用户账号:

删除用户账号userdel命令的语法及选项解析:

 userdel [-r] username  #-r表示将用户的home目录一起删除

需要注意的是如果使用当前用户登入的话,切换到管理员账号再操作删除会因为该用户的进程还没关闭而失败,这部分内容在后面的进程管理中具体介绍;

2.3用户功能

在前面2.2中介绍了一系列的用户账号管理内容,它们都有一个特征,在账号管理中除了管理员对系统上的账号管理,还有对帐号内部的管理,这些管理包括:查看用户信息、查看用户登入信息、设置用户的个人信息、加入退出(增删)用户组等。

查看用户真实的UID和GID的命令id语法:

 id [username]  #如果是查看用户自己的id信息直接执行id不需要跟参数

查看用户的信息的命令finger语法:

这个工具可以用来查看用户的信息比较多,具体看语法中的选项以及后面的选项介绍,不过需要注意的是这个工具在一些Linux系统中不一定默认安装的,如果你测试的系统没有默认安装,需要安装然后再测试:

 finger [-slmp] username

finger命令的选项解析:

-s:列出用户的账号、名称、终端代号及登入时间;
-l:使用多好显示来列出账号信息,包括-s的内容,除此之外还会列出用户的home目录、电话、登入脚本、邮件状态、以及home下的一些文件信息(.plan、.project、.forward),默认使用该方式输出用户信息。
-m:默认情况下会使用username的字符串部分匹配用户名,使用-m只匹配username全部字符,不会做字符串的部分匹配;
-p:不查看.plan和.project文件信息;

finger的安装与使用示例:

 yum install finger  #安装finger,根据后面的提示完成安装即可;

 finger -s tx  #使用-s查看用户tx的账号信息:

 Login     Name       Tty      Idle  Login Time   Office     Office Phone   Host
 tx           tx              *:0             Jul 25 12:29                                        (:0)

 finger tx  #使用默认方式即-l查看用户tx的账号信息:

 Login: tx                         Name: tx
 Directory: /home/tx                     Shell: /bin/bash
 On since 一 7月 25 12:29 (CST) on :0 from :0 (messages off)
 No mail.
 No Plan.

使用finger查看用户信息,可以发现Linux用户信息中还包含了通信信息,这是测试账号没有设置这些信息,所以输出了空白,用户通信信息的设置工具就是下面要介绍的chfn命令。

设置用户通讯信息chfn命令语法:

 chfn [-foph] [账号名]

chfn命令的选项及参数解析:

-f:设置用户完整的大名;
-o:表示office的意思,用于设置办公室号码,也就是前面finger输出信息中的office字段;
-p:设置办公室电话号码;
-h:设置家里的电话号码;

这个命令对于管理系统没有什么必要和实际意义,了解即可。

查看和设置shell的工具chsh命令:

 chsh [-ls]

chsh命令的选项解析:

-s:设置当前用户自己的登入shell;
-l:查看当前系统上所有可用的shell,实质上就是/etc/shells的内容;

使用chsh命令设置vbird用户的登入shell为csh:

 chsh -s /bin/csh; grep vbird /etc/passwd  #首先要确保当前是vbird用户,然后执行这行命令,修改以后需要输入账号密码重新登入,然后打印下面的信息:

 vbird:x:1500:100::/home/vbird:/bin/csh

 chsh -s /bin/bash  #为了确保后续使用正常,建议使用这行命令将vbird用户的shell修改回bash

用户新增用户组的工具groupadd命令:

 groupadd [-g gid] [-r] 用户组名称

groupadd命令的选项及参数解析:

-g:后面接执行的GID,用来创建一个指定GID的用户组(如果不适用-g指定GID,创建用户组时会由1000以上最大GID+1来作为当前创建用户组的GID);
-r:建立系统用户组,与/etc/login.defs内的GID_MIN有关;

 使用groupadd创建一个用户组:

 groupadd group1

 grep group1 /etc/group /etc/gshadow

 #打印结果:

 /etc/group:group1:x:1001:
/etc/gshadow:group1:!::

用于修改用户组的名称或GID数值的工具groupmod命令:

 groupmod [-g id] [-n groupname] 用户组

groupmod命令的选项及参数解析:

-g:用于设置用户组新的GID数值,即id;
-n:用于设置用户组新的名称,即groupname;

将前面groupadd示例中创建的group1用户组的名称和GID数值进行修改作为groupmod的示例:

 groupmod -g 201 -n mygroup group1

 grep mygroup /etc/group /etc/gshadow

 打印结果:

 /etc/group:mygroup:x:201:
 /etc/gshadow:mygroup:!::

用于删除用户组的工具groupdel命令:

 groupdel [groupname]

这个命令非常简单,但却有一个隐藏的细节,看下面的示例:

 groupdel mygroup  #可以正常删除

 groupdel users  #报:“groupdel:不能移除用户“games”的主组”,这个跟/etc/passwd的第四栏用户初始用户组有关,也就是说被设置为用户初始用户组不能直接删除

管理用户组的工具gpasswd命令:

这个工具可以用来加入和移除用户组中的用户、管理用户组密码、以及用户组管理权转移,下面先来看语法。

 gpasswd groupname

 gpasswd [-A user1,...] [-M user3,...] groupname

 gpasswd [-rRad] groupname

gpasswd命令的选项及参数解析:

:如果不使用任何选项,表示设置用户组的密码;
-A:将用户组的管理权交给指定的用户管理;
-M:将某些用户加入到这个用户组;
-r:将用户组的密码删除;
-R:让用户组的密码栏失效;
-a:将某个用户加入到这个用户组中;
-d:将某个用户组成员移除出去;

gpasswd演示示例:

 groupadd testgroup  #创建一个测试用户组

 gpasswd testgroup  #给测试用户组设置密码

 grep testgroup /etc/group /etc/gshadow  #查看测试用户组的相关信息:

 /etc/group:testgroup:x:1001:
 /etc/gshadow:testgroup:$6$1FFk1QYy$rd4EA6FBNinZVlurOZoDJc5BOtEgmFsNSqSBsTEK7kqHudRBRqV2V/FcV4hVUrIFBZnbu4e4sqOAHlJqSdyyI/::

 gpasswd -a vbird testgroup  #将用户vbird添加到testgroup用户组中

 grep testgroup /etc/group  #查看测试用户组的信息:

 testgroup:x:1001:vbird

 gpasswd -A vbird testgroup  #给vbird用户授权testgroup的管理员权限

 su vbird  #切换到vbird用户

 gpasswd -a tx testgroup  #通过testgroup的管理员vbird添加用户组新成员tx

 grep testgroup /etc/group  #查看testgroup用户组的信息

 testgroup:x:1001:vbird,tx

 su tx  #切换到tx用户

 groups  #tx用户查看自身加入的用户组:tx testgroup

以上就是关于用户组管理所有相关内容,应用非常简单,其实跟我们日常的即时通讯软件的账号的群非常类似,只是c端的即时通讯软件有丰富便捷的界面操作,而在Linux系统中就只能使用shell的命令来实现。

 三、主机详细权限规划ACL

在进入这部分内容之前我们需要搞清楚什么是ACL,其全称是Access Control List,译为访问控制列表,主要是提供传统的属主、所属群组、其他人的读、写、执行权限之外的详细权限设置。前面提到的这些权限其实就是在这篇博客的第二部分提到的权限控制,而ACL可以理解为是在那些权限之外的一个独立权限控制系统,这个权限控制可以针对具体的用户、用户组、甚至还可以针对一个目录新建文件/目录时默认配置这类独立权限。

当然在Linux中独立于系统权限系统之外的权限控制不仅仅只有ACL,比如还有为使用不同主机使用同一组账号密码的一些身份认证系统,如:LDAP、NIS等。在之前ACL时UNIX-like操纵系统的额外支持选项,由于Linux发展的需要,ACL逐渐被默认加入了所有常见的Linux文件系统挂在参数中,比如ext2、ext3、ext4、xfs等,可以通过下面的命令来查看当前的内核挂载中的相关信息:

 dmesg | grep -i acl  #下面是打印信息

 [    2.882178] systemd[1]: systemd 219 running in system mode. (+PAM +AUDIT +SELINUX +IMA -APPARMOR +SMACK +SYSVINIT +UTMP +LIBCRYPTSETUP +GCRYPT +GNUTLS +ACL +XZ +LZ4 -SECCOMP +BLKID +ELFUTILS +KMOD +IDN)
[    5.149648] SGI XFS with ACLs, security attributes, no debug enabled

通过上面的打印信息可以看到我当前的测试系统内核是默认支持ACL的,简单的来说ACL就是可以实现给文件指定单个用户/用户组设置权限,那下面就正式的来了解ACL的具体应用:

3.1设置文件访问控制列表的工具setfacl命令

 setfacl [-bkRd] [{-m | -x} acl参数] 目标文件名

setfacl命令的选项及参数解析:

acl参数:用来设置acl特殊权限的用户及权限,设置用户的acl权限格式【u:[使用者账号列表]:[rwx]】,设置用户组acl权限格式【g:[用户组账号列表]:[rwx]】;
-m:用于设置文件的acl有效权限以及有效权限范围,在acl参数中哟一个权限格式没有列出来【m:[rwx]】,这个acl参数表示文件的ACL权限访问,后面再设置具体的用户和用户组权限都要在这个权限范围内,超出这个权限范围无效;
-x:用于删除文件的acl指定某个有效权限,假设文件的acl有效权限是rx,可以通过这个选项删除acl有效权限中的r或x权限。
-b:删除所有ACL权限设置,文件的所有ACL权限设置都会被删除。
-k:删除文件默认的ACL参数,参考后面-d选项理解;
-R:递归设置ACL,即包括子目录都会被设置;
-d:设置默认ACL参数,即针对一个目录设置默认的ACL设置,在该目录下新建文件都会引用此默认ACL参数;

3.2获取文件的访问控制列表的工具getfacl命令

 getfacl [-aceEsRLPtpndvh] file ...

getfacl命令的选项及参数解析:

-a:显示文件范文控制列表;
-c:不显示注释;
-e:打印所有有效的权限注释,即使与ACL条目定义的权限相同;
-E:不发表有效权限的评论;
-s:跳过只有基本ACL条目(所有者、组、其他)的文件;
-R:递归列出所有文件和目录的ACL;
-L:逻辑遍历,跟随符号连接到目录。默认行为是跟随符号连接参数,然后跳过子目录中遇到的符号连接,与-R配合使用;
-P:物理遍历,不要跟随符号连接到目录。这也跳过了符号连接参数,与-R配合使用;
-t:使用另一种表格输出格式。
-n:列出数字类型的用户和组id;
-d:显示默认的访问控制列表;

getfacl命令简单的来说就是用来查看文件的ACL权限信息,没有什么具有功能性的操作,一般情况下都不使用选项查看文件的权限信息,在这部分内容中不会太多介绍,如果想深入的了解的话建议逐个测试即可。

3.3了解ACL设置技巧的基本操作

针对文件的特定使用者设置ACL权限:

 touch acl_test1  #创建一个空文件用来测试ACL权限的设置

 ll acl_test1  #查看文件信息,注意文件的权限信息:-rw-r--r--. 1 root root 0 7月  26 16:18 acl_test1

 setfacl -m u:vbird:rx acl_test1  #给测试文件设置用户vbird的ACL权限为rx,即vbird用户对测试文件具备了读取和执行权限

 ll acl_test1  #查看文件信息,注意文件的权限信息的变化:-rw-r-xr--+ 1 root root 0 7月  26 16:18 acl_test1

 getfacl acl_test1  #使用getfacl查看文件权限信息

 # file: acl_test1
 # owner: root
 # group: root   # ---上面都是注释部分---
 user::rw-    #表示文件拥有者的权限
 user:vbird:r-x  #针对vbird用户的权限设置为r-x
 group::r--     #表示用户组的权限
 mask::r-x     #次文件默认的有效权限
 other::r--     #其他人拥有的权限

通过上面的示例有两个需要注意的细节:

第一个是文件权限信息在没有设置ACL权限时最后一个字符是点".",设置了ACL权限以后变成了加号"+",这两者分别表示两种权限,点表示文件具有SELinux权限,加号表示文件具有ACL权限,这两个权限不是互斥的,也就是说设置了ACL权限以后,前面文件的SElinux权限表示的拥有者、用户组、普通用户的权限依然起作用。除了点和加号这两种情况,也有可能是空白的,这种情况出现在禁用了SElinux权限的时候创建的文件,该字符位置空白表示文件没有SELinux权限。

第二个是通过getfacl打印出来的信息中有一个mask字段,这个字段表示的是文件默认ACL权限,这是由文件所在的目录决定的,具体参考setfacl的-d选项解析。

针对文件的特定用户组设置ACL权限:

 setfacl -m g:testgroup:rx acl_test1  #给测试文件设置用户组testgroup的ACL权限问题rx

 getfacl acl_test1  #查看测试文件的ACL权限信息:

 # file: acl_test1
# owner: root
# group: root
user::rw-
user:vbird:r-x
group::r--
group:testgroup:r-x
mask::r-x
other::r--

给文件设置ACL的有效权限mask:

 setfacl -m m:r acl_test1  #给测试文件设置ACL有效权限为r

 getfacl acl_test1  #查看测试文件的ACL权限信息:
 # file: acl_test1
 # owner: root
 # group: root
 user::rw-
 user:vbird:r-x            #effective:r--
 group::r--
 group:testgroup:r-x        #effective:r--
 mask::r--
 other::r--

可以从权限信息中对比前面的示例中的值发现,文件acl_test1的ACL有效权限mask从rx变成了r。

给用户设置目录的ACL权限及默认权限:

 mkdir -m 700 acl_dir_test  #使用管理员账户在/tmp下创建这个目录,用于当前示例的测试目录

 ll | grep acl  #打印结果:drwx------.  2 root root      6 7月  26 18:41 acl_dir_test

 su vbird  #切换到普通用户

 cd acl_dir_test  #尝试进入这个目录:bash: cd: acl_dir_test: 权限不够

 su root  #切换到管理员身份

 setfacl -m u:vbird:rwx acl_dir_test  #给vbird用户设置ACL权限为rwx

 su vbird  #切换到普通用户

 cd acl_dir_test  #在vbird普通用户身份下进入目录,如果前面操作成功,这一次就可以以vbird身份进入这个测试目录了

 touch test1  #以vbird普通用户身份在这个目录下创建一个测试文件test1

 ll  #打印结果:-rw-r--r--. 1 vbird users 0 7月  26 18:54 test1

 getfacl test1  #查看文件详细的ACL权限信息
 # file: test1
 # owner: vbird
 # group: users
 user::rw-
 group::r--
 other::r--
 su root
 cd /tmp  #回到tmp目录

 setfacl -m m:rwx acl_dir_test  #在vbird用户身份情况下给这个目录添加ACL有效权限为rwx

 setfacl -m d:u:vbird:rw acl_dir_test  #但不能使用vbird用户身份给这个目录设置默认ACL权限

 su root  #切换到管理员身份

 setfacl -m d:u:vbird:rw acl_dir_test  #在管理员身份下可以正常设置

 getfacl acl_dir_test  #查看测试目录的ACL权限

 # file: acl_dir_test
 # owner: root
 # group: root
 user::rwx
 user:vbird:rwx
 group::---
 mask::rwx
 other::---
 default:user::rwx
 default:user:vbird:rw-
 default:group::---
 default:mask::rw-
 default:other::--- touch ./acl_dir_test/test2  #在测试目录下创建一个文件

 getfacl ./acl_dir_test/test2  #查看刚刚创建的这个文件的ACL权限信息

 # file: acl_dir_test/test2
 # owner: root
 # group: root
 user::rw-
 user:vbird:rw-  #可以看到刚刚创建的文件vbird用户就直接拥有了默认的权限
 group::---
 mask::rw-
 other::---

以上就是ACL权限设置的全部内容,它可以实现SELixnu权限之外给指定的用户和用户组设置独立权限,这个操作在日常的系统管理中还是比较常见的情况;

 四、用户身份切换

关于用户身份切换在之前的很多内容中就已经应用过su这个工具,但没有详细对这个工具做过解析,然后就是你可能发现在前面第三部分中关于ACL权限的示例中我多次使用了用户身份切换来回操作,这种操作非常的不方便,你可能会想要一个命令来实现身份切换并直接执行一个命令,并且执行完以后又回到原来的用户身份,这些都在su和sudo工具中有实现,下面直接来看具体的内容:

4.1su命令实现身份切换

 su [-lm] [-c 命令] [username]

su命令的选项及参数解析:

-:表示使用login-shell的读取变量文件方式来登入系统,如果没有"-"则代表切换为root身份,而不会重新读取root的相关环境配置数据;
-l:与-类似,但后面必须加上username,不然就是打印当前用户上次登入的信息,也是login-shell的方式(会重新读取相关环境配置数据);
-m:-m和-p一样,表示使用目前的环境设置,而不读取新使用者的方式;
-c:仅执行一次命令,所以-c后面可以加上命令;

切换用户的操作很简单,但是要注意操作是否会读取login-shell的配置数据,关于login-shell配置数据在Bash相关博客中已经由很详细的介绍了,如果需要了解可以参考:Bash与Shell,需要注意的是“-”操作与没有username的操作实现的管理员身份切换的环境配置数据的差别,详细参考“-”选项的解析,然后还可以通过-m来指定环境配置数据的读取方式,下面来看相关的示例操作:

 su  #切换到root,不会重新读取root的环境配置数据

 id  #打印结果:uid=0(root) gid=0(root) 组=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023 #id打印的信息已经可以确定用户身份切换到了root

 env | grep 'vbird'  #下面是输出的信息:

 USER=vbird  ==>居然还是vbird
 PATH=/usr/lib64/qt-3.3/bin:/usr/local/bin:/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/vbird/.local/bin:/home/vbird/bin
 MAIL=/var/spool/mail/vbird
 PWD=/home/vbird  ==>不是root的home目录
 LOGNAME=vbird
 XDG_DATA_DIRS=/home/vbird/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share

 exit  #可以通过退出当前su的进程切换到原来的用户

关于"-"和"-l"这里就不演示了,它们都会重读用户环境配置数据,如果在这两个选项基础上仅仅只需要切换用户而不需要重读用户环境配置数据可以使用“-m”实现,下面再来看-c的示例:

 su - -c "head -n 3 /etc/shadow"  #shadow文件只有root权限才可以读取,下面是输出结果:

 root:$6$AGZMONJrgTvV6C6A$kCLEhhUovrFUeA6d283mJdS0wtkRUvxWLy2V.4An8wW9VtRnqLliZzb1GoTIZDDpYHNXpgintQFF24IiKE45m/::0:99999:7:::
 bin:*:18353:0:99999:7:::
 daemon:*:18353:0:99999:7:::

 # ==> 能输出数据说明su -肯定是切换到了root身份,但执行完以后当前终端的用户身份依然还是之前的用户身份,这就是-c的特性;

4.2使用sudo实现其他用户执行命令

在前面的su中如果要切换到管理员身份,每一次都必须使用管理员的密码登入,而且在现实的系统管理中又不可避免的需要使用一些管理员身份可执行的命令,如果使用su那岂不是每个需要使用到管理员命令的用户都会知道root账户的密码,这会对系统管理造成非常大的风险,而基于sudo只需要使用用户自身账户的密码就可以执行管理员命令,这就解决了管理员密码被多人使用的风险,下面先来看sudo的语法:

 sudo [-b] [-u 新使用者账号]

sudo的语法及参数解析:

-b:将后续的命令放到后台中让系统自行执行,而不与目前的shell产生影响;
-u:后面可以接要切换的用户名称,如果不使用这个选项就表示切换为root身份;

在默认情况下sudo命令只能使用root身份才能执行,所以sudo必须要配合visudo配置授权给普通用户身份才能实现以其他用户身份执行名,关于visudo后面再详细解析,这里先来看sudo的使用示例:

 sudo -u sshd touch /tmp/mysshd  #需要在root用户下执行这行测试命令

 ll /tmp/mysshd  #查看文件信息:-rw-r--r--. 1 sshd sshd 0 7月  27 20:03 /tmp/mysshd

这里使用sshd用户测试还有另一个原因,就是sshd用户是一个系统用户,没办法使用su切换到sshd用户的shell环境,所以要使用这类不能使用su切换的情况但又需要这类用户的身份执行一些命令就可以使用sudo这个工具来实现,当然这只是sudo很简单的应用之一,下面来了解如何让普通用户使用自己的账户密码执行管理员的命令,在了解这部分内容之前需要理解sudo的执行流程:

sudo的执行流程:

1.当用户执行sudo时,系统通过/etc/sudoers文件中查找该用户是否有执行sudo的权限,这里指的是执行sudo命令的用户也就是当前登入的用户;

2.若用户具有可执行sudo的权限,就让用户【输入自己的密码】来确认,如果当前是root执行sudo就不需要输入密码;

3.密码输入验证正确后,就开始基于-u执行的用户身份执行后续的命令;

4.如果-u指定的用户身份与当前shell环境用户身份相同也不需要输入密码;

根据前面的介绍可以知道,要实现普通用户执行sudo命令,需要基于/etc/sudoers文件中的配置信息,简单的来说就是在/etc/sudoers中配置用户可执行权限,这个文件可以直接使用vim编辑器,但不建议这样做,通常情况下是使用visudo命令进行编辑,编辑操作与vim一样,但visudo可以以安全模式编辑sudoers,实现锁定sudoers文件防止多个编辑同时进行,visudo命令还提供了一些语法检查和一些其他功能,详细查看man文档。

下面就是用visudo命令来打开/etc/sudower,先看看文件中的内容,然后在编辑:

 visudo  #在root用户身份下执行

往下找到这行文件内容:

 # 使用者账号  登入者的来源主机名称=(可切换的身份)  可执行的的命令  ==>这一行实我在这里添加的注释,对应理解下面的数据

   root        ALL=(ALL)                    ALL

上面这四个主件的就是表示用户执行sudo命令的授权范围,分别表示:

使用者账号:表示那个用户可以使用sudo这个命令;

登入者的来源主机名称:表示用户可以用哪些客户机连接本机执行sudo命令;

可以切换的身份:表示执行sudo命令的用户可以切换哪些用户来执行后续的命令;

可执行命令:表示该用户可以执行哪些命令;

 /etc/sudoers在未被修改的时候只有root一个用户的默认配置数据,值得一提的是root这个默认数据中三个ALL表示的是任意所有的意思,即用户任意主机登入、用户可切人当前系统上任意用户身份执行命令、用户可使用任意命令;

sudoers配置信息可以实现用户授权,还可以实现用户组授权下面就通过visudo来修改sudoers来测试sudo的相关功能:

单一用户可使用root所有命令:

 #给sudoers添加vbird用户,让他拥有使用root任意命令的权限

 vbird  ALL=(ALL)  ALL

编辑保存以后,再来使用以下命令来测试:

 su vbird  #切换到vbird用户下

 tail -n 1 /etc/shadow  #然后在vbird用户下读取shadow文件,报:tail: 无法打开"/etc/shadow" 读取数据: 权限不够;因为不是root身份肯定不能查询shadow

 sudo tail -n 1 /etc/shadow  #没有使用-u执行切换用户就表示切换的是root,这在选项解析中就解析过了
 我们信任您已经从系统管理员那里了解了日常注意事项。  ==>这是一些提示信息
 总结起来无外乎这三点:        
    #1) 尊重别人的隐私。
    #2) 输入前要先考虑(后果和风险)。
    #3) 权力越大,责任越大。
 [sudo] vbird 的密码:          ==>这里是输入vbird用户的密码
 vbird:$6$3mHWGZkl$eH.Ck3cLVuJbSQAUKynTHoAbZ9NRuom9XTTtmDFwXSLFbb2YkFBGyeMrN.OMWPKS17/c7Eu0XawO80qHRVxN01:19197:0:99999:7:::

用户组所有成员使用root所有命令:

通过前面单一用户的授权可以看到,一个用户就要编辑一行配置信息,如果需要授权多个用户一样的权限,岂不是要写除了用户名以外很多条同样的配置信息,不用当心这个问题,下面就来通过演示用户组授权的方式解决这个问题:

 exit  #退出vbird用户的shell环境,回到root用户环境下

 groupadd sudotest  #创建一个用户组用来测试(在sudoers中有一个wheel用户组的配置,正式配置系统管理员用户组可以使用,这里自定义一个用户组用来测试)

 gpasswd -a vbird sudotest

 gpasswd -a tx sudotest  # ==>给用户添加两个用户用于测试

 grep sudotest /etc/group  #查看用户组的信息,确认用户组创建和成员添加正确:sudotest:x:1002:vbird,tx

 visudo  #当然前面vbird用户已经可以切换root用户身份执行任意命令,但需要注意这个任意并不能真的任意,比如visudo命令普通用户即便获得sudoers的ALL授权也不能使用

 #下面是编辑的内容

 %sudotest       ALL=(ALL)       ALL  #给sudoers添加sudotest用户组,让他使用root任意命令,为了方便测试,我将前面配置的vbird用户删除了(注意注释部分不要编辑进去了)

 #写入保存sudoers刚刚的编辑以后,切换用户测试

 su vbird

 sudo tail -n 1 /etc/shadow  #可以看到vbird用户依然可以使用自己的密码切换到root身份执行管理员命令

 [sudo] vbird 的密码:
 vbird:$6$3mHWGZkl$eH.Ck3cLVuJbSQAUKynTHoAbZ9NRuom9XTTtmDFwXSLFbb2YkFBGyeMrN.OMWPKS17/c7Eu0XawO80qHRVxN01:19197:0:99999:7:::

 exit  #退出当前vbird用户进程

 su tx  #再切换到tx用户下测试

 sudo tail -n 1 /etc/shadow

 我们信任您已经从系统管理员那里了解了日常注意事项。
 总结起来无外乎这三点:

    #1) 尊重别人的隐私。
    #2) 输入前要先考虑(后果和风险)。
    #3) 权力越大,责任越大。

 [sudo] tx 的密码:
 vbird:$6$3mHWGZkl$eH.Ck3cLVuJbSQAUKynTHoAbZ9NRuom9XTTtmDFwXSLFbb2YkFBGyeMrN.OMWPKS17/c7Eu0XawO80qHRVxN01:19197:0:99999:7:::

 #可以看到tx也获得了授权,这就是通过用户组的方式实现sudo授权

这里稍微提一下用户组授权和用户授权的区别,给用户组授权时要在用户组名称前加上百分号(%),其他的与用户授权设置一样;

通过sudoers配置实现有限制的命令操作:

前面讲过sudoers中的ALL表达的是任意不限制的意思,也就是说sudo授权可以限制用户的登入主机、切换用户、执行命令。以可执行命令来说可以给用户配置可执行命令文件(完整路径),来指定用户可执行的命令,还可以在文件名前面加上感叹号(!)来禁止用户不可执行指定的命令,下面来看示例:

 visudo

 #编辑以下内容,还是跟前面示例一样,为了方便准确的测试,先将sudotest群组从配置中删除

 vbird   ALL=(root)       !/usr/bin/passwd,/usr/bin/passwd [A-Za-z]*,!/usr/bin/passwd root

 #编辑完以后,写入退出

简单的来解释一下上面这行配置:用户vbird可以在任意主机登入,可以切换root用户身份执行passwd命令,但禁止passwd没有任何参数的执行和参数为root的执行。

从2.2中的相关内容知道passwd没有参数默认表示修改root用户的密码,所以上面这一行配置实现的就是用户vbird可以修改其他用户的密码,但不能修改root用户的密码。

通过别名创建visudo:

在前面为了同时使多个用户可以使用sudo命令,采用了用户组授权的方式,这是基于系统用户管理机制实现的,在sudoers内部还可以通过别名的方式来实现多个用户同时授权,简单的来说就是在sudoers中创建一个用户别名,让多个用户通过这个别名来获得授权。别名的方式除了可以同时给多个用户授权,还可以实现多个命令采用一个别名管理,其他字段同理可以使用别名的方式实现。

User_Alias 用户别名 = 用户名1,用户名2,用户名3...    #创建用户别名的语法
Host_Alias 主机别名 = 主机名1,主机名2,主机名3...  #创建主机别名的语法
Cmnd_Alias 命令别名 = 命令文件1,命令文件2,命令文件3...  #创建命令别名的语法

sudoers别名的示例:

 visudo  #编辑一下内容:

 User_Alias ADMPW = vbird, tx
 Cmnd_Alias ADMPWCOM = !/usr/bin/passwd, /usr/bin/passwd [A-Za-z]*, !/usr/bin/passwd root
 ADMPW   ALL=(root)      ADMPWCOM

使用sudoers别名时需要注意的是,所有别名都需要使用大写字符。

关于sudo的使用时有时候不需要输入用户密码的现象,这是系统相信你在一定时间内不会离开,是同一个人在管理系统,所以在五分钟内连续使用sudo是不需要输入用户密码的。

最后关于用户切换,在日常系统管理中难免需要切换root身份,同样可以使用sudo来实现使用普通用户密码切换到root身份,具体的sudoers配置如下:

 vbird  ALL=(root)  /bin/su -

通过这一段配置,vbird就可以使用自己的账户密码切换到root身份了,切换命令: sudo -u root su - 或 sudo su - 都可以实现。

 五、用户特殊shell与PAM模块

5.1特殊的shell

还记得在Bash与Shell那篇博客中提到的/sbin/nologin吗?没错,这里所说的特殊shell就是用来给不能获取shell环境的用户登入的nologin产生的一种特殊shell,使用这个shell登入的用户不能使用bash和其他有shell环境的shell来登入系统,简单的来说就是通过特殊shell即nologin登入的用户不能使用命令来使用系统资源,但不代表它们不能使用系统资源,它们可以通过它们相对应的服务程序来使用系统资源,比如FTP服务的用户它可以通过FTP服务来通过网络IO接口读写系统数据。

 grep mail /etc/passwd  #查看系统上的邮箱账号,比如我的测试机上的默认邮箱账号:mail:x:8:12:mail:/var/spool/mail:/sbin/nologin

 su mail  #尝试使用su切换mail用户

 #数据信息:This account is currently not available.

不能使用shell环境不代通过nologin的特殊shell登入的用户就什么都不干,比如用户使用特殊shell登入时它要负责帮助用户去找到相关的验证模块,告诉验证模块应该使用什么样的验证类别,还可以告诉验证模块验证完以后应该给这个特殊的shell返回什么样的结果,即验证的控制标识。这个特殊的shell根据这些控制标识输出相应的验证信息,并且决定是否继续接下来的验证操作。

下面先来看自定义配置一段nologin用户使用su尝试基于shell环境的登入的提示信息:

 vim /etc/nologin.txt  #下面是编辑的文本数据

 当前账号为系统账号或邮件账号
 请求不要使用此账号登录Linux服务器

 #然后写入保存/etc/nologin.txt后,再使用su尝试使用邮件用户登入shell

 su mail  #下面会打印:

 当前账号为系统账号或邮件账号
 请求不要使用此账号登录Linux服务器

5.2PAM模块

通过上面的示例可以看到账号登入的这种信息交互,这是Bash的标准登入交互模式。既然非正常shell用户不能时使用bash或其他shell登入系统,简单的说就是特殊的shell即nologin用户不能使用bash的程序登入系统,它们都会有自己特定的登入方式,比如示例中的邮件账户有自己的邮件系统登入程序、还有后面的http账号有自己的网络服务登入程序,但不论哪一种登入方式都有自己的一套自己的登入认证机制,为了解决不同的用户登入机制的差异性问题,就有了PAM(Pluggable Authentication Modules)插入式验证模块的机制,这套机制它不提供具体的验证程序,而是定义了一套标准的登入认证接口,不同的服务根据这套标准的登入认证接口实现具体的登入验证程序,就可以让所有服务的用户登入都看起来是一致的,可以简单的说这些特殊的用户基于PAM的验证接口登入可以和shell登入感觉是一样的。

一般情况下一个验证程序需要经过多个验证过程,每一个验证过程为一个模块,也被称为PAM模块,下面是PAM模块与应用程序的关系图:

这些PAM验证模块由相应的应用程序来提供,然后通过PAM的配置文件来组织多个模块实现一个应用服务的账号登入认证的整个过程。实际上基于/etc/bin/passwd登入的Bash和其他shell也采用的是PAM验证机制,也就是示图中的Linux system实际上也是系统服务应用程序,它们实现的用户登入验证程序也是基于标准的PAM验证接口,下面就通过passwd的PAM流程与其PAM模块配置文件来理解它的登入验证过程:

1.用户开始执行/usr/bin/passwd这个程序,并输入密码;

2.passwd调用PAM模块进行验证;

3.PAM模块会到/etc/pam.d寻找与程序passwd同名的配置文件;

4.根据/etc/pam.d/passwd内的设置,引用相关的PAM模块逐步进行验证分析;

5.将验证结果(成功、失败以及其他信息)返回给passwd这个程序;

6.passwd这个程序会根据PAM返回的结果决定下一个操作(重新输入新密码或通过验证)。

以上是基于passwd登入整个逻辑过程,具体的验证过程是基于/etc/pam.d目录下的passwd同名的配置实现,可以通过文件数据读取工具来查看这个配置信息:

 cat /etc/pam.d/passwd  #下面是这个配置文件的具体数据:

 #%PAM-1.0
 auth       include    system-auth
 account    include    system-auth
 password   substack    system-auth
 -password   optional    pam_gnome_keyring.so use_authtok
 password   substack    postlogin

在这个配置文件中的第一行声明了PAM版本,其他任何【#】开头的都是注释,而每一行都是一个独立的验证流程,从上面打印的数据来看每个验证配置信息包含三个字段分别表示的是:验证类别(type)、控制标准(flag)、PAM的模块与该模块的参数。

这三个字段需要重点来了解它的前两个字段,第一个字段验证类别主要分为四种,第二个字段验证控制也分为四种表示用于管控验证的控制方式,下面来看它们的及具体解析:

PAM验证的四种主要类别:

auth:表示认证(authentication)的意思,用来检验用户的身份,通常是需要账号密码来检验,所以后续的模块用来检验用户身份;

account:表示账号(account)授权(authorization)的意思,用来检验用户是否具有正确的权限。比如使用一个过期的密码来登入时,就无法正确的登入;

session:表示会话期间的意思,session管理的就是用户这次登入(或使用命令)期间,PAM给予的环境设置。这个类别通常用于记录用户登入与注销时的信息,如经常常使用的su和sudo命令,在/var/log/secure日志里面就会发现很多关于PAM的说明,这些数据记录的就是【session open、session close】的信息;

password:就是密码的意思,这个类别提供的就是验证修订任务,比如修改密码时后面的PAM模块负责验证密码在修改账号密码;

这四个验证类别通常是有顺序的,不过也有例外。有顺序的原因是验证身份是必须的第一步操作,然后第二步再检验用户的权限才可以对用户授权,有了授权用户才可以进行后续的操作。第三步会话期间是用户在进行相关操作时,需要应用程序与终端进行的交互,这些交互需要有授权的环境才能进行,并且回对关键的操作进行日志记录;第四步可能与第三步可能就没有完整现后的顺序了,但修改密码肯定是需要在会话开启以后才可以进行,也必然会在注销之前。

PAM验证的四种主要控制标识:

required:表示当前PAM模块验证完以后,不论成功还是失败都会继续后续的验证流程;

requisite:表示当前PAM模块验证完以后,如果成功继续后续的验证流程,否者为失败时终止验证流程;

sufficient:表示当前PAM模块验证完以后,如果成功则返回验证成功的消息,无论前面的验证是否失败,而且也不再执行后续的验证了。简单的说就是当前PAM验证成功,就可以通过验证并登入;

optional:表示当前PAM模块即使验证失败,也允许应用程序提供服务。简单的来说就是会忽略当前的验证,继续按顺序执行下一个模块的验证,这个模块大多用来显示信息,并不用在验证方面;

在passwd的PAM配置文件中还出现include、substack这两个控制标识,它们分别表达的含义是:

include:表示当前PAM模块包含一个新的配置文件进行验证,简单的来说就是在这个模块验证的过程中会调用其他验证模块;

substack:与include一样表示包含一个新的配置文件进行验证,但substack要等待调用文件执行完;

 以上就是PAM的配置文件解析的全部内容,下面是PAM控制标识所造成的返回流程图:

 

 一般情况下,作为系统管理不需要具体去实现PAM验证模块的编程,通常只需要开发者提供PAM模块和应用登入需要经过的验证过程文档,更具文档编写配置文件才是系统管理员需要做的工作,但这要看具体的项目成员的分工合作方式,如果需要自己编写PAM模块,可以参考Linux的官方文档:Linux-PAM中文文档,谈完配置文件的语法,来看看CentOS7.x提供的登入认证的PAM模块文件内容:/etc/pam.d/login

 cat /etc/pam.d/login  #下面是文件的具体数据:

#%PAM-1.0
auth [user_unknown=ignore success=ok ignore=ignore default=bad] pam_securetty.so
auth       substack     system-auth
auth       include      postlogin
account    required     pam_nologin.so
account    include      system-auth
password   include      system-auth
# pam_selinux.so close should be the first session rule
session    required     pam_selinux.so close
session    required     pam_loginuid.so
session    optional     pam_console.so
# pam_selinux.so open should only be followed by sessions to be executed in the user context
session    required     pam_selinux.so open
session    required     pam_namespace.so
session    optional     pam_keyinit.so force revoke
session    include      system-auth
session    include      postlogin
-session   optional     pam_ck_connector.so

通过上面的login的配置信息,就可以推断出各个服务的用户登入认证的过程,为了更好的理解每个模块对应的认证功能,还可以去查看login配置的模块调用的其他PAM模块和相关信息,对以后自己配置PAM也有启发意义,这些模块基本都在这几个目录下:

/etc/pam.d/*:每个程序的PAM配置文件
/lib64/security/*:PAM模块文件的实际存放目录
/etc/security/*:其他PAM环境配置文件
/usr/share/doc/pam-*:详细的PAM说明文件

下面介绍几个常见的PAM模块:

pam_securetty.so:限制系统管理员(root)只能从安全的终端secure登入,所谓终端这在Linux相关的第一篇博客就有说过,相关设置写在/etc/securetty这个文件中。

pam_nologin.so:这个模块可以限制一般用户是否能够登入主机。如果/etc/nologin这个文件存在时,则所有一般用户均无法再登入系统,而对root以及已登入系统的账号没有影响;

pam_seLinux.so:SELinux是针对程序进行详细管理权限的功能,在后期进程相关博客中会详细介绍;

pam_console.so:当系统出现一些问题时,或是某些时候需要使用特殊的终端接口(例:RS232终端设备),这个模块可以帮助处理一些文件权限,让用户可以通过特殊的终端接口顺利的登入系统;

pam_loginuid.so:在前面介绍过UID的数值范围的一些规范,配合这个PAM模块可以验证当前用户的UID是否是我们需要的数值;

pam_env.so:用来设置环境变量的一个模块,如果需要设置额外的环境变量,可以参考/etc/security/pam_env.conf这个说明文件;

pam_unix.so:用于实现验证阶段的认证功能、授权阶段的账号许可证管理、会话阶段的日志文件记录等,甚至还可以用在密码更新阶段的检验;

pam_pwquality.so:用来检验密码的强度,包括密码是否在字典中、密码输入几次都失败就中断此次连接等功能;

pam_limits.so:这个模块用来验证用户当前资源现额,在Bash那篇博客中介绍的ulimit工具吗,它实现的用户资源配额设置就决定了这个模块的验证结果;

 最后再来总结一下login的PAM验证流程:

1.验证阶段(auth):pam_securetty.so判断,如果用户是root则参考/etc/securetty的设置-->pam_env.so设置额外的环境变量-->pam_unix.so检验密码-->pam_succeed_if.so判断UID是否大于1000,小于1000返回失败,否则再往下以pam_deny.so拒绝连接;

2.授权阶段(account):pam_nologin.so判断/etc/nologin是否存在,如果存在则不允许一般用户登入-->pam_unix.so、pam_localuser.so进行账号管理-->pam_succeed_if.so判断UID是否小于1000,如果小于1000则不记录登入信息-->最后以pam_permit.so允许账号登入;

3.密码阶段(password):pam_pwquality.so设置密码参数错误3次,pam_unix.so通过512、shadow等功能进行密码检验,如果通过返回login程序,否则以pam_deny.so拒绝登入;

4.会话阶段:pam_selinux.so暂时关闭SELinux-->pam_limits..so设置用户能够操作的系统资源-->开始记录相关信息到日志文件中-->以pam_loginuid.so规范授权不同UID的权限-->开启pam_selinux.so的功能;

 以上就是简单的将PAM相关内容做的一个汇总,关于PAM在Linux安全运维中会有详细的介绍,涉及PAM的编程在Linux高级运维中再找机会介绍。一下在添加几个帮助理解的文档和博客连接:

Linux-PAM中文文档

Linux PAM 可插拔认证模块介绍

PAM详细介绍

Linux系统的PAM模块认证文件含义说明总结

 六、主机上用户信息传递

6.1查询用户

查看最近登入的用户可以使用last工具,还有查看当前登入的用户及其正在进行的操作信息可以使用w工具,只的查看当前登入的用户可以使用who工具,查看指定用户的登入信息可以使用lastlog,lastlog同样可以差异查看所有用的登入信息,lastlog与last差不多,lastlog基于用户读取对应的登入数据,last基于最近登入的用户信息,last不会输出为登入的用户信息,而lastlog则会按照用户列表全部显示。

下面就简单的列举一些这些命令查询的数据:

 last  #查看最近的用户登入信息:
 root     pts/0        192.168.1.102    Mon Aug  1 00:24   still logged in   
 tx       :0           :0               Mon Aug  1 00:23   still logged in   
 reboot   system boot  3.10.0-1160.el7. Mon Aug  1 00:21 - 00:44  (00:22)    
 tx       :0           :0               Sun Jul 31 20:53 - crash  (03:28)    
 reboot   system boot  3.10.0-1160.el7. Sun Jul 31 20:48 - 00:44  (03:56)

 w  #查看当前登入的用户及正在进行的操作,第一行会打印当前的时间、系统这次启动的时长、几个用户使用者在系统上平均负载;后面的数据按照第二行的各项名称了解即可。
 00:45:18 up 23 min,  2 users,  load average: 0.00, 0.05, 0.21
 USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
 tx       :0       :0               00:23   ?xdm?   1:32   0.69s /usr/libexec/gnome-session-binary --session gnome-classic
 root     pts/0    192.168.1.102    00:24    6.00s  0.41s  0.05s w

 who  #查看当前登入的用户
 tx       :0           2022-08-01 00:23 (:0)
 root     pts/0        2022-08-01 00:24 (192.168.1.102)

 lastlog -u vbird  #查看指定用户的登入信息,也可以不加任何选项和参数查看所有用户的登入信息
用户名           端口     来自             最后登陆时间
vbird            pts/2                     四 7月 28 15:25:52 +0800 2022

关于查看用户登入信息的相关命令非常简单,就不多做解析了,自行测试理解即可。

6.2用户对谈:write、mesg、wall

简单的来说就像通讯软件一样,通过命令发送消息,这三个工具也非常的简单,write实现向指定的用户发送消息、wall实现向系统上所有用户发送消息;mesg用来控制用户终端的写访问权限。

使用write向用户发送消息,需要指定用户的名称和终端(测试时没有写端口也成功了),那么在发送消息前就可以通过who查看当前系统上的用户及端口信息:

 who  #查看当前系统上的用户及终端信息:

 root     pts/0        2022-08-01 15:37 (192.168.1.102)
 tx       pts/1        2022-08-01 15:32 (:0)

 write 使用者账号 [使用者所在终端界面]  #语法

 write tx pts/1  #在当前root终端上向tx用户发送消息,执行这行命令以后就会等待输入消息的内容:

 ...  # ==>  这里输入要发送的消息内容(可以多次发送),如果要结束消息发送可以使用【ctrl+d】结束消息发送,消息接收方直接按【enter】退出消息接收。

需要注意的是,当消息接收方正在查数据,这时候如果收到消息,原本查数据的任务就会被中断,所以这时候就可以使用mesg n禁止用户终端的写访问权限,简单的说就是禁止别的用户给自己发送消息,但这个禁止不能阻止root发送过来的消息。如果root用户终端使用mesg n禁止用户终端的写访问权限,root自己都不能发送消息。

最后就是使用wall广播消息,所有登入的系统用户都会接收到这条消息:

 wall "大家好呀!"

6.3用户邮箱:mail

发送邮件:

 #在控制台上使用标准输入编辑邮件内容并发送

 mail -s "邮件标题" 用户名  #执行命令后输入邮件内容

 # - - - - 这里是邮件内容 - - - - -

 .  #当输入接收以后,最后一行输入小数点"."然后回车就可以结束输入,并将邮件发送出去

 #使用文本编辑器编辑邮件内容,然后再使用bash的数据重定向和管道命令发送邮件

 vim mailtest  #随便编辑一些内容并保存文件

 mail -s "vimtxt" tx < ./mailtest  #使用bash的数据重定向将mailtest的文件数据用邮件发送给tx用户

 cat mailtest | mail -s "catvitxt" tx  #使用管道命令将mailtest的文件数据用邮件发送给tx用户

接收邮件:

 mail  #直接执行就会打印出当前用户的邮箱列表

 "/var/spool/mail/tx": 3 messages 2 new  #这里表示总共有三个邮件,有两个未读的新邮件
    1 root                  Mon Aug  1 16:57  20/620   "abc"
>N  2 root                  Mon Aug  1 17:13  20/623   "vimtxt"  #">"表示当前处理的邮件,直接按下回测件就可以查看这封邮件
 N  3 root                  Mon Aug  1 17:15  20/625   "catvitxt"  #查看完上一封邮件以后可以使用"next"子命令查看这封邮件
&  #在这里输入"?"可以查看mail的子命令的说明,参考说明测试即可

当前的邮件应用还是基于本机的用户而言,后面会有专门解析邮件系统,会介绍如何发送网络邮件。

 七、CentOS7环境下大量创建账号

 7.1一些账号检查工具

pwck:用于检查密码文件,实际上就是对比/etc/passwd和/etc/shadow的信息是否一致,如果/etc/passwd中的数据段有误时,会提示用户修正,比如下面是我的测试结果:

 pwck  #下面是打印结果

 用户“gluster”:目录 /run/gluster 不存在
用户“saslauth”:目录 /run/saslauthd 不存在
用户“pulse”:目录 /var/run/pulse 不存在
用户“hacluster”:目录 /home/hacluster 不存在
用户“cockpit-ws”:目录 /nonexisting 不存在
用户“gnome-initial-setup”:目录 /run/gnome-initial-setup/ 不存在
用户“oprofile”:目录 /var/lib/oprofile 不存在
pwck:无改变

从打印结果来看,就只有用户home目录不存在的提示,由于这些用户确实也用不着home目录,所以实际上这个提示不算错误。

然后就是密码转换相关的工具,实际上就是指密码在/etc/passwd和/etc/shadow文件之间的密码数据转移,下面就来看pwconv、pwunconv、chpasswd三个工具的详细解析:

pwconv:简单的来说这个工具就是可以基于passwd中的密码数据生成shadow的密码数据,如果使用useradd这个工具增加用户passwd和shadow的数据是相匹配的,不会需要pwconv处理,但如果是手动设置账号,这个pwconv就很重要了。

pwunconv:这个工具可以实现将shadow中的密码栏数据写回passwd中,并且会删除shadow文件,这个工具一般使用不到,最好也不要测试,如果实测了将shadow文件删除,一定记得使用pwconv恢复shadow文件。

chpasswd:可以实现将未加密的的密码进行加密并写入/etc/shadow中,这个在大量创建账号时经常使用。

 比如系统中有一个vbird2的账号,可以使用chpasswd实现密码更新:

 echo "vbird2:abcdefg" | chpasswd

7.2实现大量创建账号的模板脚本

 cd /tmp

 vim accountadd.sh  #下面是脚本的全部内容

#!bin/bash
#这个shell脚本可以实现创建大量的linux登入账户;
#1.检查accountadd.txt是否存在,该文件用于每行一个用户名,提供给脚本用于用户创建;
#2.使用openssl创建用户密码;
#3.用户首次登入需要修改密码;
export PATH=/bin:/sbin:/usr/bin:/usr/sbin
#用户输入
usergroup=""        #如果账号需要指定从属组,请手动添加,不添情况下没设置默认从属组
pwmech="openssl"    #需要输入"openssl"或"account",当为"openssl"随机生成6位字符的密码,当为"account"时使用用户名作为密码
homeperm="no"        #如果输入"yes",home目录权限将修改为711
#检查accountadd.txt文件
action="${1}"        #当参数值为“create"时表示创建,当值为”delete"表示删除
if [! -f accountadd.txt ]; then
    echo "没有accountadd.txt文件,程序已停止!"
    exit 1
fi
[ "${usergroup}" !="" ] && groupadd -r ${usergroup}    #当指定从属用户组时,创建该用户组
rm -f outputpw.txt                    #当outputpw.txt文件存在时,删除该文件
usernames=$(cat accountadd.txt)                #读取要创建的用户名称
for username in ${usernames}
do
    case ${action} in
        "create" )
            [ "${usergroup}" !="" ] && usegrp=" -G ${usergroup} " || usegrp=""
            useradd ${usegrp} ${username}            #建立新账号
            [ "${pwmech}" == "openssl" ] && usepw=$(openssl rand -base64 6) || usepw=${username}
            echo ${usepw} | passwd --stdin ${username}    #建立密码
            chage -d 0 ${username}                #设置账号密码过期,第一次登入就需要修改密码
            [ "${homeperm}" == "yes" ] && chmod 711 /home/${username}    #根据配置信息修改home目录权限
            echo "username=${username}, password=${usepw}" >> outputpw.txt    #将用户账号和密码保存到outputpw.txt文件中
            ;;
        "delete" )
            echo "删除用户${username}"
            userdel -r ${username}
            ;;
        *)
            echo "参数示例:$0 [create|delete]"
            ;;
    esac
done

编辑保存好accountadd.sh脚本以后,下面接着创建accountadd.txt要创建用户的名单文件,然后使用脚本创建脚本:

 vim accountadd.txt

std01

std02

std03

std04

std05

 #编辑保存以后,执行脚本创建用户账号

 sh accountadd.sh create

 # ... ==>这里会打印出创建账号的相关输出内容

 cat outputpw.txt  #查看刚刚创建的账号及密码,可以使用密码登入账号,第一次登入需要修改密码

 #测试完以后,还可以使用刚刚的脚本删除这些测试账号

 sh accountadd.sh delete

 

这篇关于Linux操作系统(十):Linux账号管理与ACL权限设置的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!