Linux基础学习笔记之——账号管理与ACL权限设定

Linux 账号管理与 ACL 权限设定

1、Linux 的账号与群组

1.1、使用者标识符:UID 与 GID

虽然我们登陆 Linux 主机时,输入的是我们的账号,但是其实 Linux 主机并不会直接认识我们的 “账号名称” 的,它仅认识 ID 。那文件如何判别它的拥有者和群组呢?其实就是利用 UID 和 GID 了!每一个文件都会有所谓的拥有者 ID 和 群组 ID,当我们要要显示文件属性的需求时,系统会依据 /etc/passwd 与 /etc/group 的内容,找到 UID 和 GID 并显示出来!我们可以做一个小实验:

#1、先检查以下有没有 li 的账户
[root@li testpw]# id li
uid=1000(li) gid=1000(li)=1000(li)	#确实有这个账户

[root@li testpw]# ll -d /home/li
drwx------. 2 li li 83 8月   5 16:52 /home/li	#使用的是 li 本身
#2、修改一下,将 li 的 UID 1000 修改为 2000 看看:
[root@li testpw]# vim /etc/passwd
[root@li testpw]# cat /etc/passwd
...
li:x:2000:1000:li:/home/li:/bin/bash		#修改后的数据
[root@li testpw]# ll -d /home/li
drwx------. 2 1000 li 83 8月   5 16:52 /home/li		
#变成了 1000,因为我们乱改,导致 1000 找不到对应的账号,所以显示数字了!记得改回来!!!因为涉及到很多的权限问题!

如果没有进入 /etc/passwd 改回来会发生什么情况呢?那么当 li 下次登录时将没有办法进入自己的家目录!!!因为它的 UID 已经改为了 2000,但是它的家目录却记录的是 1000,由于权限是 700,所以它将无法进入原本的家目录!

1.2、使用者账号

你在登录主机时,输入账号密码后,系统帮你处理了什么呢?

  1. 先找寻 /etc/passwd 里面是否有你的账号?如果没有则跳出,如果有的话则将该账号对应的 UID 与 GID 找出来(在 /etc/passwd 中),另外,该账号的家目录与 shell 也一并读出来;
  2. 再来则是核对密码了!这时 Linux 会进入 /etc/shadow 里面找出对应的账号与 UID,然后核对输入的密码与里头的密码是否一致?
  3. 如果一切 OK 的话,就进入 Shell 控管阶段了!

1.2.1、/etc/passwd 文件结构

每一行代表一个账号,有几行就代表有几个账号在你的系统中!里边有很多账号是系统运行所必须的,简称为系统账号,例如:bin、daemon、nobody、adm等。

[root@li ~]# 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

可以看到,每一行使用 “:” 隔开,一共有7 段,分别是:

  1. 账号名称

  2. 密码

    只有一个 x,具体的密码放在 /etc/shadow 里边

  3. UID

    id 范围 说明
    0
    (系统管理员)
    当 UID 为 0 时,代表该账号就是 “系统管理员”。所以当你要让其他账号也具有 root 权限的时候,将该账号的 UID 改为 0 即可。
    1~999
    (系统账号)
    系统运行所必须的账号
    1000~60000
    (可登录账号)
    一般使用者的账号
  4. GID

    这个与 /etc/group 有关

  5. 用户信息说明

  6. 家目录

  7. Shell

1.2.2、/etc/shadow 文件结构

[root@li ~]# head -n 4 /etc/shadow
root:$6$Wut1Cw0fCGVGBkEF$H/OVyZf7Y00AQEASWVcyFvo2ZBgv4pgH3Qp5QuFH8bOZXKgxZw0CaiZ/...
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::

同样是以 “:” 作为分隔符,一共有 9 段,分别是:

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

1.3、关于群组:有效群组与初始群组、groups,newgrp

1.3.1、/etc/group 文件结构

[root@li ~]# head -n 4 /etc/group
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:

还是以 “:” 作为分隔符,一共有 4 段,分别是:

  1. 组名
  2. 群组密码
  3. GID
  4. 此群组支持的账号名称

看完了 /etc/passwd、/etc/shadow 和 /etc/group 之后,我们来梳理一下 UID、GID 和密码之间的关系。其实重点是 /etc/passwd,其他数据都是根据这个文件的字段去查找的:

在这里插入图片描述

1.3.2、有效群组和初始群组

还记得每个账号在他的 /etc/passwd 里边的第四栏有所谓的 GID 吧?那个 GID 就是所谓的 “初始群组”。也就是说,当用户一登录系统,立刻就拥有这个群组的相关权限的意思

  • groups:有效和支持群组的观察
  • newgrp:有效群组的切换(是以另外一个 shell 来提供这个功能的,可以使用 exit 退出)

通常有效群组的作用就是在新建文件

1.3.3、/etc/gshadow

[root@li ~]# head -n 4 /etc/gshadow
root:::
bin:::
daemon:::
sys:::

还是以 “:” 分隔的,一共有 4 段,分别为:

  1. 组名
  2. 密码
  3. 群组管理员的账号
  4. 有加入该群组支持的所属账号(与 /etc/group 内容相同)

2、账号管理

2.1、新增与移出使用者:useradd,相关配置文件,passwd,usermod,userdel

