很久以来,我对Linux用户的概念都很模糊,只知道如果碰到“Permission Denied”就用sudo来执行,甚至在服务器上跑的很多东西都是用root来跑的。今天花时间学习了一下Linux用户有关的知识,记一下笔记。
本文所有代码都是在virtualbox虚拟机中进行,环境:Ubuntu 16.04.3 LTS (GNU/Linux 4.4.0-87-generic x86_64),用户名vagrant,密码vagrant。
一、用户与用户组
1.Linux是如何分辨每一个用户的
Linux并不是通过用户名来分辨每一个用户的,而是通过UID(计算机认识数字比较容易,而人类认识单词比较容易),我们平时所说的用户名只是便于人类操作和记忆。
1 2 3 4 5 |
vagrant@saltmaster:~$ ls -l total 256 -rw-r--r-- 1 root root 256191 Nov 13 06:26 bootstrap-salt.sh -rw-rw-r-- 1 vagrant vagrant 0 Nov 26 08:44 filea -rw-r--r-- 1 root root 100 Nov 20 06:30 nettools.sls |
对于每个文件,记录的其实是一个UID,之所以显示成用户名“vagrant”、“root”,是因为在/etc/passwd
中存储了有关的用户信息,ls程序在显示的时候,会根据此文件将对应的UID显示成用户名。如果我们在/etc/passwd
这个文件中将UID修改,那么ls将显示的是一个UID,而不是用户名。
用户登录Linux的流程如下:
- 寻找
/etc/passwd
是否有这个用户名,如果有,读出对象的UID和GID(group ID),以及主目录和配置 - 读取
/etc/shadow
,核对密码 - 进入shell
2. passwd文件和shadow文件
Linux所有的用户都保存在/etc/passwd
文件中,格式如下:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
vagrant@saltmaster:~$ cat /etc/passwd root:x:0:0:root:/root:/bin/bash daemon:x:1:1:daemon:/usr/sbin:/usr/sbin/nologin bin:x:2:2:bin:/bin:/usr/sbin/nologin sys:x:3:3:sys:/dev:/usr/sbin/nologin sync:x:4:65534:sync:/bin:/bin/sync games:x:5:60:games:/usr/games:/usr/sbin/nologin man:x:6:12:man:/var/cache/man:/usr/sbin/nologin lp:x:7:7:lp:/var/spool/lpd:/usr/sbin/nologin mail:x:8:8:mail:/var/mail:/usr/sbin/nologin news:x:9:9:news:/var/spool/news:/usr/sbin/nologin uucp:x:10:10:uucp:/var/spool/uucp:/usr/sbin/nologin proxy:x:13:13:proxy:/bin:/usr/sbin/nologin www-data:x:33:33:www-data:/var/www:/usr/sbin/nologin backup:x:34:34:backup:/var/backups:/usr/sbin/nologin |
每一行代表一个账户,通过:
来分割信息。数一数会发现一共有7个字段,这7个字段分别代表:
- 账户名称
- 密码,可以看到所有的密码都是
x
,这是因为很多程序会读/etc/passwd
,将用户名和密码放在一起很不安全,后来密码移动到/etc/shadow
文件中了,/etc/passwd
文件只留一个x占位。 - UID
- GID
- 用户信息说明
- 主目录(即登录之后立即所在的位置)
- shell 登录之后启动的shell,这里有一个特殊的shell就是
nologin
,上面的例子中,像是backup
这种账户是无法登录shell的。所以当我们新建一些系统服务的账号,类似apache,Jenkins等都可以让它们不要登录系统
/etc/shadow
文件的格式如下:
1 2 3 4 5 6 |
vagrant@saltmaster:~$ clear vagrant@saltmaster:~$ sudo head -n 4 /etc/shadow root:!:17466:0:99999:7::: daemon:*:17379:0:99999:7::: bin:*:17379:0:99999:7::: sys:*:17379:0:99999:7::: |
可以看到,这也是用:
来分割的,一共有9列,每一列代表的意思如下:
- 账户名称
- 密码
- 最近改动密码的日期(相对于第0天,也就是1970年1月1日的偏移天数)
- 密码不可改动的日期,如果是0则可以随时修改
- 密码需要重新更改的日期,如果不改账户将会变为过期。可以看到默认设置是99999=273年
- 字段5前几天进行提醒
- 密码过期后的宽限时间,字段5+本字段天数之后依然没有更改才算过期。宽限时间内用户登录会被强制要求修改密码
- 账户失效日期,到期无法使用
- 保留字段
3.有效用户组与初始用户组
每一个用户都有一个用户组,和UID一样,Linux分辨用户组也是通过GID的,而不是通过名字。和/etc/passwd
/etc/shadow
一样,对于用户组有 /etc/group
/etc/gshadow
。
先来看/etc/group
:
1 2 3 4 5 |
vagrant@saltmaster:~$ sudo head -n 4 /etc/group root:x:0: daemon:x:1: bin:x:2: sys:x:3: |
一共四个字段:
- 用户组名字
- 用户组密码,其实很少用,和passwd一样,用x占位了
- GID
- 此用户组的用户列表,逗号分搁,没有空格(一个用户组可以有多个用户,一个用户可以在多个用户组)
/etc/gshadow
的内容几乎和/etc/group
一样:
1 2 3 4 5 6 |
vagrant@saltmaster:~$ sudo head -n 4 /etc/gshadow root:*:: daemon:*:: bin:*:: sys:*:: systemd-timesync:!:: |
要注意的事第二个字段,是密码,如果第二个字段是!
,表明该用户组没有用户组管理员。不过由于sudo
的存在,其实用户组管理员的功能很少使用了。
- 用户组名字
- 密码列
- 用户组管理员的账号
- 该用户组的所属账号
仔细观察你可能发现这样一个问题:在/etc/passwd
里面说某一个用户的用户组ID是a,但是在/etc/group
的a用户组ID下并没有看到这个账户的名字啊?
这是因为,passwd里面的用户组叫做“初始化用户组”,就是你登录到shell的用户组。这个用户组不需要写到groups里面。
如果一个用户属于很多用户组,这么这些用户组的权限,该用户都会有。那么创建一个文件,默认的用户组应该是哪个呢?
答案是“有效用户组”,通过groups
命令,可以查看当前用户的所在用户组,其中,排在第一个的是有效用户组,如果创建文件就会模式使用这个用户组。
下面的命令演示了有效用户组以及用户组的切换:
1 2 3 4 5 6 7 8 |
vagrant@saltmaster:~$ groups adm cdrom sudo dip plugdev lxd lpadmin sambashare vagrant vagrant@saltmaster:~$ touch test_a vagrant@saltmaster:~$ newgrp sudo vagrant@saltmaster:~$ touch test_b vagrant@saltmaster:~$ ll test_* -rw-rw-r-- 1 vagrant adm 0 Nov 26 15:46 test_a -rw-rw-r-- 1 vagrant sudo 0 Nov 26 15:47 test_b |
需要注意的是,newgrp
是通过新开一个shell来赋予用户新的用户组的权限,通过exit
可以回到之前的用户组。
1 2 3 4 5 6 7 |
vagrant@saltmaster:~$ exit exit vagrant@saltmaster:~$ touch test_c vagrant@saltmaster:~$ ll test_* -rw-rw-r-- 1 vagrant adm 0 Nov 26 15:46 test_a -rw-rw-r-- 1 vagrant sudo 0 Nov 26 15:47 test_b -rw-rw-r-- 1 vagrant adm 0 Nov 26 15:48 test_c |
二、创建与管理用户
1.useradd
了解了用户和用户组的概念,接下来开始讲用户的管理。
创建一个新的账户的命令是useradd
,执行这个命令需要读写/etc/passwd
等文件,所以一般需要root账户来执行。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
vagrant@saltmaster:/home$ useradd tom useradd: Permission denied. useradd: cannot lock /etc/passwd; try again later. vagrant@saltmaster:/home$ sudo -s root@saltmaster:/home# useradd tom root@saltmaster:/home# ls vagrant root@saltmaster:/home# grep tom /etc/passwd /etc/shadow /etc/group /etc/passwd:tom:x:1001:1001::/home/tom: /etc/shadow:tom:!:17496:0:99999:7::: /etc/group:tom:x:1001: root@saltmaster:/home# ls vagrant root@saltmaster:/home# su - tom No directory, logging in with HOME=/ $ pwd / $ touch tom_file touch: cannot touch 'tom_file': Permission denied |
上面的代码新建了一个tom账户,可以看到,系统并没有默认为tom创建一个home目录。在CentOS中,使用useradd
,系统一般会默认帮你做这几件事:
- 在
/etc/passwd
中创建一行与账号相关的数据 - 在
/etc/shadow
创建相关数据,但是密码为空 - 在
/etc/group
创建一个与用户名一模一样的名称 - 在
/home
下创建一个和用户名一样的目录,权限700
我们简单的使用useradd
命令,Linux会帮我们自动配置一些参数,这些参数是参考的哪里呢?见下面两条命令的输出就明白了:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 |
vagrant@saltmaster:~$ useradd -D GROUP=100 HOME=/home INACTIVE=-1 EXPIRE= SHELL=/bin/sh SKEL=/etc/skel CREATE_MAIL_SPOOL=no vagrant@saltmaster:~$ cat /etc/default/useradd # Default values for useradd(8) # # The SHELL variable specifies the default login shell on your # system. # Similar to DHSELL in adduser. However, we use "sh" here because # useradd is a low level utility and should be as general # as possible SHELL=/bin/sh # # The default group for users # 100=users on Debian systems # Same as USERS_GID in adduser # This argument is used when the -n flag is specified. # The default behavior (when -n and -g are not specified) is to create a # primary user group with the same name as the user being added to the # system. # GROUP=100 # # The default home directory. Same as DHOME for adduser # HOME=/home # # The number of days after a password expires until the account # is permanently disabled # INACTIVE=-1 # # The default expire date # EXPIRE= # # The SKEL variable specifies the directory containing "skeletal" user # files; in other words, files such as a sample .profile that will be # copied to the new user's home directory when it is created. # SKEL=/etc/skel # # Defines whether the mail spool should be created while # creating the account # CREATE_MAIL_SPOOL=yes vagrant@saltmaster:~$ |
2.passwd
创建用户用useradd
,然后需要为用户创建密码,使用passwd
命令。需要注意的有以下几点:
passwd
修改自己账户的密码,普通用户需要输入旧密码,root用户不需要- root用户可以修改其他用户的密码而不需要输入旧密码
- 普通用户在创建密码时会经过PAM模块检查密码的强度,而root无需遵守强度检查
3.其他一些修改账户的命令(sudo)
chage
命令可以修改密码参数有关的信息。
1 2 3 4 5 6 7 8 |
vagrant@saltmaster:~$ chage -l vagrant Last password change : Oct 27, 2017 Password expires : never Password inactive : never Account expires : never Minimum number of days between password change : 0 Maximum number of days between password change : 99999 Number of days of warning before password expires : 7 |
usermod
可以修改有效用户组、初始用户组、主目录等与用户有关的信息。
userdel
可以删除用户。这个命令非常危险,将会从/etc/passwd
,/etc/shadow
,中删除用户,也会删除/home/user
用户目录。一般情况下,我们暂停某个账户可以只将账户的状态设置为不可用,例如/etc/shadow
第八个字段(账号失效日期)设置为0即可。如果确实需要删除用户,也可以用userdel -r username
,这样会先删除find / -user username
,然后再删除用户。
4.用户可以使用的一些命令
上面介绍的都是sudo
用户对账户的管理,还有一些命令普通用户就可以使用:
finger
查阅用户有关的信息chfn
change finger,修改用户的详细信息chsh
改变默认登录的shellid
可以用来查询用户的id
5.用户组的管理
在上面我们已经认识了用户和用户组,以及用户的管理。其实用户组的管理也是类似,只不过是/etc/group
与/etc/gshadow
而已。要注意的是,newgrp
是新开启一个shell,用新的环境来登录用户和用户组的。仔细想想, 这是一个很有趣的问题。正好我在写这篇文章的第三天(本文估计要写一个周),Julia写了一篇博客:How do groups work on Linux? 这篇博客正好说明了newgrp
的行为:Linux运行的进程都保存着有效组GID的属性,当进程想要通过组权限(这里略去了UID检查过程)读一个文件的时候,当看一个文件是否可以读的时候,Linux检查一下此进程的有效组里面是否有等于文件的组的,如果有那么就可以读。Julia之前误认为是:Linux检查一下此进程的用户是否可以读文件,如果不可以,就看一下用户所在的组,是否有等于文件所属的组的。——这样的话,就要每次去读/etc/passwd
了!
另外有关用户组还要知道的一个命令是gpasswd
,这个命令可以分配组管理员。组管理员可以添加或删除用户到某一个用户组。有点像论坛的版主的意思。
三、精确的权限控制ACL
我们知道,Linux的文件系统有三组权限,分别是“owner group other”,这样无法做到对同一group的成员,或对都是others的成员控制权限。所以就有了ACL(Access Control List)。ACL可以针对单一用户、单一文件或目录进行rwx的权限设置。这是一个UNIX-Like操作系统权限外的支持项目,需要文件系统的支持(mount | grep acl
)。
这里没有啥需求所以没有仔细研究,更多的资料读者可以自行搜索,推荐IBM Linux ACL 体验。
四、用户切换su, su – 和sudo
su
用来切换用户,使用方法是 su - username
, -
的意思是环境变量。比如说su - vagrant
那么会以vagrant来登录shell,所有的环境变量都会变成vagrant的。如果不加-
那么就只是id变成vagrant,进去之后如果收MAIL,还会是原来的用户的。
su - root
就可以登录root账户了!其实root可以省略,su -
就是登录root账户的意思。使用某个账户临时运行一下命令:su - root -c command
,这里的root也可以省略。注意如果root
账户没有密码的话,会出现 Authentication failure。
su是简单的切换命令。现在有一个问题,如果每个人都有用root账户权限的需求,那么就要有很多人知道root账户的密码,这很不安全,所以就有了sudo
命令。sudo可以让你用其他用户(通常是root账户)来执行命令。使用sudo的账户必须在/etc/sudoers
里面。系统验证sudo的过程如下:
- 当用户执行sudo命令时,系统先从
/etc/sudoers
文件中检查用户是否有执行权限 - 如果有,让用户输入自己的密码
- 执行sudo后面的命令
sudoers文件支持对用户组授权(以%开头)。格式如下:
1 2 |
用户账号 登陆者的来源主机名=可切换的身份 可执行的命令(绝对路径) root ALL=(ALL) ALL |
其中,可以修改最后一列为NOPASSWD:ALL
来免除每次运行sudo都需要的密码操作。(设置之后简直每天可以多好几秒呢!)
好了,基本的管理和操作到这里差不多了,上面的学习过程都是参考的鸟哥的Linux私房菜第三版(这本书讲的挺细的但是有点啰嗦,让人摸不透重点)。其余还提到了一些内容,下面就只列一下,有需要的可以去了解:
- PAM模块,对密码强度的的检查就是这个模块实现的,基本上就是个API
- 查询在线用户与登录日志: w, who, last, lastlog
- 用户之间发送消息: write, mesg, wall
- 发送mail:MAIL
- 一些用户有关的检查工具:pwck, pwconv, pwunconv, chpasswd
- 如何批量创建账号?
passwd --stdin
本文完结!(接下来是废话了)写这篇博客花了三个星期!好吧,虽然中间有各种各样别的事情来分心。之前有人在论坛上说,《鸟哥私房菜》这本书草草看了一遍但是不想再看了,又没学到什么东西。我也有差不多类似的感受,这本书好是好,但是太详细,实践又比较少,写的比较像手册(很多书都写的像手册)。学习的过程中不要怕慢,自己多试试就好了,多记笔记。感慨一下,人家制作出来的东西,我们竟然要花这么多时间去学习,差距啊。另外Linux的东西还是要扎扎实实学,多少年过去了,这些知识都没怎么变!
文件夹(folder)是一个windows概念,Linux没有文件夹概念,与之对应的是目录(directory)。
谢谢指出,已改正。不过windows的ls命令是“dir” 好像没有严格的folder的概念,linux确实是一直用directory的说法。
如果是大量主机管理的话,或许需要这种平台工具 https://xabcloud.com
看起来太复杂了,做的事情也比较杂,做了部署的事情,还有监控管理,权限管理。相比之下ansible,saltstack部署,grafana监控这种专门的工具更加专业和可靠。可以参考一下aisible这种实现。