Linux Capabilities是一种细粒度的权限管理机制,用于将root用户的特权划分为具体的功能集。它允许将部分root特权授予非root进程。
可以在shell中运行:
man capabilities
将显示capability man page,其中包含有关Linux功能的详细信息。
文章目录
什么是Capabilities
对于执行权限检查, 传统的UNIX实现区分两类进程: 特权进程(其有效用户ID为0,也称为超级用户或root)和非特权进程(其有效用户ID非零)。
特权进程绕过内核的所有权限检查,而非特权进程根据进程的凭证(通常为:有效用户ID、有效组ID和补充组列表)进行完整的权限检查。
从内核2.2开始,Linux将传统上与超级用户相关联的特权分成独立的单元,称为Capability,可以独立启用和禁用。
需要注意的是,功能是线程属性。
Linux Cap 分类
Linux capabilities可以分为以下几类:
文件系统相关:
- CAP_CHOWN - 改变文件所有权
- CAP_DAC_OVERRIDE - 忽略DAC权限
- CAP_DAC_READ_SEARCH - 忽略文件读/搜寻权限
- CAP_FOWNER - 忽略文件的所有权
- CAP_FSETID - 忽略setuid/setgid位
设备相关:
- CAP_MKNOD - 创建设备文件
- CAP_NET_ADMIN - 管理网络子系统
- CAP_NET_RAW - 使用RAW和底层网络协议
- CAP_SYS_MODULE - 插入和删除内核模块
- CAP_SYS_RAWIO - 执行raw I/O端口操作
进程相关:
- CAP_SETPCAP - 转移其他进程的capabilities
- CAP_SETUID - 设置UID
- CAP_SETGID - 设置GID
- CAP_SYS_ADMIN - 执行许多系统管理操作
- CAP_SYS_PTRACE - 跟踪其他进程
- CAP_SYS_CHROOT - 使用chroot限制根目录
- CAP_KILL - 向其他进程发送信号
- CAP_AUDIT_WRITE - 编写审计日志条目
系统管理:
- CAP_SYS_BOOT - 重新引导系统
- CAP_SYS_NICE - 修改进程优先级
- CAP_SYS_RESOURCE - 修改资源限制
- CAP_SYS_TIME - 修改系统时间
这只是capabilities的广义分类,某些capabilities可能属于多个类别。
基于最小特权原则,一个可执行文件可按需选择其中某些能力,而不是获取全部。
File Capabilities
自内核2.6.24起,内核支持使用setcap(8)
将功能集与可执行文件相关联。文件功能集存储在名为security.capability
的扩展属性中(请参阅setxattr(2)
)。写入此扩展属性需要CAP_SETFCAP
功能。文件功能集与线程的功能集一起确定execve(2)后线程的功能。
文件功能比传统的setuid和setgid机制更加精细和灵活。
在引入文件功能(File Capabilities)之前,setuid为0的程序会授予执行它的进程全部特权。
Cap管理工具
libcap2-bin
功能很重要,因为允许决定进程所需的功能,而不是给予它完全访问权限 - 即使它并不需要。
功能特性于1999年在2.2内核中引入,但当时仅限于进程。2008年,功能也引入到文件中。
需要安装libcap2-bin
获取和设置功能的两个基本命令是setcap
和getcap
。getcap
获取功能列表,而setcap
用于为可执行文件设置特定功能。
请注意,要使用
setcap
, 必须传递原始文件,而不是符号链接文件。Linux中的符号链接是指向另一个文件的特殊文件。
设置功能:
$ sudo setcap cap_net_bind_service+ep /path/to/the/file
获取功能:
$ sudo getcap /path/to/the/file
libcap2-bin附带了其他工具,包括capsh
和getpcaps
。
capsh
也用于获取功能,帮助解码功能集。getpcaps
在检查Linux进程的功能时很有用。
举例说明,以ping
为例。它需要打开原始套接字。只有root用户可以打开原始套接字或小于1024的端口。
我们如何为特定进程提供必要的功能? 答案是使用setcap
来为可执行文件设置特定的Linux功能。
为ping设置特定的net_raw
功能:
$ sudo setcap cap_net_raw=ep ping
总而言之,功能涉及将root特权分成不同的级别,并帮助您为每个进程提供特定的功能。
例如:
CAP_CHOWN
更改文件的所有权。它允许root随意更改文件UID和GID。CAP_KILL
杀死系统中正在运行的任何进程。CAP_NET_BIND_SERVICE
允许您打开小于1024的端口,即使进程不是以root用户运行。
libcap-ng-utils
在处理功能时,另一个非常有用的软件包名为libcap-ng-utils
,它带有netcap
、filecap
和pscap
工具。这些工具在处理Linux中的功能时非常有用。
filecap
查看可执行文件的所有功能。netcap
为通过TCP、UDP等在网络上通信的进程提供功能报告。pscap
查看正在运行的进程的功能
要安装libcap-ng-utils
, 以CentOS 7为例:
yum -y install libcap-ng-utils
Capabilities在容器中的应用
Docker
默认情况下,容器在启动时会获得容器运行环境提供的某些默认功能。像Docker这样的工具为您提供了根据需求添加和删除功能的灵活性。要理解这一点,您需要知道您的容器为正常工作所需的功能,否则将无法达到预期效果。
例如,让我们运行一个busybox容器并检查运行该进程所具有的功能。
busybox容器基于busybox镜像,是一个轻量级容器,内置许多常用的UNIX实用工具,如awk、grep和tar。
docker run --rm -it busybox sleep 1h &
要获取正在运行的容器的PID,您可以使用docker inspect <container-id>
。PID代表进程ID。它是在Linux系统上运行的每个进程的唯一数字ID。
$ docker inspect 7666636cd08c | grep -i PID
Output "Pid": 23764,
"PidMode": "",
"PidsLimit": null,
进程权限集
有五种不同类型的进程权限集。让我们理解每个权限所代表的含义:
- CapInh(Inherited capabilities)是从运行的父进程传递到其子进程的权限。
- CapPrm(Permitted capabilities)是进程允许拥有的权限。
- CapEff(Effective capabilities)集是当前进程执行的所有权限。
- CapBnd(Bounding capabilities)集是进程允许拥有的最大权限集。
- CapAmb(Ambient capabilities)集包括当前生效的权限。它可以在以后应用于当前进程或其子进程。
在本文中,将重点关注有效权限集。大部分时候,会使用有效权限。
获取与解析
要获取容器的进程权限集, 运行以下命令:
$ grep Cap /proc/<container-pid>/status
CapInh: 00000000a80425fb
CapPrm: 00000000a80425fb
CapEff: 00000000a80425fb
CapBnd: 00000000a80425fb
CapAmb: 0000000000000000
这个输出不可读,所以要读取这个输出,需要使用来自libcap2-bin
软件包的二进制文件capsh
。
此时,确保已安装libcap2-bin
软件包。要解码有效权限,获取CapEff:
之后写入的文本,并使用以下命令,应该会看到如下输出:
$ capsh --decode=00000000a80425fb
0x00000000a80425fb=cap_chown,cap_dac_override,cap_fowner,
cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,
cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_mknod,
cap_audit_write,cap_setfcap
输出显示进程具有不同的权限。例如, cap_chown权限使程序有权更改文件的所有者或目录的所有者。chown
命令使用此权限。
类似地,如果要进程打开/监听小于1024的端口,可以使用cap_net_bind_service
,它允许进程绑定到小于1024的端口。
如果有进程的PID,也可以使用getpcaps
获取进程的权限:
getpcaps 23808
运行具有某些权限的容器
现在,让我们尝试理解如何运行具有某些权限的容器。如果使用docker,可以使用--cap-add
添加权限和--cap-drop
放弃权限。例如,如果要运行有sys_admin
权限的容器并放弃其他所有权限,可以如下:
$ docker run --rm --cap-drop=all --cap-add=sys_admin \
-it busybox sleep 1h &
请注意,如果要添加或删除多个权限,必须再次添加相同的标志。
例如,如果要运行一个容器,放弃所有权限, 只使用SYS_ADMIN
和NET_ADMIN
权限,需要使用--cap-add
标志两次。
$ docker run --rm --cap-drop=all --cap-add=sys_admin \
--cap-add=net_admin -it busybox sleep 1h &
kubernetes
如何在Pod中设置正确的权限?
通过在Kubernetes清单中使用SecurityContext
,可以在容器中设置权限。让我用一个示例清单说明:
apiVersion: v1
kind: Pod
metadata:
name: pod
spec:
containers:
- command:
- sleep
- "100000"
image: ubuntu
name: ubuntu-pod
securityContext:
privileged: false
capabilities:
drop:
- ALL
add:
- SYS_ADMIN
- NET_ADMIN
上述Kubernetes清单将创建一个具有Ubuntu镜像的Pod,并且只有两个权限:SYS_ADMIN
和NET_ADMIN
。在上述清单中,我们放弃了所有其他权限。
这比运行privileged: true
的Pod要好得多,后者将添加所有Linux权限,约37个。
SYS_ADMIN
几乎相当于授予容器root级访问权限,如果不需要,应避免使用。如果查看权限的手册页,则SYS_ADMIN
也称为新的root。与SYS_ADMIN
类似,NET_ADMIN
允许您在系统上执行所有特权网络操作。
在Kubernetes中使用权限时,应该在前缀中放弃CAP这个词。
即使使用多容器Pod,也可以在每个容器中设置SecurityContext。您也可以使用工具(如tracee、inspektor-gadget和其他eBPF工具)来跟踪容器的权限。如果您不确定应用程序所需的权限,这将很有用。
文章评论