[root@li ~]# useradd [-u UID] [-g 初始群组] [-G 次要群组] [-mM] [-c 说明栏] [-d 家目录绝对路径] [-s shell] 账号
选项与参数:
-M:强制!不要建立家目录!(系统账号默认值)
-m:强制!要建立家目录!(一般账号默认值)
-r:建立一个系统账号
-e:后面接一个日期,格式为 “YYYY-MM-DD”,此项目会写入 shadow 第八字段,即账号失效日的设定项目
-f:后面接 shadow 的第七个字段,指定密码是否会失效。0 为立即失效,-1 为永远不失效(密码只会过期而强制登录时重新设定)
#1、完全默认值建立一个账号,名称为 vbird1
[root@li ~]# useradd vbird1
[root@li ~]# ll -d /home/vbird1/
drwx------. 2 vbird1 vbird1 62 8月   9 09:31 /home/vbird1/		#权限默认是 700,这是重点!!!

[root@li ~]# grep 'vbird1' /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird1:x:1001:1001::/home/vbird1:/bin/bash
/etc/shadow:vbird1:!!:18483:0:99999:7:::
/etc/group:vbird1:x:1001:	#默认会建立一个和账号名称一样的群组

完全使用默认值建立一个账号,系统会帮我们处理以下事情:

  • 在 /etc/passwd 里边建立一行与账号相关的数据,包括建立 UID/GID/家目录等;
  • 在 /etc/shadow 里边将此账号的密码相关参数填入,但是没有密码;
  • 在 /etc/group 里边加入一个与账号名称一模一样的群组;
  • 在 /home 底下建立一个与账号名称一模一样的目录作为账号的家目录,且权限为 700。
#2、请用 li 作为初始群组,以及 uid 为 1500 来建立 vbird2 账号
[root@li ~]# useradd -u 1500 -g li vbird2
[root@li ~]# ll -d /home/vbird2
drwx------. 2 vbird2 li 62 8月   9 09:37 /home/vbird2	#群组为 li

[root@li ~]# grep 'vbird2' /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird2:x:1500:1000::/home/vbird2:/bin/bash		#UID 为 1500
/etc/shadow:vbird2:!!:18483:0:99999:7:::
#3、建立一个系统账号 vbird3
[root@li ~]# useradd -r vbird3
[root@li ~]# ll -d /home/vbird3
ls: 无法访问/home/vbird3: 没有那个文件或目录		#不会主动建立家目录

[root@li ~]# grep 'vbird3' /etc/passwd /etc/shadow /etc/group
/etc/passwd:vbird3:x:998:996::/home/vbird3:/bin/bash
/etc/shadow:vbird3:!!:18483::::::
/etc/group:vbird3:x:996:

从上面的案例可知,使用 useradd 建立账号,其实会改动的地方不少,至少我们知道底下这几个文件:

  • 用户的账号与密码参数方面的文件:/etc/passwd、/etc/shadow
  • 使用者群组相关方面的文件:/etc/group、/etc/gshadow
  • 用户的家目录:/home/账户名称

那还有一个问题:家目录内的数据是从哪里来的呢?为何预设的 shell 是 /bin/shell 呢?

2.1.1、useradd 参考文件

[root@li ~]# useradd -D		#useradd 的默认值
GROUP=100		#默认的群组
HOME=/home		#默认的家目录所在的目录
INACTIVE=-1		#密码失效日,在 shadow 的第 7 栏
EXPIRE=			#账号失效日,在 shadow 的第 8 栏
SHELL=/bin/bash		#预设的 shell
SKEL=/etc/skel		#用户家目录的内容数据参考目录
CREATE_MAIL_SPOOL=yes	#是否主动帮助使用者建立邮件信箱

这些数据其实都是由 /etc/default/useradd 这个文件里边的。除了这些基本的账号设定值外,UID/GID 还有密码参数又是在哪里参考的呢?那就需要看一下 /etc/login.defs 文件了:

[root@li ~]# cat /etc/login.defs
MAIL_DIR        /var/spool/mail		#用户默认的邮件信箱放置目录

PASS_MAX_DAYS   99999	#/etc/shadow 内的第 5 栏,多久需要变更密码
PASS_MIN_DAYS   0		#/etc/shadow 内的第 4 栏,多久不可重新设定密码天数
PASS_MIN_LEN    5		#密码最短字符长度,已被 pam 取代
PASS_WARN_AGE   7		#/etc/shadow 内的第 6 栏,过期前会警告的天数

UID_MIN                  1000		#账号的最小 UID,小于 1000 的 UID 为系统保留
UID_MAX                 60000		#使用者最大的 UID
	
SYS_UID_MIN               201		#保留给用户自行设定的系统账号最小值 UID
SYS_UID_MAX               999		#保留给用户自行设定的系统账号最大值 UID

GID_MIN                  1000		#一般使用者账号自定群组的最小 GID,小于 1000 为系统保留
GID_MAX                 60000		#一般使用者账号自定群组的最大 GID
# System accounts
SYS_GID_MIN               201		#保留给用户自行设定的系统账号最小值 GID
SYS_GID_MAX               999		#保留给用户自行设定的系统账号最大值 GID

CREATE_HOME     yes				#-m 和 -M 参数
UMASK           077				#用户家目录建立的 umask,因此权限为 700
USERGROUPS_ENAB yes				#使用 userdel 时,是否会删除初始群组
ENCRYPT_METHOD SHA512			#密码加密的机制使用的 sha512

