Linux 权限模型说明
一:DAC 模型
在 Linux 中,传统的权限控制模型为 DAC(Discretionary Access Control),它通过用户、组以及 rwx 权限位来决定进程是否具备访问资源的资格。
Linux 操作系统并不是通过用户名来区分用户,而是通过 UID(User ID)区分不同的用户,UID 分为两类:
- UID = 0:对应 root 用户,UID 为 0 的进程在传统 DAC 权限模型下拥有特权访问能力,可绕过大多数权限检查。
- UID ≠ 0:对应非特权用户
实际使用中,大多数 Linux 发行版会将非 0 的 UID 进一步划分为系统用户和普通用户,系统用户 和 普通用户并不会被操作系统区别对待,这样划分是为了方便管理,因为系统用户常用于运行服务进程,为了安全考虑,系统用户遵循的都是最小权限原则。
- 系统用户(1~999):用于运行服务进程
- 普通用户(≥1000):用于登录和日常操作
Linux 传统文件权限(DAC)模型将权限分为 属主(owner)、属组(group)、其他(other)三类,每类由读(r)、写(w)、执行(x) 三个权限位组成。
- 对于普通文件来说:r:读取文件内容;w:修改文件内容;x:执行文件
- 对于目录文件来说:r:查看目录列表;w:在目录中创建 / 删除文件;x:进入目录
DAC 权限判定的流程是按以下顺序进行判断:
- 判断进程是否为文件属主,若是则使用属主权限
- 若非属主,判断是否属于文件属组,若是则使用属组权限
- 否则使用 other 权限
文件权限不是给用户用的,而是给进程使用的,用户只负责进程的启动,真正去访问文件的是进程,进程和文件权限是这样关联的。
一个进程至少包含以下三种 UID:
- RUID(Real UID):记录的是这个进程是谁启动
- EUID(Effective UID):记录的是当前以谁的权限在干活(权限检查时只使用进程的 EUID 和文件的权限进行匹配)
- SUID(Saved UID):保存的曾经的有效 UID
初次创建一个文件时,文件会有一个默认的属主和属组,文件属主和属组是这样来的
- 文件属主:创建文件进程的 EUID
- 文件属组:创建进程的 EGID(若所在目录设置了特殊权限 SGID,则继承目录属组)
创建一个文件时,文件的默认权限 和 umask 值有直接的关系,umask 记录的一个三位八进制的数,普通用户的 umask 值默认是 0002,root 用户的 umask 值默认是 0022,最前面的0表示这个是一个八进制数字
- 普通文件:666 - umask ,普通文件默认不会赋予执行权限
- 目录文件:777 -umask,目录文件保证每一个组都存在可执行权限
除了 r、w、x 三个通用权限外,文件还有三个特殊权限(SUID、SGID 和 Sticky Bit)
- SUID:当这个文件被某个进程执行,则该进程的 EUID 就会变为该文件的属主。由此也可知这个权限只有在被执行的时候会生效,而且只能给非目录文件添加。
- SGID:当这个文件被某个进程执行,则该进程的EGID就会变为该文件的属组。若是给目录文件加,则在该目录下创建的文件/目录的属组都是所在目录的属组。
- Sticky Bit:只能给目录文件添加,只要是能在该目录下创建文件的用户创建的文件,就只能自己和root能删除,其他人不行。
二、LSM 模型
LSM(Linux Security Modules)是一种强制访问控制框架,它在 传统 DAC 权限检查通过之后,对进程的访问行为再进行一次安全校验。核心目的是防止某个高权限得进程被劫持或存在其他一些问题,通过限制这些进程的权限范围来降低系统整体风险。
所以 DAC 是判断有没有权限执行对应的操作,LSM 判断即使你有资格,我不允许这个操作,你还是不行,LSM 有两种主流的实现:
- SELinux:基于标签(Label)的强制访问控制机制,为进程和对象打上标签,然后通过策略规则规定什么标签的进程可以访问什么标签的对象。
- AppArmor:基于路径的强制访问控制,某个程序只能访问特定的路径,其他路径不允许。
SELinux 就是为进程和对象打上标签后,规定什么标签的进程可以访问什么标签的对象,一般在 CentOS、RedHat、麒麟 V10、欧拉 等 Linux 发行版中默认启用 SELinux。
但是 SELinux 策略复杂、学习成本较高,在一些业务场景下,为了降低维护成本,一般会选择关闭 SELinux,SELinux 三种工作模式:
-
Enforcing:严格按照策略规则进行拦截
-
Permissive:只记录日志,不实际拦截
-
Disabled:完全关闭 SELinux
AppArmor 就是会给每个程序准备一个策略文件,策略文件中定义了改进程能通过何种权限来访问哪些路径。Ubuntu、Debian 等 Linux 发型版默认内置启用的就是 AppArmor。
- AppArmor 的配置文件统一存放在:
/etc/apparmor.d/ - 配置文件的命名规则为:
进程的可执行文件路径,将 / 替换为 .,并去掉根路径
例如:启动mysql服务的二进制文件 mysqld 的路径为 /usr/sbin/mysqld,对应的配置文件是:/etc/apparmor.d/usr.sbin.mysqld
三:最小权限
运行某个服务的时候,只给服务进程完成职责所必需的最小权限集合,任何多余的能力都不应该存在。
以 root 用户启动,以专有服务用户运行的原因:
因为 Linux 规定了服务要绑定某些知名端口,就需要这个服务进程的 EUID 是 root (UID 为 0)才行,还有就是服务启动的时候需要初始化相关系统级资源,如:创建 socket 文件、访问设备文件、初始化共享内存这些操作,只有 root 用户来才行,所以就需要先以 root 用户的身份来将相关准备工作给做好。
准备工作做好以后,如果这个服务进程一直让 root 来运行就很危险,假设谁把这个 root 进程控制了,那么就能以root权限来做一些操作导致造成风险。
如果是使用只有特定权限的系统用户,那么即使被控制了也只会造成局部的变化,不会让整个系统崩掉。
所以启动一个服务一般是这样的:
- 以 root 用户身份来启动一个服务,则该服务进程的 EUID 为 0,具备root权限,此时会完成相关的初始化操作。
- 该进程会 fork 一个子进程,然后设置该子进程的 EUID 为特定系统用户,这样后续就由这个子进程来提供服务。
fork 出特定系统用户运行的子进程后,root 启动的这个进程不一定都要退出,因为有些 特权操作 不是只在启动阶段发生,所以运行期仍然需要 root,但是这些 root 服务进程在设计的时候是限制了权限的,所以即使被控制了也不会造成太大的影响。
例如:NGINX 服务,它 master 进程是以 root 身份运行的,worker 进程是以 nginx 用户运行的。
数据/配置/日志 文件的权限如何进行设计:
配置文件防篡改,数据目录防越权,日志目录便于审计
- 配置文件:通常由 root 作为属主,防止服务进程修改配置;服务进程只需要读取配置文件,不应具备写权限。防止服务被入侵后篡改自身配置。
- 数据目录:数据目录应只允许服务用户读写,其他用户无访问权限,防止数据被误删或篡改。
- 日志目录:允许服务用户写入,允许特定运维组或审计用户读取,不对所有普通用户开放。
服务运行时 Permission denied 的排查思路:
1、确认服务运行用户是谁,先搞清楚到底是哪个用户在访问这个文件
2、检查 DAC 权限,检查文件/目录是否存在,是否具有特定权限
3、检查是否被 LSM 拦截,查看系统的 SELinux、AppArmor相关配置。
4、查看对应目录是否是只读挂载,检查 systemd 或挂载参数等额外安全机制是否进一步限制了服务行为。
浙公网安备 33010602011771号