linux账号管理

UID与GID

linux主机其实并不会直接认识用户的账户名称,实际上识别的是用户的ID,账户名字与ID的对应关系记录在 /etc/passwd 里面,登录后用户至少能够取得两个ID——使用者ID(UID)和群组ID(GID),当需要显示一个用户是谁/属于哪个群组的时候,系统又会根据用户的ID去查找 /etc/passwd/etc/group 中和ID对应的名字。

#尝试查看一个用户的ID
[email protected]:~# id fine
uid=1001(fine) gid=1001(fine) groups=1001(fine)

我们可以尝试把passwd文件中的id换一个,之后再使用 ls -l 查看文件所属的时候,会发现原来显示该用户名字的地方只剩下了id(1001)了,因为这个id已经找不到对应的名字了。(如果不改回来,而目录权限又是700的话,该用户也进不去这个文件夹了)

相关的文件

关于用户

用户登录系统后,系统进行了一系列的处理:

  1. 在passwd文件中查找输入的用户名,如果找到了就读出UID和GID,以及shell配置 (我们可以在passwd中为用户设置默认使用的shell程序)
  2. /etc/shadow 中查找对应的账号还有UID以及密码,核对输入的密码是否正确。
  3. 通过验证之后,用户才能取得shell的控制权/

我们可以查看 /etc/passwd 文件,大概有下面两种类型的账号。

root:x:0:0:root:/root:/bin/bash

bin:x:2:2:bin:/bin:/usr/sbin/nologin

注意到第二个用户“bin”取得的shell是无法登录的,这些是系统用户,在系统服务中使用。

