Linux 之旅 11:Linux 账号管理与 ACL 权限设置
Linux 的账号与用户组
使用者识别码:UID与GID
关于Linux的账号管理,有两个数字最为重要:
- UID:(User ID),即账号的唯一识别码
- GID:(Group ID),即用户组的唯一识别码
LInux通过这两个数字识别系统中的用户以及群组。
要查看当前账号的UID与GID,可以:
[icexmoon@xyz ~]$ id
uid=1000(icexmoon) gid=1000(icexmoon) 组=1000(icexmoon),10(wheel) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
查看指定行号的UID与GID:
[icexmoon@xyz ~]$ id root
uid=0(root) gid=0(root) 组=0(root)
事实上用户的UID和GID等信息都保存在几个账号和群组相关的配置文件中,其中最重要的是/etc/passwd :
[icexmoon@xyz ~]$ cat /etc/passwd | grep icexmoon
icexmoon:x:1000:1000:icexmoon:/home/icexmoon:/bin/bash
其中第三个字段是用户的UID,第四个字段是用户的主要群组(初始化群组)的GID。
使用者账号
在用户登录Linux的时候,用户验证的大概流程如下:
- 检查登录的用户名是否存在于
/etc/passwd 文件中,如果有,则读取其对应的UID和GID,以及登录用的shell和账号的家目录等。 - 通过
/etc/shadow 文件比对用户输入的密码是否正确。 - 如果没问题就调用对应的登录用
shell 进行登录。
/etc/passwd
现在看/etc/passwd 的详细结构:
[icexmoon@xyz ~]$ head -n 5 /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
lp:x:4:7:lp:/var/spool/lpd:/sbin/nologin
该文件由: 分隔,每一个字段的含义为:
- 用户名
- 密码:早期的Linux使用此字段保存密码,目前已废弃,转移到了
/etc/shadow 中,所以当前该字段中会用x 字符填充。 - UID:0表示
root 用户,1~999 为系统账号,1000~60000 为可以设置的一般性用户账号。 - GID:用户所属的主用户组(初始化用户组)
- 用户信息说明:关于用户的描述性信息
- 家目录
- Shell:通过登录验证后会使用这里指定的Shell进行登录,部分系统账号会被设置为
/sbin/nologin ,所以无法登录。
/etc/shadow
用户的密码保存在/etc/shadow 中:
[root@xyz ~]
root:$6$h5eXZCiKw8ucXyB2$PxxRgKneIDs2TWIpg916ugAfGCfqNf/HJHiXjy0PTPtUmY.pR/e2cUMpjRBqbx5Y0AHNJtjxAf3aOUTek3DpO.::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::
lp:*:18353:0:99999:7:::
同样以: 分隔,字段对应的内容为:
- 用户名
- 密码:这里存放的是经过加密后的密码,老式的Linux会使用md5,新的Linux会使用SHA或者其它的加密算法。只要稍微修改这里的数据就会导致用户无法正常登录,所以如果需要临时禁止某个用户登录,但是保留其包括登录密码在内的用户信息,就可以在这个字段开始添加一个
! 字符,如果要恢复登录就取消,很方便。 - 最近一次修改密码的日期:格式为以天为单位的时间戳
- 可变更密码的间隔天数:刚修改完密码后,需要间隔指定天数才能再次修改密码,通过设置这个字段可以杜绝频繁修改密码的行为,默认为0,表示可以随时修改密码。
- 密码过期天数:距离上一次修改密码后超过该天数后会在用户登录时要求用户修改密码。默认为99999,可以看作是永不过期。
- 密码过期前多少天进行警告:会在临近过期时,用户登录后会收到密码将要到期的提醒。
- 密码过期后的宽限天数:在宽限天数内可以修改密码并登录,如果超过宽限天数,密码将失效,无法修改和登录系统。
- 账号失效日期:格式为天为单位的时间戳,到该时间后账户会无条件失效,此字段用于特殊用途,比如将账号作为收费项目提供。
- 保留字段
如果一般用户忘记了密码,很好解决,只要用root 或者其它管理员账号修改即可,如果root 账号的密码忘了,且没有其它的管理员账号可以使用,就比较麻烦了,要么通过单人维护模式之类的方式启动系统,此时会获得root 权限,进行密码重置,要么可以用启动U盘之类的启动系统,用挂载文件系统的方式挂载/etc/shadow 所在分区,然后清空其中的root 密码字段,然后重启系统后就会提示设置root 的密码。
如果要查看Linux对密码加密使用的是何种算法,可以:
[root@xyz ~]
password hashing algorithm is sha512
关于用户组
/etc/group
用户组相关的信息保存在/etc/group 中:
[root@xyz ~]
root:x:0:
bin:x:1:
daemon:x:2:
sys:x:3:
adm:x:4:
这些字段的含义为:
- 用户组名称
- 用户组密码:此字段已废弃,相关信息移动到了
/etc/gshadow - GID
- 包含在此用户组中的用户名:例如
root:x:0:user1,user2 就表明user1 和user2 两个用户包含在root 用户组中,一个用户可以加入多个用户组,此外,如果某个用户的主用户组是当前的用户组,则不需要写入这里。
初始化用户组
用户的主用户组,或者说初始化用户组(initial group)是创建用户时所关联的用户组,是不需要将用户名写入/etc/group 中的相关字段的:
[root@xyz ~]
/etc/passwd:icexmoon:x:1000:1000:icexmoon:/home/icexmoon:/bin/bash
/etc/shadow:icexmoon:$6$vGNuDgQdXLIv4U19$mnkT6XkbUOAAO9jxxBfzXbRfS6ZA9LpR0fDwRJmfQ2cZ7PyMF18aGosW00KXjlcsv9GbzDpzSqgvqQr5E51aW/::0:99999:7:::
/etc/group:wheel:x:10:icexmoon
/etc/group:icexmoon:x:1000:icexmoon
不过事实上这里是有的:/etc/group:icexmoon:x:1000:icexmoon ,是CentOS版本的问题?
有效用户组
使用groups 命令可以查看用户所有关联的用户组:
[icexmoon@xyz ~]$ groups
icexmoon wheel
其中第一个为用户的有效用户组(effective group),如果创建新文件,所用的用户组信息就会是这个有效用户组:
[icexmoon@xyz tmp]$ touch test_group
[icexmoon@xyz tmp]$ ll test_group
-rw-rw-r--. 1 icexmoon icexmoon 0 8月 19 21:43 test_group
使用newgrp 命令可以切换有效用户组:
[icexmoon@xyz tmp]$ newgrp wheel
[icexmoon@xyz tmp]$ groups
wheel icexmoon
[icexmoon@xyz tmp]$ touch test_grou2
[icexmoon@xyz tmp]$ ll test_grou*
-rw-r--r--. 1 icexmoon wheel 0 8月 19 21:45 test_grou2
-rw-rw-r--. 1 icexmoon icexmoon 0 8月 19 21:43 test_group
[icexmoon@xyz tmp]$ exit
exit
newgrp 会打开一个子shell ,并改变有效用户组,此时新建文件会使用新的有效用户组。需要注意的是因为是新的子shell ,所以在执行完相关操作后需要使用exit 退出,并返回之前所在的shell 中。
/etc/gshadow
/etc/gshadow 主要的用途是保存用户组的密码:
[root@xyz ~]
root:::
bin:::
daemon:::
sys:::
adm:::
这些字段的含义是:
- 用户组名称
- 用户组密码:如果为用户组设置管理员,则会设置这个字段
- 用户组管理员账号
- 加入用户组的用户(与
/etc/group 相同)
所谓的用户组管理员,就是可以帮助root 管理对应的用户组,进行增加和删除用户,如果Linux主机上的用户很多,且频繁需要管理用户组,就可能需要设置用户组管理员来帮助管理,不过现在已经很少需要这么做了。
账号管理
添加和移除用户
useradd
使用useradd 就可以添加一个新用户:
[root@xyz ~]
[root@xyz ~]
drwx------. 3 user1 user1 78 8月 20 18:26 /home/user1
[root@xyz ~]
/etc/passwd:user1:x:1001:1001::/home/user1:/bin/bash
/etc/shadow:user1:!!:18859:0:99999:7:::
/etc/group:user1:x:1001:
可以看到新用户创建后,会自动创建相应的家目录(一般是/home/xxx ),此外还会在前边介绍的几个关键的用户和用户组相关的配置文件中添加相应的信息。
需要注意的是,/etc/shadow 中添加的新记录中的密码字段是!! ,意味着该用户的密码还未设置,所以需要设置密码后才能使用,可以用root 进行设置:
[root@xyz ~]
更改用户 user1 的密码 。
新的 密码:
无效的密码: 密码未通过字典检查 - 它基于字典单词
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
这里我使用的是一个常见的简单密码,所以被提示未通过字典检查,但是root 依然可以通过重复两次的方式强行设置。
默认情况下useradd 会给新用户指定一个UID和GID,其中GID是为新用户单独创建的一个新的用户组。如果你有特殊需要,也可以为新用户指定一个UID和一个已存在的用户组作为其主用户组:
[root@xyz ~]
[root@xyz ~]
drwx------. 3 user2 users 78 8月 20 18:37 /home/user2
[root@xyz ~]
/etc/passwd:user2:x:1500:100::/home/user2:/bin/bash
/etc/shadow:user2:!!:18859:0:99999:7:::
上面说的是用于普通用户登录和使用Linux主机的一般账号,此外还可以添加系统账号:
[root@xyz ~]
[root@xyz ~]
ls: 无法访问/home/user3: 没有那个文件或目录
[root@xyz ~]
/etc/passwd:user3:x:988:982::/home/user3:/bin/bash
/etc/shadow:user3:!!:18859::::::
/etc/group:user3:x:982:
使用useradd -r 可以添加系统账号,可以看到分配的UID是988 ,小于1000,此外,因为系统账号一般用于运行程序等,并不会被用户登录和使用,所以没有创建对应的家目录。
useradd 参考文件
可以通过useradd -D 查看useradd 命令创建用户时的默认值:
[root@xyz ~]
GROUP=100
HOME=/home
INACTIVE=-1
EXPIRE=
SHELL=/bin/bash
SKEL=/etc/skel
CREATE_MAIL_SPOOL=yes
其实这些内容是从/etc/default/useradd 这个文件读取的。
这些默认值的含义为:
-
GROUP=100 新建用户时候分配的初始用户组是100 。但是CentOS或Redhat系列发行版中,实际上并不会使用这个设置,而是会为新用户创建同名的一个新的用户组作为初始用户组,这种机制称为“私有用户组机制”,而使用这个设置并为新用户指定同一个用户组作为初始用户组的方式称为“公共用户组机制”。 -
HOME=/home 为新用户创建的家目录的位置,一般为/home/xxx 。 -
INACTIVE=-1 这个默认值对应/etc/shadow 中的第7个字段“密码过期后的宽限天数”,-1 表示永不失效,0 表示立即失效,其它值表示具体的宽限天数。 -
EXPIRE 对应/etc/shadow 中的第8个字段,账号会在到达该天数后失效。 -
SHELL=/bin/bash 新用户默认使用的shell 程序,如果为了安全考虑,希望新用户默认都不能登录,可以将这个值改为/sbin/nologin 。 -
SKEL=/etc/skel 新用户家目录的模板目录,在创建新用户的时候,会使用这里的模板目录为新用户创建家目录,比如,如果你希望新用户的家目录有一些基础的用户手册或者shell脚本,可以在/etc/skel 中设置好对应的文件,这样新建的用户的家目录里也会有一份相关文件的拷贝。 -
CREATE_MAIL_SPOOL=yes 是否为新用户创建邮箱,也就是/var/spool/mail/xxx 。
除了这些默认值以外,useradd 还需要参考其他的配置文件,比如/etc/login.defs :
[root@xyz ~]
MAIL_DIR /var/spool/mail
PASS_MAX_DAYS 99999
PASS_MIN_DAYS 0
PASS_MIN_LEN 5
PASS_WARN_AGE 7
UID_MIN 1000
UID_MAX 60000
SYS_UID_MIN 201
SYS_UID_MAX 999
GID_MIN 1000
GID_MAX 60000
SYS_GID_MIN 201
SYS_GID_MAX 999
CREATE_HOME yes
UMASK 077
USERGROUPS_ENAB yes
ENCRYPT_METHOD SHA512
这个文件包含这些信息:
MAIL_DIR :邮箱目录PASS_MAX_DAYS :密码相关设置中可以设置的最大天数,所以新用户的密码更新天数为99999 。PASS_MIN_DAYS :密码相关设置的最小天数PASS_MIN_LEN :密码最小长度。因为新版Linux都已使用PAM进行登录验证,所以这里的值已不再起作用。UID_MIN :一般用户可以设置的最小UID值。UID_MAX :一般用户可以设置的最大UID值。SYS_UID_MIN :系统账户可以设置的最小UID值。SYS_UID_MAX :系统账户可以设置的最大UID值。GID_MIN :新建的用户组可以设置的最小GID值。GID_MAX :新建的用户组可以设置的最大GID值。CREATE_HOME :是否默认为新用户创建家目录。UMASK :创建家目录时使用的umask,因为这里是077 ,所以创建的目录权限自然是700 。USERGROUPS_ENAB :使用userdel 删除用户时是否会删除其初始群组。ENCRYPT_METHOD :密码加密算法。
passwd
使用passwd 命令可以修改密码,特别的,root 可以修改所有用户的密码,而一般用户只可以修改自己的密码。此外需要注意的是,如果root 修改他人的密码,passwd 后需要写上对应的用户名,否则就是修改自己的密码。
新的Linux发行版使用PAM进行登录验证,所以一般会对密码有一些基本要求,否则是不允许设置该密码的(root 除外):
- 密码不能与账号同名
- 不能是常见的简单密码,如
123456 或password 之类的,系统有一个常见简单密码本,会进行比对。 - 密码需要超过8个字符。
- 不能使用个人信息,如身份证、手机号等作为密码
- 密码不能使用简单关系,如1+1=2等
- 密码尽量要使用数字、字母、特殊字符($、-等)的组合。
这里推荐一个大学时某网络安全老师教我们的密码生成方法:想一句话,比如”Today is a good day“,则可以取每个单词的首字母作为密码,即Tiagd ,这种密码看起来毫无规律,但实际上只要你记住那句话就能记住密码,这大概就是所谓的容易记住的无规律密码吧。而且这种方法可以有很多衍生版本,比如用拼音,或者不取首字母,取尾字母等。
新版的CentOS为passwd 命令加入了一个新的参数--stdin ,可以结合管道命令来显式地修改密码:
[root@xyz ~]
更改用户 user2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
使用这种方式可以通过Shell 脚本批量创建用户,并设置密码,但缺点是不安全,黑客可以通过命令历史记录看到这些信息(当然也可以执行完脚本后手动清除历史记录)。
如果想查看密码的相关设置,可以:
[root@xyz ~]
user2 PS 2021-08-20 0 99999 7 -1 (密码已设置,使用 SHA512 算法。)
这里打印的信息对应/etc/shadow 的相关字段,比如上边打印的信息就代表:user2 账号的密码最近一次修改时间为2021-08-20 ,密码可以随时修改,密码会在99999 天后过期,过期前7 天会提醒用户,账号永远不会失效。
可以对密码的这些设置进行修改:
[root@xyz ~]
调整用户密码老化数据user2。
passwd: 操作成功
[root@xyz ~]
user2 PS 2021-08-20 0 60 7 10 (密码已设置,使用 SHA512 算法。)
现在user2 账号被要求在修改密码60天后再次修改密码,如果过期超过10天账户将失效。
之前在介绍/etc/shadow 时说过可以通过在密码字段前添加! 的方式让用户无法进行登录,起到临时限制登录的目的,事实上不需要手动修改/etc/shadow 文件,可以:
[root@xyz ~]
锁定用户 user2 的密码 。
passwd: 操作成功
[root@xyz ~]
user2 LK 2021-08-20 0 60 7 10 (密码已被锁定。)
[root@xyz ~]
user2:!!$6$vsrs7fll$UAzw.3Gsu5hODBU/6UOTVy14M6M06NTZXW7//k3MXRYtG7mLwq3K.pWgOHlky1hD692uNvGjMBFUdMGqTr1iO1:18859:0:60:7:10::
可以看到对应的密码字段前被添加了两个! ,现在user2 就不能登录了。
要解除账户锁定也很简单:
[root@xyz ~]
锁定用户 user2 的密码 。
passwd: 操作成功
[root@xyz ~]
user2 LK 2021-08-20 0 60 7 10 (密码已被锁定。)
[root@xyz ~]
user2:!!$6$vsrs7fll$UAzw.3Gsu5hODBU/6UOTVy14M6M06NTZXW7//k3MXRYtG7mLwq3K.pWgOHlky1hD692uNvGjMBFUdMGqTr1iO1:18859:0:60:7:10::
chage
chage (change)命令主要用于修改用户密码的过期信息,也可以用来查看密码过期信息的详情:
[root@xyz ~]
最近一次密码修改时间 :8月 20, 2021
密码过期时间 :10月 19, 2021
密码失效时间 :10月 29, 2021
帐户过期时间 :从不
两次改变密码之间相距的最小天数 :0
两次改变密码之间相距的最大天数 :60
在密码过期之前警告的天数 :7
chage 有一个用途比较有用:要求新建的用户在第一次登录后必须修改密码:
[root@xyz ~]
[root@xyz ~]
更改用户 chagetest 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]
[root@xyz ~]
最近一次密码修改时间 :密码必须更改
密码过期时间 :密码必须更改
密码失效时间 :密码必须更改
帐户过期时间 :从不
两次改变密码之间相距的最小天数 :0
两次改变密码之间相距的最大天数 :99999
在密码过期之前警告的天数 :7
看到没,出现了密码必须更改 的字样,现在使用chagetest 账号通过ssh 连接进行登录:
? ssh chagetest@192.168.1.105
chagetest@192.168.1.105's password:
You are required to change your password immediately (root enforced)
WARNING: Your password has expired.
You must change your password now and login again!
更改用户 chagetest 的密码 。
为 chagetest 更改 STRESS 密码。
(当前)UNIX 密码:
新的 密码:
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
Connection to 192.168.1.105 closed.
在使用初始密码登录后会被强制要求修改密码,且修改完后会立即退出登录,必须使用修改后的密码再重新登录后才能正常使用系统。
这种方式对系统管理员批量创建账号,并使用一个随机密码作为初始密码的情况很有用,可以在相应的用户收到自己的账号和初始密码登录后让其修改为自己习惯的密码,并避免一些可能的密码泄露问题。
usermod
如果在创建完用户后需要对用户信息进行修改,可以使用usermod 命令:
[root@xyz ~]
[root@xyz ~]
user2:x:1500:100:test_account:/home/user2:/bin/bash
这里使用-c 参数给user2 添加了一段描述性文字。
此外usermod 也可以修改密码过期相关的设置:
[root@xyz ~]
[root@xyz ~]
最近一次密码修改时间 :8月 20, 2021
密码过期时间 :10月 19, 2021
密码失效时间 :10月 29, 2021
帐户过期时间 :12月 31, 2021
两次改变密码之间相距的最小天数 :0
两次改变密码之间相距的最大天数 :60
在密码过期之前警告的天数 :7
这里通过-e 参数给账户添加了一个账户过期时间。
userdel
userdel 命令的用途很明确,就是删除账号:
[root@xyz ~]
[root@xyz ~]
ls: 无法访问/home/user2: 没有那个文件或目录
参数-r 的用途是将用户的家目录一同删除。
对于账户的删除操作需要谨慎,如果只是让账户失效的话,可以通过将账户的过期时间(/etc/shadow 中第8个字段)设置为0 的方式实现。因为userdel 操作可能会删除用户相关的文件,可能会导致一些依赖于该用户的程序无法正常运行,所以如果一定要执行用户删除操作,请先通过find / -user username 之类的方式查询该用户相关的文件,确定的确可以删除后再进行删除用户的操作。
用户功能
id
之前介绍过,通过id 命令可以查询用户和用户组的相关信息:
[root@xyz ~]
uid=0(root) gid=0(root) 组=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@xyz ~]
uid=1000(icexmoon) gid=1000(icexmoon) 组=1000(icexmoon),10(wheel)
finger
finger 同样可以查询用户相关信息,这个命令一般不会默认安装,所以需要先安装:
[root@xyz ~]
已加载插件:fastestmirror, langpacks
Loading mirror speeds from cached hostfile
* base: mirrors.aliyun.com
* extras: mirrors.aliyun.com
使用finger 查看用户信息:
[root@xyz ~]
Login: icexmoon Name: icexmoon
Directory: /home/icexmoon Shell: /bin/bash
On since 五 8月 20 18:16 (CST) on pts/0 from icexmoon-book
1 second idle
No mail.
No Plan.
包含以下信息:
Login :账号名Name :描述文字Directory :家目录Shell :登录用Shell - 最后一次登录时间
- 邮件情况
- 任务计划:这里关联的是
~/.plan 的内容
测试一下,写入一个任务计划并使用finger 查看:
[icexmoon@xyz ~]$ echo "This is a test plan." > ~/.plan
[icexmoon@xyz ~]$ finger icexmoon
Login: icexmoon Name: icexmoon
Directory: /home/icexmoon Shell: /bin/bash
On since 五 8月 20 18:16 (CST) on pts/0 from icexmoon-book
3 seconds idle
No mail.
Plan:
This is a test plan.
此外,finger 还可以查看当前Linux主机上的登录的用户:
[icexmoon@xyz ~]$ finger
Login Name Tty Idle Login Time Office Office Phone Host
chagetest pts/1 Aug 20 21:01 (icexmoon-book)
icexmoon icexmoon pts/0 Aug 20 18:16 (icexmoon-book)
chfn
chfn(change finger)的用途是修改finger 命令查看的相关个人信息:
[icexmoon@xyz ~]$ chfn
Changing finger information for icexmoon.
名称 [icexmoon]: 魔芋红茶
办公 []:
办公电话 []: 123456
住宅电话 []: 123456
密码:
Finger information changed.
[icexmoon@xyz ~]$ finger icexmoon
Login: icexmoon Name: 魔芋红茶
Directory: /home/icexmoon Shell: /bin/bash
Office: 123456, 123456
On since 五 8月 20 18:16 (CST) on pts/0 from icexmoon-book
5 seconds idle
No mail.
Plan:
This is a test plan.
有点像是个人主页上的那些信息,但一般来说,除非你想在Linux主机上搞个账户社区啥的,这个命令用处不大。
chsh
chsh 命令用于修改用户的登录用Shell。
先列出当前Linux上可用的shell:
[chagetest@xyz ~]$ chsh -l
/bin/sh
/bin/bash
/usr/bin/sh
/usr/bin/bash
/bin/tcsh
/bin/csh
修改自己的登录用shell:
[chagetest@xyz ~]$ chsh -s /bin/csh
Changing shell for chagetest.
密码:
Shell changed.
[chagetest@xyz ~]$ cat /etc/passwd | grep chagetest
chagetest:x:1501:1501::/home/chagetest:/bin/csh
[chagetest@xyz ~]$ chsh -s /bin/bash
Changing shell for chagetest.
密码:
Shell changed.
[chagetest@xyz ~]$ cat /etc/passwd | grep chagetest
chagetest:x:1501:1501::/home/chagetest:/bin/bash
新增与删除用户组
groupadd
使用groupadd 可以创建新的用户组:
[root@xyz ~]
[root@xyz ~]
/etc/group:group1:x:1502:
/etc/gshadow:group1:!::
默认情况下会分配一个大于1000的GID,这样会造成你之后创建的新用户分配的UID和GID不再是相同数字的值,所以也有教程会建议自行创建用户组时使用小于1000的GID,但事实上保持UID和GID相等并没有什么实际意义。
groupmod
使用groupmod 可以修改已有用户组的信息:
[root@xyz ~]
[root@xyz ~]
/etc/group:mygroup:x:201:
/etc/gshadow:mygroup:!::
修改用户组的GID需要慎重,因为文件权限等都是与GID直接相关的。
groupdel
使用groupdel 可以删除用户组:
[root@xyz ~]
[root@xyz ~]
groupdel:不能移除用户“user1”的主组
需要注意的是,如果一个用户组是依然存在的某个用户的主用户组(初始用户组),则是不能被删除的。这很好理解,如果删除了,那个用户就没有主用户组了,这显然是不可接受的。
如果依然要删除,可以先给该用户指定一个新的主用户组,或者删除该用户,然后再删除这个用户组。
gpasswd
gpasswd 这个命令就是之前将的设置用户管理员的相关命令:
[root@xyz ~]
[root@xyz ~]
正在修改 grouptest 组的密码
新密码:
请重新输入新密码:
[root@xyz ~]
这里新建了一个用户组grouptest ,并将user1 用户设置为这个用户组的管理员。
现在使用user1 登录系统,并添加用户到该用户组:
? ssh user1@192.168.1.105
user1@192.168.1.105's password:
Last failed login: Sat Aug 21 10:20:30 CST 2021 from icexmoon-book on ssh:notty
There was 1 failed login attempt since the last successful login.
[user1@xyz ~]$ id
uid=1001(user1) gid=1001(user1) 组=1001(user1) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[user1@xyz ~]$ gpasswd -a user1 grouptest
正在将用户“user1”加入到“grouptest”组中
[user1@xyz ~]$ gpasswd -a user3 grouptest
正在将用户“user3”加入到“grouptest”组中
[user1@xyz ~]$ grep grouptest /etc/group
grouptest:x:1502:user1,user3
[user1@xyz ~]$ id
uid=1001(user1) gid=1001(user1) 组=1001(user1) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
这里需要注意的是:
- 加入用户组后需要重新登录才会生效。
- 一个用户组可以有多个管理员。
账号管理实例
任务一
先创建3个用户,并且给前两个用户添加辅助用户组,将第三个用户设置为不能登录:
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
更改用户 myuser1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]
更改用户 myuser2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]
更改用户 myuser3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
任务二
创立一个项目文件夹,并让三个用户都对该文件夹拥有全部的权限:
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
drwxr-xr-x. 2 root root 6 8月 21 10:36 /srv/projecta/
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
drwxrws---. 2 root projecta 6 8月 21 10:36 /srv/projecta/
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
[root@xyz ~]
更改用户 pro1 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]
更改用户 pro2 的密码 。
passwd:所有的身份验证令牌已经成功更新。
[root@xyz ~]
更改用户 pro3 的密码 。
passwd:所有的身份验证令牌已经成功更新。
使用外部身份认证系统
上面讲的都是本地的账号和认证系统,在一些网络构建的系统中,可能会有专门的账号管理和认证服务器,进行登录认证和账号管理,这里不做详细说明。
ACL的使用
什么是ACL
ACL(access control list)是访问控制列表。
之前在介绍文件系统时候介绍的文件权限控制,仅能针对用户、用户组、其他人这三个维度进行粗略控制,如果我们需要这之外的特殊权限控制,比如某个特定用户对某某目录具有读写权限,但又不想讲该用户变为该目录的拥有者。这时候就需要用到ACL。
简单的说,ACL可以针对单一用户、单一文件或目录进行权限设置。
虽然ACL是Linux内核之外的额外功能,但是新的Linux发行版都已默认对ACL提供了支持,要查看系统是否已经开启了ACL,可以:
[root@xyz ~]
[ 3.644493] 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)
[ 7.964164] SGI XFS with ACLs, security attributes, no debug enabled
SGI XFS with ACLs 表明当前系统已经为xfs 文件系统开启了ACL功能。
设置ACL
有两个ACL设置相关的命令:
getfacl :获取某个文件/目录的ACL设置选项。setfacl :修改某个文件/目录的ACL设置选项。
setfacl
如果要使用ACL给某个用户添加上某个文件的相关权限,可以:
[root@xyz ~]
[root@xyz tmp]
[root@xyz tmp]
-rw-r--r--. 1 root root 0 8月 21 11:29 acl_test
[root@xyz tmp]
[root@xyz tmp]
-rw-r-xr--+ 1 root root 0 8月 21 11:29 acl_test
[root@xyz tmp]
[root@xyz tmp]
-rwxr-xr--+ 1 root root 0 8月 21 11:29 acl_test
其中setfacl -m u::rwx acl_test 这种没有指定用户名的做法,是给文件的拥有者设置相关权限。
可以注意到,设置完ACL权限后,文件的信息栏中最后一位标识变成了+ ,这表明该文件设置了ACL权限。
getfacl
现在使用getfacl 命令查看上面设置好的ACL权限:
[root@xyz tmp]
user::rwx
user:user1:r-x
group::r--
mask::r-x
other::r--
可以清楚地看到,文件拥有者(root)的权限为user::rwx ,而user1 的权限为user:user1:r-x 。此外需要注意mask 这个选项,其作用有点像创建目录和文件时候决定默认权限的umask,但并不完全像,因为这里mask 选项的实际用途是决定实际ACL的最终权限,也就是说虽然上边的设置对于root 的权限是rwx ,但因为mask 是r-x ,所以经过mask 的“遮罩”后,实际权限只能是r-x 。对于user1 来说反而没影响,因为本身的设置就是r-x 。因为上边的原因,ACL的mask 设置通常被设置成rwx 比较容易使用。
上边都是纯理论的讨论,实际上作为文件的拥有者和超级管理员,root 自然是对该文件拥有全部权限的。
mask
ACL的mask选项上边已经介绍过了,现在展示如何修改mask的值:
[root@xyz tmp]
[root@xyz tmp]
user::rwx
user:user1:r-x
group::r--
mask::r--
other::r--
可以看到使用getfacl 打印出的信息中出现了提示#effective:r-- ,这正是在说因为mask 的存在,user1 的实际权限是r-- ,设置中添加的x 权限不会真正生效。
实例
现在有一个用户myuser1 :
[root@xyz tmp]
uid=1502(myuser1) gid=1504(myuser1) 组=1504(myuser1),1503(mygroup1)
还有一个之前创建的项目目录:
[root@xyz tmp]
drwxrws---+ 2 root projecta 6 8月 21 10:36 /srv/projecta/
因为myuser1 不属于projecta ,所以自然是无法进入该目录:
[myuser1@xyz ~]$ cd /srv
[myuser1@xyz srv]$ cd projecta/
-bash: cd: projecta/: 权限不够
如果要在不调整从属用户组和目录权限的情况下让myuser1 能进入目录,可以使用ACL权限设置的方式实现:
[root@xyz tmp]
[root@xyz tmp]
getfacl: Removing leading '/' from absolute path names
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
使用myuser1 用户进入目录:
[myuser1@xyz srv]$ cd projecta/
[myuser1@xyz projecta]$
ACL权限继承
默认情况下所设置的ACL权限是不会继承的:
? ssh pro1@192.168.1.105
pro1@192.168.1.105's password:
[pro1@xyz ~]$ cd /srv/projecta/
[pro1@xyz projecta]$ touch test_file
[pro1@xyz projecta]$ mkdir test_dir
[pro1@xyz projecta]$ ls -al
总用量 0
drwxrws---+ 3 root projecta 39 8月 21 11:59 .
drwxr-xr-x. 4 root root 93 8月 21 10:36 ..
drwxrwsr-x. 2 pro1 projecta 6 8月 21 11:59 test_dir
-rw-rw-r--. 1 pro1 projecta 0 8月 21 11:59 test_file
可以看到虽然/srv/projecta 目录设置了ACL权限,但是在其中创建的文件和目录并不会继承ACL权限(权限信息的最后并没有+ )。
如果想让子目录或者文件继承目录的ACL权限,可以:
[root@xyz tmp]
[root@xyz tmp]
getfacl: Removing leading '/' from absolute path names
user::rwx
user:myuser1:r-x
group::rwx
mask::rwx
other::---
default:user::rwx
default:user:myuser1:r-x
default:group::rwx
default:mask::rwx
default:other::---
getfacl 打印出的信息中出现了default 的相关内容,那些就是子目录和文件会继承的ACL权限。
重新创建子文件和目录:
[pro1@xyz projecta]$ rmdir test_dir
[pro1@xyz projecta]$ rm -f test_file
[pro1@xyz projecta]$ touch test_file
[pro1@xyz projecta]$ mkdir test_dir
[pro1@xyz projecta]$ ls -al
总用量 0
drwxrws---+ 3 root projecta 39 8月 21 12:04 .
drwxr-xr-x. 4 root root 93 8月 21 10:36 ..
drwxrws---+ 2 pro1 projecta 6 8月 21 12:04 test_dir
-rw-rw----+ 1 pro1 projecta 0 8月 21 12:04 test_file
看到+ 了,新的子文件和目录有继承ACL权限。
实际测试一下:
? ssh myuser1@192.168.1.105
myuser1@192.168.1.105's password:
Last login: Sat Aug 21 11:48:42 2021 from icexmoon-book
[myuser1@xyz ~]$ cd /srv/projecta/
[myuser1@xyz projecta]$ cd test_dir
删除ACL权限
要想删除一个文件或目录的所有的ACL权限:
[root@xyz tmp]
[root@xyz tmp]
总用量 0
drwxrws---+ 2 pro1 projecta 6 8月 21 12:04 test_dir
-rw-rw----+ 1 pro1 projecta 0 8月 21 12:04 test_file
[root@xyz tmp]
drwxrws---. 3 root projecta 39 8月 21 12:04 /srv/projecta/
需要注意的是默认不会影响到子目录或文件的ACL权限,如果有需要,可以使用-R 参数。
如果只想删除个别用户或者ACL继承权限的,可以:
[root@xyz tmp]
[root@xyz tmp]
[root@xyz tmp]
getfacl: Removing leading '/' from absolute path names
user::rwx
group::rwx
mask::rwx
other::---
default:user::rwx
default:group::rwx
default:mask::rwx
default:other::---
如果想禁止某个用户使用目录或文件,可以:
[root@xyz tmp]
[root@xyz tmp]
getfacl: Removing leading '/' from absolute path names
user::rwx
user:pro3:---
group::rwx
mask::rwx
other::---
default:user::rwx
default:group::rwx
default:mask::rwx
default:other::---
- 表示不拥有任何权限。
用户身份切换
一般用户要想切换到root 用户,以执行一些root 用户才可以执行的操作,可以:
su
使用su 可以切换身份为其他账号,如果不指定账号名,将切换到root 账号:
[pro1@xyz projecta]$ su
密码:
[root@xyz projecta]
uid=0(root) gid=0(root) 组=0(root) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[root@xyz projecta]
USER=pro1
PATH=/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/pro1/.local/bin:/home/pro1/bin
MAIL=/var/spool/mail/pro1
LOGNAME=pro1
XDG_DATA_DIRS=/home/pro1/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
需要注意的是,通过这种方式切换到root 账户,实际上是使用的是non-login shell ,所以虽然id 命令显式当前用户的确是root 没错,但是与用户相关的环境变量,如USER 、MAIL 等依然是切换之前的信息。
不过万幸的是至少家目录是root 的家目录:
[root@xyz projecta]
[root@xyz ~]
/root
但不管怎么说,这种没有通过login shell 且没有完全加载用户相关环境变量的情况需要避免,所以如果要切换到root 用户,应该使用su - :
[pro1@xyz projecta]$ su -
密码:
上一次登录:六 8月 21 15:38:44 CST 2021pts/1 上
[root@xyz ~]
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
XDG_DATA_DIRS=/root/.local/share/flatpak/exports/share:/var/lib/flatpak/exports/share:/usr/local/share:/usr/share
[root@xyz ~]
此外,如果仅是想使用root 权限执行一条命令,执行完后回到原来的用户,可以:
[pro1@xyz projecta]$ head -n 5 /etc/shadow
head: 无法打开"/etc/shadow" 读取数据: 权限不够
[pro1@xyz projecta]$ su - -c 'head -n 5 /etc/shadow'
密码:
root:$6$h5eXZCiKw8ucXyB2$PxxRgKneIDs2TWIpg916ugAfGCfqNf/HJHiXjy0PTPtUmY.pR/e2cUMpjRBqbx5Y0AHNJtjxAf3aOUTek3DpO.::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::
lp:*:18353:0:99999:7:::
这样的使用方式与sudo 命令类似,不同的是这里需要root 的密码,而sudo 命令仅需要当前登录用户的密码。
如果需要切换到非root 账号,可以:
[pro1@xyz projecta]$ su -l icexmoon
密码:
上一次登录:六 8月 21 09:55:47 CST 2021从 icexmoon-bookpts/0 上
[icexmoon@xyz ~]$ id
uid=1000(icexmoon) gid=1000(icexmoon) 组=1000(icexmoon),10(wheel) 环境=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023
[icexmoon@xyz ~]$ exit
登出
需要注意的是,虽然不使用参数-l 同样可以切换:su -l icexmoon 。但是这种做法就等同于使用su 切换root 用户,此种情况下使用的是non-login shell ,即不会加载用户相关的环境变量,所以是有问题的,应当避免。
同时,对于账号信息中shell 设置为/sbin/nologain 的账号,同样是无法切换的:
[root@xyz tmp]
最后一次失败的登录:六 8月 21 16:08:39 CST 2021pts/1 上
最有一次成功登录后有 1 次失败的登录尝试。
This account is currently not available.
[root@xyz tmp]
Login: sshd Name: Privilege-separated SSH
Directory: /var/empty/sshd Shell: /sbin/nologin
Last login 六 8月 21 16:09 (CST) on pts/0
No mail.
No Plan.
sudo
事实上并非所有人都可以使用sudo 命令,只有符合配置文件/etc/suders 中的设置的账号才可以。
如果你还记得Linux 之旅 1:安装中安装Linux时候勾选的那个将账户添加为管理员的选项,其实就是在通过/etc/suders 配置文件设置让该账号具有使用sudo 命令的权限。
基本用法
使用sudo 命令可以很方便地通过其他用户地身份执行某条命令:
[root@xyz tmp]
[root@xyz tmp]
-rw-r--r--. 1 sshd sshd 0 8月 21 16:22 /tmp/sudo_test_file
通过-u 可以指定执行命令的用户,如果不加则为root 用户。
甚至可以执行多条命令:
[root@xyz tmp]
[root@xyz tmp]
总用量 0
-rw-r--r--. 1 sshd sshd 0 8月 21 16:26 sudo_test_file2
这实际上是借助sh -c 来实现的,有点套娃的意思。
事实上sudo 命令的调用过程如下:
- 读取
/etc/sudoers 配置文件,并判断当前用户有没有执行sudo 命令的权限。 - 如果通过上一步检测,则会要求输入当前用户的密码(
root 不需要输入密码)。 - 如果密码也正确,则会执行
sudo 命令后的Shell 命令。
之所以会要求用户输入密码,是考虑到用户有可能临时离开电脑去上厕所或喝咖啡,所以要求身份验证。通过后短期内再次使用sudo 不会再重复要求验证。
/etc/sudoers
上面已经说了,用户能不能使用sudo 是由/etc/sudoers 这个配置文件决定的,如果一个未添加权限的用户使用sudo 命令:
[pro1@xyz projecta]$ sudo head -n 5 /etc/shadow
我们信任您已经从系统管理员那里了解了日常注意事项。
总结起来无外乎这三点:
[sudo] pro1 的密码:
pro1 不在 sudoers 文件中。此事将被报告。
如果要给一个用户开放sudo 权限,自然需要root 来修改这个文件:
[root@xyz tmp]
这个命令会使用vi 打开/etc/sudoers ,可以搜索root ,然后依葫芦画瓢地设置一个用户可以使用sudo :
这里这个字段的含义为:
- 账号
- 登录者的来源主机名(可以限制远程登录)
- 可切换的身份
- 可执行的命令
现在使用user1 用户执行sudo :
[user1@xyz ~]$ sudo head -n 5 /etc/shadow
我们信任您已经从系统管理员那里了解了日常注意事项。
总结起来无外乎这三点:
[sudo] user1 的密码:
root:$6$h5eXZCiKw8ucXyB2$PxxRgKneIDs2TWIpg916ugAfGCfqNf/HJHiXjy0PTPtUmY.pR/e2cUMpjRBqbx5Y0AHNJtjxAf3aOUTek3DpO.::0:99999:7:::
bin:*:18353:0:99999:7:::
daemon:*:18353:0:99999:7:::
adm:*:18353:0:99999:7:::
lp:*:18353:0:99999:7:::
除了直接将用户加入/etc/sudoers 外,还可以通过配置用户组来赋予sudo 使用权限:
[root@xyz tmp]
Defaults !visiblepw
Defaults always_set_home
Defaults match_group_by_gid
Defaults always_query_group_plugin
Defaults env_reset
Defaults env_keep = "COLORS DISPLAY HOSTNAME HISTSIZE KDEDIR LS_COLORS"
Defaults env_keep += "MAIL PS1 PS2 QTDIR USERNAME LANG LC_ADDRESS LC_CTYPE"
Defaults env_keep += "LC_COLLATE LC_IDENTIFICATION LC_MEASUREMENT LC_MESSAGES"
Defaults env_keep += "LC_MONETARY LC_NAME LC_NUMERIC LC_PAPER LC_TELEPHONE"
Defaults env_keep += "LC_TIME LC_ALL LANGUAGE LINGUAS _XKB_CHARSET XAUTHORITY"
Defaults secure_path = /sbin:/bin:/usr/sbin:/usr/bin
root ALL=(ALL) ALL
user1 ALL=(ALL) ALL
%wheel ALL=(ALL) ALL
看到%wheel ALL=(ALL) ALL 没,这行的意思是用户组wheel 具有使用sudo 的权限,因此我们可以通过将用户添加到wheel 用户组的方式赋予sudo 权限:
[root@xyz tmp]
[root@xyz tmp]
uid=1505(pro1) gid=1508(pro1) 组=1508(pro1),10(wheel),1507(projecta)
之后登录pro1 测试的过程不再赘述。
如果想每次使用sudo 不再需要输入密码进行验证,可以通过visudo 命令修改配置文件中的如下信息:
将上面红框位置内的信息去掉注释,变成如上的内容后保存即可。
这样做了以后,wheel 用户组内的用户也可以像root 一样在使用sudo 的时候不需要输入密码了。
此外,还可以实现一些更复杂的设置,比如说让某些用户只能通过sudo 执行特定的命令:
可以修改为上边的设置,现在user1 仅能执行passwd 这个命令了(需要注意的是这里指定的命令必须是完整路径):
[user1@xyz ~]$ sudo head -n 5 /etc/shadow
[sudo] user1 的密码:
对不起,用户 user1 无权以 root 的身份在 xyz.icexmoon.centos 上执行 /bin/head -n 5 /etc/shadow。
[user1@xyz ~]$ sudo passwd myuser1
[sudo] user1 的密码:
更改用户 myuser1 的密码 。
新的 密码:
无效的密码: 密码少于 8 个字符
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
但是要知道的是,user1 用户拥有的是执行passwd 这个命令的全部功能,也就是说也可以通过passwd 命令修改root 用户的密码,一般来说我们显然不允许这样的操作,如果要进一步限制,不允许user1 修改root 的密码,可以:
需要注意这里的命令顺序,! 表示会被阻止的命令形式,如果!/usr/bin/passwd root 放在usr/bin/passwd [a-zA-Z]* 之前就会出错,原因是先阻止再被允许,显然是不正确的规则,所以最好将阻止规则放在允许规则的后边。
现在看效果:
[user1@xyz ~]$ sudo passwd root
对不起,用户 user1 无权以 root 的身份在 xyz.icexmoon.centos 上执行 /bin/passwd root。
[user1@xyz ~]$ sudo passwd
对不起,用户 user1 无权以 root 的身份在 xyz.icexmoon.centos 上执行 /bin/passwd。
[user1@xyz ~]$ sudo passwd myuser1
更改用户 myuser1 的密码 。
新的 密码:
无效的密码: 密码未通过字典检查 - 它基于字典单词
重新输入新的 密码:
passwd:所有的身份验证令牌已经成功更新。
正是我们希望的。
此外还可以在/etc/sudoers 中使用别名:
User_Alias PASSWORD_ADMINS = pro1,pro2,pro3,myuser1,myuser2
Cmnd_Alias PASSWORD_COMMAND = !/usr/bin/passwd,/usr/bin/passwd [a-zA-Z]*,!/usr/bin/passwd root
PASSWORD_ADMINS ALL=(root) PASSWORD_COMMAND
写入上面的信息后保存后,PASSWORD_ADMINS 中关联的用户将可以使用sudo 命令修改一般用户的密码。使用别名可以更容易地配置sudo 命令的管理权限。
最后,在介绍一种用途:借助sudo 命令我们可以实现在不知道root账号密码的情况下切换为root用户,这样可以更好地保护root密码(虽然好像意义并不是特别大,毕竟有sudo 权限的用户都可以修改root 的密码)。
实现的方法也很简单,只要在/etc/sudoers 中添加这样的信息:
pro1 ALL=(root) /usr/bin/su -
然后使用对应的用户这样:
[pro1@xyz ~]$ sudo su -
如果需要输入密码就输入自己账户的,就可以切换为root 了。
事实上《鸟哥的私房菜》这部分章节还有相当一部分内容,但本文的幅度已经很长了,而且我的Typora编辑器已经很卡了,就分为两个章节发吧。
先到这里了,谢谢阅读。
|