现在知道,使用 useradd 程序建立 Linux 上的账号时,至少会参考:

  • /etc/default/useradd
  • /etc/login.defs
  • /etc/skel/*

2.1.2、passwd

使用 useradd 建立账号之后,在默认情况下,该账号是暂时封存的,也就是说,该账号是无法登陆的,那如何设置密码呢?

[root@li ~]# passwd [--stdin] [账号名称]
[root@li ~]# passwd [-l] [-u] [--stdin] [-S] [-n 天数] [-x 天数] [-w 天数] [-i 天数] 账号		#root 功能
选项与参数:
--stdin:可以通过管线来作为密码输入
-l:是 Lock 的意思,会将 /etc/shadow 第二栏最前面加上 ! 是密码失效
-u:与 -l 相对,是 Ulock 的意思
-S:列出密码相关参数
-n:shadow 第 4 栏,多久不可修改密码的天数
-x:shadow 第 5 栏,多久内必须修改密码的天数
-w:shadow 第 6 栏,密码过期前的警告的天数
-i:shadow 第 7 栏,密码失效日期
#1、使用 root 修改 vbird2 的密码
[root@li ~]# passwd vbird2
更改用户 vbird2 的密码 。
新的 密码:			#屏幕不会由任何显示
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。

#2、登录 vbird2 后,修改自己的密码
[vbird2@li root]$ passwd
更改用户 vbird2 的密码 。
为 vbird2 更改 STRESS 密码。
(当前)UNIX 密码:		#还需要输入 Linux 的密码
新的 密码:				#不能和原密码相同或相似
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。

#3、使用标准输入作为密码
[root@li ~]# echo "abc543CC" | passwd --stdin vbird2
更改用户 vbird2 的密码 。
passwd:所有的身份验证令牌已经成功更新。

#4、管理 vbird2 账号的密码具有 60 天变更、密码过期 10 天后失效的设定
[root@li ~]# passwd -S vbird2
vbird2 PS 2020-08-09 0 99999 7 -1 (密码已设置,使用 SHA512 算法。)
#显示的信息包括:2020/08/09 创建的密码,0 最小天数、99999 变更天数、7 警告天数与密码不会失效(-1)

[root@li ~]# passwd -x 60 -i 10 vbird2
调整用户密码老化数据vbird2。
passwd: 操作成功
[root@li ~]# passwd -S vbird2
vbird2 PS 2020-08-09 0 60 7 10 (密码已设置,使用 SHA512 算法。)

#5、让 vbird2 的账号失效
[root@li ~]# passwd -l vbird2
锁定用户 vbird2 的密码 。
passwd: 操作成功
[root@li ~]# passwd -S vbird2
vbird2 LK 2020-08-09 0 60 7 10 (密码已被锁定。)
[root@li ~]# grep 'vbird2' /etc/shadow
vbird2:!!$6$wYS1p/TT$tcFap4Ksysd9X/CFylmEvF7qQTUTeILiuQpHd16tpZRjtvBpZHZm3o50dkpMeoVDNPngrLsAkd9CgONtu9eUU0:18483:0:60:7:10::			#其实只是加上了 ! 而已
[root@li ~]# passwd -u vbird2
解锁用户 vbird2 的密码。
passwd: 操作成功
[root@li ~]# grep 'vbird2' /etc/shadow
vbird2:$6$wYS1p/TT$tcFap4Ksysd9X/CFylmEvF7qQTUTeILiuQpHd16tpZRjtvBpZHZm3o50dkpMeoVDNPngrLsAkd9CgONtu9eUU0:18483:0:60:7:10::				#解锁成功

2.1.3、chage

除了 passwd -S 之外,还有没有更详细的密码参数显示功能呢?

[root@li ~]# chage [-ldEImMW] 账号名
选项与参数:
-l:列出该账号的详细密码参数
-d:后面接日期,修改 shadow 的第 3 字段:最近一次更改密码的日期,格式:YYYY-MM-DD
-E:后面接日期,修改 shadow 的第 8 字段:密码失效日期,格式:YYYY-MM-DD
-I:后面接天数,修改 shadow 的第 7 字段:密码失效天数
-m:后面接天数,修改 shadow 的第 4 字段:密码最短保留天数
-M:后面接天数,修改 shadow 的第 5 字段:密码多久需要进行变更
-W:后面接天数,修改 shadow 的第 6 字段:密码过期前警告的天数
#1、列出 vbird2 的详细密码信息
[root@li ~]# chage -l vbird2
最近一次密码修改时间                   :8月 09, 2020
密码过期时间                          :10月 08, 2020
密码失效时间                          :10月 18, 2020
帐户过期时间                          :从不
两次改变密码之间相距的最小天数           :0
两次改变密码之间相距的最大天数           :60
在密码过期之前警告的天数        		:7

#2、建立一个 agetest 的账号,该账号第一次登录后使用默认密码,但必须要更改过密码后,使用新密码才能登录系统使用 bash 环境
[root@li ~]# useradd agetest
[root@li ~]# echo "agetest" | passwd --stdin agetest
更改用户 agetest 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@li ~]# chage -d 0 agetest
[root@li ~]# chage -l agetest | head -n 3
最近一次密码修改时间                             :密码必须更改
密码过期时间                                    :密码必须更改
密码失效时间                                    :密码必须更改

#3、尝试登录 agetest
WARNING: Your password has expired.
You must change your password now and login again!
更改用户 agetest 的密码 。
为 agetest 更改 STRESS 密码。
(当前)UNIX 密码:

你会发现 agetest 这个账号在第一次登录的时候可以使用与账号相同的密码登录系统,但登录时就会被要求立刻修改密码,更改密码之后就会被提出系统,再次登录时需要使用新密码!

2.1.4、usermod

[root@li ~]# usermod [-cdegGlsuLU] 账号名称
选项与参数:
-c:账号说明,shadow 的第 5 栏
-d:家目录,修改 shadow 的第 6 栏
-e:后面接日期,格式是 YYYY-MM-DD,即 shadow 的第 8 栏
-f:后面接天数,shadow 的第 7 栏
-g:初始群组,shadow 的第 4 栏
-G:次要群组
-a:与 -G 合用,可增加次要群组的支持而非设定
-l:修改账号名称
-s:后面接 Shell 的实际文件,例如 /bin/bash 或 /bin/csh 等
-u:后面接 UID,即 shadow 的第 3 栏
-L:暂时 Lock 账号
-U:解冻
#1、修改 vbird2 的说明栏
[root@li ~]# usermod -c "li's test" vbird2
[root@li ~]# grep "vbird2" /etc/passwd
vbird2:x:1500:1000:li's test:/home/vbird2:/bin/bash

#2、使 vbird2 在 2020/08/10 失效
[root@li ~]# usermod -e "2020-08-10" vbird2
[root@li ~]# chage -l vbird2 | grep "密码失效时间"
密码失效时间                                    :10月 18, 2020

2.1.5、userdel

目的在于删除用户的相关数据,而用户的数据有:

  • 用户账号/密码相关参数:/etc/passwd、/etc/shadow
  • 使用者群组相关参数:/etc/group、/etc/gshadow
  • 用户个人文件数据:/home/账户名称、/var/spool/mail/账号名称…
[root@li ~]# userdel [-r] 账号名称
选项与参数:
-r:连同家目录一起删除

2.2、用户功能

不论是 useradd/usermod/userdel,那都是系统管理员所能够使用的指令,如果我是一般使用者,那么我应该使用什么指令更查询和更改账号呢?

2.2.1、id

[root@li ~]# id [账号名称]
[root@li ~]# id
uid=0(root) gid=0(root)=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@li ~]# id vbird1
uid=1001(vbird1) gid=1001(vbird1)=1001(vbird1)

2.2.2、chsh

[root@li ~]# chsh [-ls]
选项与参数:
-l:列出目前系统上面可用的 shell,其实就是 /etc/shells 的内容
-s:设定修改自己的 shell
[root@li ~]# chsh -l
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash

chsh 能让一般用户修改 /etc/passwd 文件的内容,所以你猜猜,这两个文件的权限是什么?一定是 SUID 的功能!

2.3、新增和删除群组

基本上,群组的内容都与两个文件有关:/etc/group、/etc/gshadow。

2.3.1、groupadd

[root@li ~]# groupadd [-g gid] [-r] 群组名
选项与参数:
-r:建立系统群组,与 /etc/login.defs 内的 GID_MIN 有关
[root@li ~]# grep group1 /etc/group /etc/gshadow
/etc/group:group1:x:1502:
/etc/gshadow:group1:!::

2.3.2、groupmod

[root@li ~]# groupmod [-g gid] [-n group_name] 群组名
选项与参数:
-n:修改既有的组名
[root@li ~]# groupmod -g 201 -n mygroup group1
[root@li ~]# grep mygroup /etc/group /etc/gshadow
/etc/group:mygroup:x:201:
/etc/gshadow:mygroup:!::

2.3.3、groupdel

[root@li ~]# groupdel [群组名]
[root@li ~]# groupdel mygroup
[root@li ~]# groupdel vbird1
groupdel:不能移除用户“vbird1”的主组

为什么不能删除 vbird1 呢?原因很简单,有某个账号的初始群组使用该群组

2.3.4、gpasswd:群组管理员功能

让某个群组具有一个群组管理员,这个群组管理员可以管理哪些账号可以加入/移出该群组!

[root@li ~]# gpasswd 群组名
[root@li ~]# gpasswd [-A 账号1,...] [-M 账号2,...] 群组名
[root@li ~]# gpasswd [-rR] 群组名
选项与参数:
	:若没有任何参数,表示给予群组一个密码(/etc/gshadow)
-A:将群组的主控权交给账号1
-M:将某些账号加入这个群组
-r:将群组的密码移除
-R:让群组的密码栏失效
#关于群组管理员的动作
[someone@li ~]# gpasswd [-ad] 账号 群组
选项与参数:
-a:将某位使用者加入到群组
-d:将某位使用者移出群组
#1、建立一个新群组,名称为 testgroup 且群组交给 vbird1 管理
[root@li ~]# groupadd testgroup
[root@li ~]# gpasswd testgroup
正在修改 testgroup 组的密码
新密码:
请重新输入新密码:
[root@li ~]# gpasswd -A vbird1 testgroup
[root@li ~]# grep testgroup /etc/group /etc/gshadow
/etc/group:testgroup:x:1502:
/etc/gshadow:testgroup:.../:vbird1:

#2、以 vbird1 的身份登录系统,并且让它加入 vbird1、vbird3 称为 testgroup 的成员
[vbird1@li root]$ id
uid=1001(vbird1) gid=1001(vbird1)=1001(vbird1)	#看得出来 vbird1 尚未加入群组
[vbird1@li root]$ gpasswd -a vbird1 testgroup
正在将用户“vbird1”加入到“testgroup”组中
[vbird1@li root]$ gpasswd -a vbird3 testgroup
正在将用户“vbird3”加入到“testgroup”组中
[vbird1@li root]$ grep testgroup /etc/group
testgroup:x:1502:vbird1,vbird3

2.4、账号管理实例

一台主机上面可能有多个账号在协同工作,账号需要分组,同一组的同学间必须要能够互相修改对方的数据文件,但是同时这些同学又需要保留自己的私密文件,因此直接公开家目录是不合适的,那该如何是好?为此,下面提供几个例子:

任务1,实验要求:

账号名称 账号说明 支援次要群组 是否可登录系统 密码
myuser1 1st user mygroup1 可以 password
myuser2 2nd user mygroup1 可以 password
myuser3 3rd user 无额外支持 不可以 password
#1、先处理账号相关属性的数据
[root@li ~]# groupadd mygroup1
[root@li ~]# useradd -G mygroup1 -c "1st user" myuser1
[root@li ~]# useradd -G mygroup1 -c "2nd user" myuser2
[root@li ~]# useradd -c "3rd user" -s /sbin/nologin myuser3

#2、再处理账号与密码相关属性的数据
[root@li ~]# echo "password" | passwd --stdin myuser1
更改用户 myuser1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@li ~]# echo "password" | passwd --stdin myuser2
更改用户 myuser2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@li ~]# echo "password" | passwd --stdin myuser3
更改用户 myuser3 的密码 。
passwd:所有的身份验证令牌已经成功更新。

任务2,使用者 pro1,pro2,pro3 是同一个项目计划的开发人员,想让这三个用户在同一个目录底下工作,但这三个用户还是拥有自己的家目录与基本的私有群组,假设我想要这个项目在 /srv/projecta 目录下开发:

#1、假设这三个账号都没有建立,可先建立一个名为 projecta 的群组;再让这三个用户加入其次要群组即可
[root@li ~]# groupadd projecta
[root@li ~]# useradd -G projecta -c "projecta user" pro1
[root@li ~]# useradd -G projecta -c "projecta user" pro2
[root@li ~]# useradd -G projecta -c "projecta user" pro3
[root@li ~]# echo "password" | passwd --stdin pro1
更改用户 pro1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@li ~]# echo "password" | passwd --stdin pro2
更改用户 pro2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@li ~]# echo "password" | passwd --stdin pro3
更改用户 pro3 的密码 。
passwd:所有的身份验证令牌已经成功更新。

#2、开始建立此项目的开发目录
[root@li ~]# mkdir /srv/projecta
[root@li ~]# chgrp projecta /srv/projecta
[root@li ~]# chmod 2770 /srv/projecta
[root@li ~]# ll -d /srv/projecta
drwxrws---. 2 root projecta 6 8月  10 10:59 /srv/projecta

由于此项目是给 pro1,pro2,pro3 三个人使用的,所以 /srv/projecta 的权限一定要正确才行!所以该目录群组一定是 projecta 才行,但是权限为什么是 2770?是为了让三个使用者能够互相修改对方的文件!所以这个 SGID 是必须存在的。

那么接下来还有一个问题:假如任务一的 myuser1 是 projecta 这个项目的经理,他需要这个项目的内容,但是他不能修改项目目录内的任何数据!那该如何是好?或许可以这样做:

  • 将 myuser1 加入 projecta 这个群组的支持,但是这样会让 myuser1 具有完整的 /srv/projecta 的权限,myuser1 是可以删除该目录下的任何数据的!这样是有问题的
  • 将 /srv/projecta 的权限改为 2775,让 myuser1 可以进入查询,但此时会发生任何人均可进入该目录查询!这也不是我们要的环境!

那 Linux 该如何针对某个个人设定专属的权限?使用 ACL 的功能!


3、主机的细节权限规划:ACL 的使用

传统的权限仅有三种身份(owner,group,others)搭配三种权限(r,w,x)而已,并没有办法单纯的针对某一个使用者或某一个群组来设定特定的权限需求,这时就需要使用 ACL 的机制了

3.1、什么是 ACL 与如何支持启动 ACL

ACL 主要是针对单一使用者,单一文件或目录来进行 r,w,x 的权限规范,对于需要特殊权限的使用状况非常有帮助。那么 ACL 主要针对哪些方面来控制权限呢?

  • 使用者
  • 群组
  • 默认属性

也就是说,如果你有一个目录,需要给一堆人使用,每个人或每个群组所需要的权限并不相同时,在过去,传统的 Linux 三种身份的三种全权限是无法达到的。因为,传统的权限只能针对一个用户、一个群组及非此群组的其他人设定权限而已,无法针对单一个人来设定权限。而 ACL 正好解决了这个问题

3.1.1、如何启动 ACL

默认已自动开启,可以检查一下:

[root@li ~]# dmesg | grep -i acl
[    0.867295] 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)
[    2.036567] SGI XFS with ACLs, security attributes, no debug enabled

3.2、ACL 的设定技巧:getfacl,setfacl

  • getfacl:取得某个文件/目录的 ACL 设定项目;
  • setfacl:设定某个目录/文件的 ACL 规范。

3.2.1、setfacl:设定权限

[root@li ~]# setfacl [-bkRd] [{-m|-x} acl 参数] 目标文件名
选项与参数:
-m:设定后续的 acl 参数给文件使用,不可与 -x 合用
-x:删除后续的 acl 参数,不可与 -m 合用
-b:移除所有的 acl 参数
-k:移除预设的 acl 参数
-R:递归设定 acl
-d:设定预设的 acl 参数!只对目录有效,在该目录下新建的数据会引用此默认值

针对单一使用者的设定方式:u:[使用者账号列表]:[rwx]

[root@li ~]# touch acl_test1
[root@li ~]# ll acl_test1
-rw-r--r--. 1 root root 0 8月  10 11:26 acl_test1
[root@li ~]# setfacl -m u:vbird1:rx acl_test1
[root@li ~]# ll acl_test1
-rw-r-xr--+ 1 root root 0 8月  10 11:26 acl_test1	#注意!权限后面多了个 + 号
[root@li ~]# setfacl -m u::rwx acl_test1		#u 后面不接使用者,代表文件拥有者
[root@li ~]# ll acl_test1
-rwxr-xr--+ 1 root root 0 8月  10 11:26 acl_test1	#root 的权限变成了 rwx

3.2.2、getfacl:观察权限

[root@li ~]# getfacl 文件名
选项与参数:
几乎和 setfacl 相同
[root@li ~]# getfacl acl_test1
# file: acl_test1		#说明
# owner: root			#拥有者
# group: root			#群组
user::rwx				#使用者那栏是空的,代表文件拥有者
user:vbird1:r-x			#针对 vbird1 的设定权限
group::r--				#针对文件群组的权限
mask::r-x				#文件预设的默认权限
other::r--				#针对其他人的权限

针对单一群组的权限设定:g:[群组列表]:[rwx]

[root@li ~]# setfacl -m g:mygroup1:rx acl_test1
[root@li ~]# getfacl acl_test1
user::rwx
user:vbird1:r-x
group::r--
group:mygroup1:r-x

针对有效权限设定:m:[rwx]

mask:使用者或群组所设定的权限必须要存在于 mask 的权限设定范围内才会生效

[root@li ~]# setfacl -m m:r acl_test1
[root@li ~]# getfacl acl_test1
user::rwx
user:vbird1:r-x                 #effective:r--	#仅有 r 生效
group::r--
group:mygroup1:r-x              #effective:r--	#仅有 r 生效
mask::r--

vbird1 和 mask 的集合仅有 r 存在,因此 vbird1 仅具有 r 权限而已,并不存在 x 权限!这就是 mask 的功能。可以通过 mask 来规范最大允许权限,就能够避免开放某些权限给其他使用者或群组了。

3.3、接上面的任务

任务二中 /srv/projecta 这个目录,让 myuser1 可以进入查询,但 myuser1 具有修改的权限:因为 myuser1 是其他用户,因此无法使用传统的权限设定,使用 ACL:

#1、先测试以下 myuser1 能够进入目录?
[root@li ~]# su myuser1
[myuser1@li root]$ cd /srv/projecta/
bash: cd: /srv/projecta/: 权限不够		#确实进不去

#2、开始用 root 身份来设定目录权限
[root@li ~]# setfacl -m u:myuser1:rx /srv/projecta
[root@li ~]# getfacl /srv/projecta/
getfacl: Removing leading '/' from absolute path names
# file: srv/projecta/
# owner: root
# group: projecta
# flags: -s-
user::rwx
user:myuser1:r-x		#检查一下权限
group::rwx
mask::rwx
other::---

#3、使用 myuser1 测试结果
[root@li ~]# su myuser1
[myuser1@li root]$ cd /srv/projecta/
[myuser1@li projecta]$ ll -a
总用量 0
drwxrws---+ 2 root projecta  6 8月  10 10:59 .
drwxr-xr-x. 3 root root     22 8月  10 10:59 ..		#可以进入并查看
[myuser1@li projecta]$ touch test
touch: 无法创建"test": 权限不够			#但是无法写入

使用默认权限设定目录未来文件的ACL 权限继承:d:[u|g]:[账号|群组]:[rwx]

#让 myuser1 在 /srv/projecta 底下一只具有 rx 的权限
[root@li ~]# setfacl -m d:u:myuser1:rx /srv/projecta/
[root@li ~]# getfacl /srv/projecta/
getfacl: Removing leading '/' from absolute path names
...
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

[root@li projecta]# ll -d zzz*
-rw-rw----+ 1 root projecta 0 8月  10 16:02 zzz1
drwxrws---+ 2 root projecta 6 8月  10 16:02 zzz2
[root@li projecta]# getfacl zzz2
...
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---

针对刚刚 /srv/projecta 目录的权限中,需要(1)取消 ,myuser1 的设定(连同默认值),以及(2)不让 pro3 使用该模流,即 pro3 没有任何权限:

#1.1、找到针对 myuser1 的设定
[root@li projecta]# getfacl /srv/projecta/ | grep myuser1
getfacl: Removing leading '/' from absolute path names
user:myuser1:r-x
default:user:myuser1:r-x
#1.2、针对每个设定值来处理
[root@li projecta]# setfacl -x u:myuser1 /srv/projecta/
[root@li projecta]# setfacl -x d:u:myuser1 /srv/projecta/

#2、开始让 pro3 无法使用该目录
[root@li projecta]# setfacl -m u:pro3:- /srv/projecta/
#没有任何权限的语法为 - !!!

4、使用者身份切换

4.1、su

[root@li ~]# su [-lm] [-c 指令] [账号名]
选项与参数:
-:单纯使用-,如“su -” 代表使用 login-shell 的变量文件读取方式来登录系统;若没有账号名称,代表切换为 root 身份
-l:与 - 类似,但后面需要加账号名称!也是 login-shell 身份
-m:-m 与 -p 是一样的。表示 “使用目前的环境设定,而不读取新使用者的配置文件”
-c:仅执行一次指令
[li@li root]$ su		#注意提示符,是 li 用户
密码:			#输入 root 的密码
[root@li ~]# id		
uid=0(root) gid=0(root)=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023	#确实是 root
[root@li ~]# env | grep 'li'
HOSTNAME=li.erver
USER=li		#但环境还是 li
LOGNAME=li

单纯使用 su 切换称为 root 身份,读取的变量设定方式为 nonlogin-shell 的方式,这种方式很多原文的变量不会改变,尤其是之前谈到的 PATH 这个变量。所以切换身份时,务必使用下面的方式:

[li@li root]$ su -
密码:
上一次登录:二 8月 11 09:55:04 CST 2020pts/0 上
[root@li ~]# env | grep root
USER=root
MAIL=/var/spool/mail/root
PATH=/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/root/bin
PWD=/root
HOME=/root
LOGNAME=root
[root@li ~]# exit
登出

如果只想执行一次指令,可以使用参数 -c:

[li@li ~]$ head -n 3 /etc/shadow
head: 无法打开"/etc/shadow" 读取数据: 权限不够
[li@li ~]$ su - -c "head -n 3 /etc/shadow"
密码:		#root 的密码
root:$6$Wut1Cw0fCGVGBkEF$H/OVyZf7Y00AQEASWVcyFvo2ZBgv4pgH3Qp5QuFH8bOZXKgxZw0CaiZ/bVW2/estLhu4hWJZW6otFsWKS/iEa1::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::

总结 su 的用法:

  • 若要完整的切换到新使用者的环境,必须使用 “su - 用户名” 或 “su -l 用户名” ;
  • 如果仅执行一次 root 指令,可以使用参数 -c;
  • 使用 root 切换成任何用户时,不需要密码。

4.2、sudo

相对于 su 的切换常常需要 root 的密码,sudo 的执行则仅仅需要自己的密码即可,甚至不需要密码。但 sudo 并不是搜有人都可以执行的,仅仅只有规范到 /etc/sudoers 内的用户才可以执行

4.2.1、visudo 与 /etc/sudoers

4.2.1.1、单一用户可进行 root 所有指令,与 sudoers 文件语法:

假如想要 li 这个用户可以使用 root 的所有指令,基本上有两种做法,第一种是直接通过修改 /etc/sudoers,如下:

[root@li ~]# visudo
root    ALL=(ALL)       ALL
li  ALL=(ALL)       ALL		#新增这一行
#使用者账号	登陆者的来源主机名=(可切换的身份)	可下达的指令
[li@li root]$ tail -n 1 /etc/shadow
tail: 无法打开"/etc/shadow" 读取数据: 权限不够
[li@li root]$ sudo tail -n 1 /etc/shadow
[sudo] li 的密码:
pro3:$6$BvK1mYX5$j080SpnR.jRNWiUj2v26FU88p.QJArlevjJJdbx7zOZme/p/FZYE2OG7IvA/mYyWHWXoGqxYNfkjl/3xkVuQ/1:18484:0:99999:7:::
4.2.1.2、利用 wheel 群组以及免密的功能处理 visudo

群组:

[root@li ~]# visudo
%wheel  ALL=(ALL)       ALL		#加上一个 %,代表群组的意思
[root@li ~]# usermod -a -G wheel pro1
#意思即为任何加入 wheel 的用户都可以使用 sudo

[pro1@li root]$ sudo tail -n 1 /etc/shadow		#使用 pro1 的身份验证

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

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

[sudo] pro1 的密码:
pro3:$6$BvK1mYX5$j080SpnR.jRNWiUj2v26FU88p.QJArlevjJJdbx7zOZme/p/FZYE2OG7IvA/mYyWHWXoGqxYNfkjl/3xkVuQ/1:18484:0:99999:7:::

[pro2@li ~]$ sudo tail -n 1 /etc/shadow		#使用 pro2 验证

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

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

[sudo] pro2 的密码:
pro2 不在 sudoers 文件中。此事将被报告。

免密:

[root@li ~]# visudo
%wheel  ALL=(ALL)       NOPASSWD:ALL
4.2.1.3、有限制的指令操作

如果我想让用户仅能够执行部分系统任务,比如说,myuser1 仅能够帮 root 修改其他用户的密码,该怎么办呢?

[root@li ~]# visudo
myuser1 ALL=(root)      /usr/bin/passwd
#myuser1 可以切换到 root 执行 passwd 这个指令
[myuser1@li ~]$ sudo passwd vbird1

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

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

[sudo] myuser1 的密码:
更改用户 vbird1 的密码 。
新的 密码:
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
[myuser1@li ~]$ sudo passwd
更改用户 root 的密码 。		#居然可以更改 root 的密码,赶紧停止!
新的 密码:
[root@li ~]# visudo
myuser1 ALL=(root)      !/usr/bin/passwd,/usr/bin/passwd [A-Za-z]*,!/usr/bin/passwd root

在设置中加上 ! 表示不可执行的意思。上面的意思就是:可以执行 passwd 任意字符,但是不能执行 passwd 和 passwd root

[myuser1@li ~]$ passwd		#修改自己的密码,可执行
更改用户 myuser1 的密码 。
为 myuser1 更改 STRESS 密码。
(当前)UNIX 密码:
新的 密码:
[myuser1@li ~]$ sudo passwd		#修改 root 密码
[sudo] myuser1 的密码:
对不起,用户 myuser1 无权以 root 的身份在 li.erver 上执行 /bin/passwd。
[myuser1@li ~]$ sudo passwd root		#修改 root 密码
[sudo] myuser1 的密码:
对不起,用户 myuser1 无权以 root 的身份在 li.erver 上执行 /bin/passwd root。
4.2.1.4、通过别名建立 visudo

假如我的 pro1,pro2,pro3 与 myuser1,myuser2 要加入上述的密码管理员的 sudo 列表中,那我可以创建一个账号别名为 ADMPW 的名称,然后将这个名称处理一下:

[root@li ~]# visudo
User_Alias ADMPW = pro1,pro2,pro3,myuser1,myuser2
Cmnd_Alias ADMPCOM = !/usr/bin/passwd,/usr/bin/passwd [A-Za-z]*,!/usr/bin/passwd root
ADMPW   ALL=(root)      ADMPCOM
4.2.1.5、sudo 的时间间隔

两次 sudo 的执行间隔超过 5 分钟,就需要重新输入密码。

4.2.1.6、sudo 搭配 su 的使用

sudo 搭配 su 一口气变成 root:

[root@li ~]# visudo
User_Alias ROOT = pro1,pro2,pro3,myuser1
ROOT    ALL=(root)      /bin/su -

接下来,pro1,pro2,pro3,myuser1 这几个用户只需要输入 sudo su - 并且输入自己的密码就可以变成 root!

[pro1@li ~]$ sudo su -
[sudo] pro1 的密码:		#自己账号的密码
上一次登录:二 8月 11 15:00:24 CST 2020pts/0 上
[root@li ~]#

4.2.2、sudo 的指令用法

[root@li ~]# sudo [-b] [-u 新使用者账号]
选项与参数:
-b:将后续指令放在背景中执行,而不与目前的 shell 产生影响
-u:后面接的是切换的使用者,若无则代表是 root
[li@li root]$ sudo -u sshd touch /tmp/mysshd
[li@li root]$ ll /tmp/mysshd
-rw-r--r--. 1 sshd sshd 0 8月  11 10:25 /tmp/mysshd

5、用户特殊的 shell 与 PAM 模块

5.1、特殊的 shell,/sbin/nologin

我们所谓的无法登陆的账号:指的是使用者无法使用 bash 或其他 shell 来登录系统。并不是无法使用其他的系统资源!举例来说,打印作业由 lp 这个账号在管理,WWW 服务由 apache 这个账号在管理,它们都可以进行系统程序的工作,但是就是无法登陆主机取得互动的 shell。

另外,如果我想让某个具有 /sbin/nologin 的用户知道,他们不能登录主机时,其实我可以建立 /etc/nologin.txt 这个文件,并且在文件中说明不能登录的原因。这个文件需要我们建立,并不是预设的文件。

[root@li ~]# vim /etc/nologin.txt
这个账号是系统账号或邮件账号。
请不要使用这个账号去登录主机!
[root@li ~]# su - myuser3		#可以使用 myuser3 测试一下
这个账号是系统账号或邮件账号。
请不要使用这个账号去登录主机!

5.2、PAM 模块简介

在过去,我们想要对一个使用者进行认证,得要要求用户输入账号密码,然后通过自行撰写的程序来判断账号的密码是否正确!也因为如此,我们常常使用不同的机制来判断账号密码,所以一台主机上面就会有很多的认证系统,也就造成了账号密码可能不同步的问题为了解决这个问题,因此就有了 PAM 机制


6、Linux 主机上的用户信息传递

6.1、查询使用者:w,who,last,lastlog

如果你想知道目前已登录到系统上面的用户,可以使用 w 或 who 来查询:

[root@li ~]# w
 15:30:52 up 41 min,  5 users,  load average: 0.00, 0.02, 0.05
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT
root     tty1                      14:49   41:08   0.01s  0.01s -bash
root     pts/0    li-911m.lan      14:51    4.00s  0.01s  0.00s w
li       pts/1    li-911m.lan      15:30   49.00s  0.00s  0.00s -bash
myuser1  pts/2    li-911m.lan      15:30   25.00s  0.00s  0.00s -bash
pro2     pts/3    li-911m.lan      15:30    5.00s  0.00s  0.00s -bash
[root@li ~]# who
root     tty1         2020-08-11 14:49
root     pts/0        2020-08-11 14:51 (li-911m.lan)
li       pts/1        2020-08-11 15:30 (li-911m.lan)
myuser1  pts/2        2020-08-11 15:30 (li-911m.lan)
pro2     pts/3        2020-08-11 15:30 (li-911m.lan)

另外,如果想知道每个账号的最近登录时间,可以使用 lastlog 这个指令,它会去读取 /var/log/lastlog

[root@li ~]# lastlog
用户名           端口     来自             最后登陆时间
root             pts/0                     二 8月 11 15:13:20 +0800 2020
...
myuser2                                    **从未登录过**
myuser3          pts/0                     二 8月 11 15:22:20 +0800 2020
pro1             pts/0                     二 8月 11 15:13:04 +0800 2020
pro2             pts/3    li-911m.lan      二 8月 11 15:30:47 +0800 2020
pro3                                       **从未登录过**

6.2、使用者交谈:write,mesg,wall

[root@li ~]# write 账号 [终端端口]
[root@li ~]# write li pts/1
Hello,there:
Please don't do something wrong!		#按下 [ctrl]-d
#在 li 的界面
[li@li ~]$
Message from [email protected] on pts/0 at 15:37 ...
Hello,there:
Please don't do something wrong!EOF

如果 li 不想接受任何消息:

[li@li ~]$ mesg n
[li@li ~]$ mesg
is n

但是 root 的消息还是必须接收的。mesg y 解开限制。

当然,我们还可以广播信息

[root@li ~]# wall "I will shtdown my linux server..."
[root@li ~]#
Broadcast message from [email protected] (pts/0) (Tue Aug 11 15:41:42 2020):

I will shtdown my linux server...

猜你喜欢

转载自blog.csdn.net/qq_36879493/article/details/107937128