账号的字段分为下面几部分:

  1. 账号名称
  2. 密码 (但是现在版本的linux密码以及不存放在这了,而是放到了 /etc/shadow 中)
  3. UID

    一般Linux对于UID的范围有下面的限制

    • 0 代表系统管理员 (把其他用户的UID改成0也能使其变为系统管理员
    • 1~999 系统账号,用来设置系统服务运行时的权限,一般 1~200 为发行版自己创建的账号,201~999 为用户自己创建的系统账号。
    • 1000~60000 (新的版本中可以到2^32-1) 给一般用户使用的UID
  4. GID 标明用户的群组ID
  5. 用户信息说明
  6. 主文件夹,用户登陆后所在的文件夹
  7. Shell程序 用户登陆后取得的Shell程序,可以通过修改这个选项修改用户默认获得的shell,/sbin/nologin 是无法取得的shell。

我们接着可以查看一下 /etc/shadow 这个文件的结构:

root:$6$.hOGhiqOZ0XfcZ7s$ZQpA9uvQIN/FCV0df2reYhDL9rqsESlVIE6zr8EDtUA7glvzb1QbLnYuuVZY9x4qDoJUSmgAVuSipcspF.e9s0:18552:0:99999:7:::
daemon:*:18550:0:99999:7:::
bin:*:18550:0:99999:7:::
sys:*:18550:0:99999:7:::

shadow实际记录了用户的密码,共有9个字段。

  1. 账号名称 与passwd中的名称对应
  2. 密码 hash加密过后的密码,我们可以在前面加一个!之类的使其失效(相当于这个账户被冻结了)
  3. 最近修改密码的日期

    从1970/1/1 开始计算的日期,可以使用命令 echo $(($(date --date="2020/10/17" +%s) /86400+1)) 查看指定的日期到1970/1/1有多少天。

  4. 密码不可变动的天数

    指明了密码在最近一次被修改后与要过多少天才能再次修改,0代表随时可以修改。

  5. 密码需要重新设置的天数

    指定了在最近一次修改密码后要过多少天需要用户修改一次密码,否则密码就会过期

  6. 密码需要变更前的警告天数

    在密码快要失效的多少天前开始警告用户密码快要过期。

  7. 密码过期后的宽限时间

    指明了密码在过期后,还有多少天能够登录(登陆后会强制要求用户重修你设置密码)

  8. 账号失效日期

    和3的格式一样,指定了哪一天后账户会失效

  9. 保留字段

如果我们忘记了root密码,也不是完全没救,我们可以先使用其他的系统(如livecd)挂载根目录(或者使用单人维护模式)再修改 /etc/shadow 文件,将密码字段清空,重新开机后不需要密码即可登录。

关于群组

看完用户相关的文件,我们继续看群组相关的文件,首先看到 /etc/group

group文件记录了GID和群组名称的对应关系。

root:x:0:
daemon:x:1:
bin:x:2:
sys:x:3:

有四个字段

  1. 群组名称
  2. 群组密码

    这个密码是给群组管理员使用的,群组管理员可以将一个用户加入自己管理的群组。这个密码也移动到了 /etc/gshadow 文件中。

  3. GID
  4. 群组包含的账户名称

    新版的linux已经不会把群组的初始用户加入到这个字段中了,如新增一个用户user,会同时创建一个user群组,但是因为user是user群组的初始用户,所以不会在这显示,但是我们可以尝试把其他的用户加入该群组,就能在这里看见新加入的用户的名字了。

接着看看 /etc/gshadow 文件

root:*::
daemon:*::
bin:*::
sys:*::

也有四个字段:

  1. 群组名称
  2. 密码栏 (如果没有设置群组管理员,显示的就是个* 或者 !)
  3. 群组管理员的账号
  4. 加入该群组的账号 (和group文件相同)

这里需要介绍一下gpasswd这个指令,该指令可以用来设置群组的管理员,管理员可以将用户加入自己管理的群组。

gpasswd groupname
: 没有参数时,代表给群组设置一个管理密码
-A username 将username设置为groupname的群组管理员
-M 将某些账号加入该群组
-r 删除群组的管理密码
-R 使群组管理密码失效
#上面的命令是root用的,群组管理员使用下面两条命令
gpasswd [-ad] user groupname
-a 将用户加入群组
-d 将用户移出群组

有效群组 初始群组

我们可以注意到,passwd中一个用户只对应了一个GID,然而我们又知道用户是可以加入多个群组的,这里就要了解到有效群组和初始群组的区别了。

GID指定的是 初始群组,用户登录系统,取得shell时,立即就能取得初始群组的权限(也正是因为这样,所以也没必要在group第四个字段中加入默认用户的名字了)。

一个用户可以有多个群组,当他对文件进行操作的时候,具体使用的群组取决于当前的有效群组,使用命令 groups 可以查看当前用户所属的群组(貌似要重新开一个shell才能看见更新),而第一个显示的就是有效群组

使用命令 newgrp 可以切换有效群组,之后我们再次新建文件,可以看到文件的所属群组已经是我们新切换的群组了。这条命令实际上是新建了一个shell,所以想要切换回之前的有效群组,直接使用 exit 退出这个shell即可。

账号管理

新增与删除使用者

使用 useradd 即可添加一个用户,当然也可以带上参数

useradd [-u UID] [-g 初始群组] [-G 次要群组] [-mM] [-s shell] 账户名
-M 不创建使用者主文件夹(创建系统账户时的默认参数)
-m 创建使用者主文件夹 (创建一般账号时的默认值)
-c passwd 第三栏的说明内容
-d 指定主文件夹
-r 创建系统账号
-e 指定账号失效日期 “YYYY-MM-DD”
-f 密码是否会失效

在创建一个用户的时候,系统一般会进行下面几个文件的设置:

  1. passwd 中新增一行相关的记录
  2. shadow 中填入密码相关参数,此时密码还没有设置 (某些发行版在添加用户的时候就要求设置了密码,而还有一些则需要自己使用passwd设置)
  3. group中新增一个和账户名称一样的群组
  4. /home 下新增一个与账户同名的文件夹作为主文件夹。

UID的取用一般是选取passwd相同类型用户中最大的一个UID并加一获得的

另外,使用useradd -D可以看见 useradd的默认参考值 (该参考文件位于 /etc/default/useradd)

[email protected]:/home# useradd  -D
GROUP=100
HOME=/home
#密码过期后是否会失效
INACTIVE=-1
#账号失效日期
EXPIRE=
SHELL=/bin/sh
#SKEL代表用户主目录的参考文件夹,新建用户主目录时会拷贝这个文件夹
SKEL=/etc/skel
CREATE_MAIL_SPOOL=no

我们注意到这里指定的GID是100,群组名为users,但是和实际的表现不符合。这是因为linux有两种群组机制

  1. 私有群组机制

    即Debian CentOS等系统使用的机制,创建用户时系统会创建一个和账户名称一样的群组作为用户的初始群组,这样更有保密性。

  2. 公共群组机制

    在SuSE中,每个账户都属于users这个群组,主文件夹的默认权限一般是 755 ,大家可以户向分享主文件夹中的文件。

除了基本账号的设置,UID/GID以及密码设置还参考了 /etc/login.defs文件。里面指定了多久需要变更密码,多久不可修改密码,密码最短长度,过期前警告天数等等。

设置用户密码

通过useradd添加用户后,用户的密码还没有被设置(有部分发行版在添加的时候就要求设置密码),之后我们需要使用passwd来为用户设置密码。

passwd 
--stdin 接收来自前一个管道的数据作为密码输入,在脚本中使用 不需要重复输入确认
-l lock,shadow第二栏之前加上!使得密码失效
-u unlock
-S 列出密码相关参数
-n 多久不可修改密码
-x 多久内必须修改密码
-w 密码过期前警告天数
-i 密码失效日期 (密码过期后多少天宣告账号失效)

普通用户设置密码的时候一般会使用PAM模块来进行强度检验,太弱的密码是无法成功设置的。不过root设置的密码可以通过检验。

除了 passwd 我们还可以使用 chage 来对密码参数进行详细的显示。

chage
-l 列出详细参数
-d 修改最近一次更改密码的时间
-E 修改账号失效日期
-I 修改密码过期后再过多少天账号失效
-m 修改密码修改后多少天内不能修改
-M 密码多久需要修改一次
-W 密码过期多久前进行警告

[email protected]:/# chage fine -l
Last password change                                    : Oct 17, 2020
Password expires                                        : never
Password inactive                                       : never
Account expires                                         : never
Minimum number of days between password change          : 300
Maximum number of days between password change          : 99999
Number of days of warning before password expires       : 7

我们可以使用 change -d 0 账户名 将密码修改日期指定为0,这样的话,用户登录后系统会要求用户重新设置一个密码。

另外我们还可以 usermod 对用户信息进行微调。

usermod [] username
  -c, --comment COMMENT         new value of the GECOS field
  -d, --home HOME_DIR           new home directory for the user account
  -e, --expiredate EXPIRE_DATE  set account expiration date to EXPIRE_DATE
  -f, --inactive INACTIVE       set password inactive after expiration
                                to INACTIVE
  -g, --gid GROUP               force use GROUP as new primary group
  -G, --groups GROUPS           new list of supplementary GROUPS
  -a, --append                  append the user to the supplemental GROUPS
                                mentioned by the -G option without removing
                                him/her from other groups
  -h, --help                    display this help message and exit
  -l, --login NEW_LOGIN         new value of the login name
  -L, --lock                    lock the user account
  -m, --move-home               move contents of the home directory to the
                                new location (use only with -d)
  -o, --non-unique              allow using duplicate (non-unique) UID
  -p, --password PASSWORD       use encrypted password for the new password
  -R, --root CHROOT_DIR         directory to chroot into
  -s, --shell SHELL             new login shell for the user account
  -u, --uid UID                 new UID for the user account
  -U, --unlock                  unlock the user account
  -v, --add-subuids FIRST-LAST  add range of subordinate uids
  -V, --del-subuids FIRST-LAST  remove range of subordinate uids
  -w, --add-subgids FIRST-LAST  add range of subordinate gids
  -W, --del-subgids FIRST-LAST  remove range of subordinate gids
  -Z, --selinux-user SEUSER     new SELinux user mapping for the user account

最后我们还可以使用 userdel 删除一个账户。 如果加上 -r 参数,会把主文件夹一起删掉。不过如果用户这样删不掉所有和该用户相关的文件,如果想要彻底删除,要使用 find / -user username 找出所有相关文件并删除。

查看/设置用户信息

上面提到的几个命令主要还是root使用的,这里再补充一些一般用户能够使用的命令。

使用 id 可以查看用户的UID/GID。使用 finger 可以查到更多和用户相关的信息,如新增用户时设置的电话号码邮箱,姓名等等,不过现在的发行版一般不会默认安装finger,需要的话可以自行安装。

虽然没有安装finger,但是系统默认安装了chfn,这个可以用来修改用户相关的信息,姓名,电话号码等等。

chsh 可以用来修改使用的shell,chsh -l列出所有可用的shell (/etc/shells 内容),chsh -s进行设置。

还有一点可以留意,那就是chfnchsh都有着SUID属性,让一般用户也可以修改passwd文件。

新增与删除群组

groupadd [-g gid 指定uid] [-r 系统群组] 群组名称 可以添加一个群组,而 groupmod也可以对群组参数进行微调,如修改GID和群组名称等等。不过不要随便变动GID

groupdel 这条命令很明显就是在删除群组,不过如果某个账户的初始群组为想要删除的群组,那么这个群组是无法删除的,我们可以修改这个账户的GID(初始群组),或者干脆先把这个账户给删了。

切换使用者

因为一般还是建议使用一般账号来进行操作,或者有时候需要用低一些的权限来启动服务(这样,即使服务因为一些漏洞被入侵,也不会导致灾难性后果),还有某些软件不允许root运行,所以我们有时候需要切换使用者。

使用 su - 可以将身份切换为root,需要root密码,也可以使用sudo命令来意root的权限执行命令,sudo只需要输入使用者自己的密码就可以了。

su

switch user,可以进行任何身份的切换。

su [-lm] [-c 指令] [username]
- : 单纯使用 - ,代表使用login-shell的方式登录系统(会读取对应的配置文件)
-l: 和- 类似,但是需要指明想要切换到的账户,也是 login-shell方式
-c 可以带上指令,执行一次之后就退出shell
例:
[email protected]:~$ head -n 4 /etc/shadow
head: cannot open '/etc/shadow' for reading: Permission denied
[email protected]:~$ su - -c  head -n 4 /etc/shadow
su: invalid option -- 'n'
Try 'su --help' for more information.
[email protected]:~$ su - -c  'head -n 4 /etc/shadow'
Password: 
root:$6$.hOGhiqOZ0XfcZ7s$ZQpA9uvQIN/FCV0df2reYhDL9rqsESlVIE6zr8EDtUA7glvzb1QbLnYuuVZY9x4qDoJUSmgAVuSipcspF.e9s0:18552:0:99999:7:::
daemon:*:18550:0:99999:7:::
bin:*:18550:0:99999:7:::
sys:*:18550:0:99999:7:::

直接接用户名,切换到的用户,采用的是 no-login shell 方式
这种情况下,比如PATH MAIL PWD(主文件夹)这些环境变量“可能”会受上一个shell的影响,导致错乱。 所以一般还是加上 - 使用login shell的方式切换账户吧。

sudo

如果我们需要用户能够执行一些特权命令,但是又不希望他们知道root密码,可以使用sudo 注意 默认情况sudo passwd root 是可以修改root密码的...所以该权限依旧只能给信任的人,也可以参考这篇文章 禁止sudo修改密码

sudo [-b] [-u 新使用者]
-b 将后续指令放到后台执行,不会影响当前的shell
-u 后面可以接想要切换的账户,不写则代表root
sudo -u sshd touch /tmp/mysshd
[email protected]:~# ls -l /tmp/mysshd
-rw-r--r-- 1 sshd nogroup 0 Oct 17 05:58 /tmp/mysshd

sudo还可以让我们切换身份进行某项任务,如使用sshd的权限新建文件,我们是无法使用su - sshd换到系统账号的,所以只能使用sudo达成这种需求。

sudoers

默认情况下sudo只能root使用,如果我们需要让用户能够使用sudo,需要修改 /etc/sudoers 文件,由于该文件有一定规范,所以使用 visudo修改这个文件更加合适。(visudo结束修改的时候会检查语法)

visudo

sudoers文件有几种设置方法:

  1. 单一使用者可进行root的所有指令,与sudoers语法

    增加一个 fine ALL=(ALL) ALL 即可。 这一行中的几个元素的意义如下:

    使用者账户 登录者来源的主机名称=(可切换身份) 可下达的指令,我们还可以把最后一个All改成 NOPASSWD: ALL,使得用户使用sudo的时候不再需要输入密码。

  2. 让一个群组的成员都能够使用sudo

    %fine ALL=(ALL) ALL

    除了第一个字段不一样,多了一个%指明这是群组,其他都是一样的,这样,所有fine群组的成员都可以使用sudo了。

  3. 限制指令

    有时候我们不希望用户能以root权限做任何事请,如重启/关机/修改密码等等,那么我们可以对用户使用sudo执行的命令作出限制。

    fine ALL=(root) /usr/bin/passwd(必须绝对路径) 指明,fine用户只能以root身份执行passwd命令,甚至还可以对参数进行限制 fine ALL=(root) !/usr/bin/passwd, !/usr/bin/passwd root, /usr/bin/passwd [A-Za-z]*命令前面加上感叹号代表不可执行 ,这一行让用户仅能以root身份修改密码,并且不能修改root的密码

  4. 使用别名

    如果同时需要设置多个用户,我们并不需要加入很多行设置,如果他们的权限相同,可以使用别名。别名一定要用大写。

    User_Alias ADMPW = u1, u2, u3, u4
    Cmnd_Alias ADMCMD = !/usr/bin/passwd, !/usr/bin/passwd root
    ADMPW ALL=(root) ADMCMD
  5. sudo时间间隔

    用户在使用过sudo后,一段时间内不需要再次输入密码,一般为五分钟。

  6. 配合su使用

    即使不告诉用户root密码,也可以让用户使用sudo su -的方式使用自己的密码获得root的shell。

ACL细化权限管理

linux默认的权限无法对一个文件进行细化的权限设置,如一个文件不允许特定的某一个人/群组进入或者是修改等等,这时我们用到ACL Access Control List来进行辅助了。

ACL的额外功能:

  • 可以针对使用者设置权限
  • 可以针对群组来设置权限
  • 可以设置目录下新建的文件/目录时的默认权限。

如果有一个目录需要给很多人使用,而每个人或者每个群组的权限还不一样的时候,传统的权限系统是无法处理这种问题的,这时我们就需要ACL了。现在ACL基本已经默认加到了Linux文件系统的挂载参数中。dmesg | grep -i acl 可以看看是否支持。

ACK的设置与观察还算比较简单。

  • getfacl 取得某个文件/目录的ACL设置信息

    [email protected]:~# getfacl fine
    # file: fine
    # owner: fine
    # group: fine
    user::rwx
    group::r-x
    other::r-x
  • setfacl 设置某个文件/目录的ACL

    setfacl [-bkRd] [{-m|-x} acl参数] 文件名
    -m 设置后续的acl参数
    -x 删除后续的acl参数 与-m不可同时使用
    
    -b 移除所有的acl设置参数
    -k 移除“默认的”acl参数
    -R 递归设置
    -d 设置acl参数为默认值
    1. 针对特定用户设置权限

      # acl参数 u:[使用者账号列表]:[rwx] 如果u后面不指明使用者,那么代表文件的拥有者
      setfacl -m u:fine:rx acltest
      [email protected]:~# ls -l |grep acltest
      -rw-r-xr--+ 1 root  root     0 Oct 17 05:18 acltest
      #此时我们注意到权限多了个 + 并且现在显示的权限和一开始的 -rw-r--r--也不一样了
      #使用acl后 我们应该使用getfacl来查看权限信息
      
      [email protected]:~# getfacl acltest
      # file: acltest
      # owner: root
      # group: root
      user::rw-
      user:fine:r-x
      group::r--
      mask::r-x
      other::r--
    2. 针对单一群组

      # acl参数 g:[群组列表]:[rwx] 如果为 g::[rwx]则代表设置所属群组的权限
      setfacl -m g::rx acltest
      setfacl -m g:fine:rx acltest
      #可以看到有了多个群组的权限设置
      [email protected]:~# getfacl acltest
      # file: acltest
      # owner: root
      # group: root
      user::rw-
      user:fine:r-x
      group::r-x
      group:fine:rwx
      mask::rwx
      other::r--
    3. 针对有效权限

      我们可以注意到上面的acl属性中有一个 mask 属性,代表了有效权限,acl设置的权限需要在有效权限的范围内才有效,比如 mask设置为 r--

      # m:[rwx]
      
      [email protected]:~# setfacl -m m:r acltest
      [email protected]:~# getfacl acltest
      # file: acltest
      # owner: root
      # group: root
      user::rw-
      user:fine:r-x                   #effective:r--
      group::r-x                      #effective:r--
      group:fine:rwx                  #effective:r--
      mask::r--
      other::r--

      可以注意到,之前设置为rwx或者r-x的权限,实际上变成了r---。不过一般我们都把有效权限设置成rwx,除非对于一些敏感文件,需要防止我们一不小心设置错了权限,才需要设置有效权限。

注意,如果要设置用户/群组不具有任何权限,权限字段不要留空白,而是要填上一个减号 - u:fine:-

ACL权限继承

默认情况,acl设置的权限是不会被子文件/目录继承的,如果需要acl在目录下有继承的功能,需要进行如下设置。

# 设置默认权限设置目录的未来文件的acl权限
# d[u|g]:[user|group]:权限
# d:[ug]:使用者列表:[rwx]
# 让fine在acldir下一直有rx的默认权限
[email protected]:~# mkdir acldir
[email protected]:~# setfacl -m d:u:fine:rx acl
acldir/   acltest   acltesty  
[email protected]:~# setfacl -m d:u:fine:rx acl
acldir/   acltest   acltesty  
[email protected]:~# setfacl -m d:u:fine:rx acldir/
[email protected]:~# getfacl acldir
# file: acldir
# owner: root
# group: root
user::rwx
group::r-x
other::r-x
default:user::rwx
default:user:fine:r-x
default:group::r-x
default:mask::r-x
default:other::r-x

[email protected]:~# touch acldir/subfile
[email protected]:~# getfacl acldir/subfile
# file: acldir/subfile
# owner: root
# group: root
user::rw-
user:fine:r-x                   #effective:r--
group::r-x                      #effective:r--
mask::r--
other::r--

我们还可以注意到,之前设置的mask有效权限,倒是传递到了子文件上。

文章目录