Docker Capabilities

Linux Capability

Linux 内核中的 Capabilities 特性用于划分特权集,以便进程可以只分配 “执行特定功能” 的特权。
在引入此特性前,如果进程需要使用网络,则必须使用 root 来运行,通常是 sudo 或者添加 suid,那么普通用户在使用 ping 时,ping 就可以运行任何特权。引入 Capabilities 特性后,可以通过给 ping 应用添加 CAP_NET_RAW 特权集,使其具有使用网络的特权集,而不具备其他特权集。缺省 ping 具有 cap_net_admin 和 cap_net_raw 特权集

命令setcap和getcap可以设置和查看文件的capabilities。因为文件的capabilities存储在文件的扩展属性中(xattr),目前ext2,ext3,ext4和xfs等常用文件系统都支持扩展属性。常规cp命令不会复制文件capabilities,cp -a可以支持拷贝文件的capabilities。如文件系统没有设置xattr属性那么无论getcap,getfattr是看不到文件的capabilities属性的也可以函数setxattr()和getxattr()的security.capability字段是可以设置和查看文件的capabilities。

# getcap /bin/ping
/bin/ping = cap_net_admin,cap_net_raw+p
在 Linux 中的 Capabilities 是通过 extended attributes 中的 security 命名空间实现的, selinux 也是一样

# getfattr -d -m "^security\\." /bin/ping
getfattr: Removing leading '/' from absolute path names
# file: bin/ping
security.capability=0sAAAAAgAgAAAAAAAAAAAAAAAAAAA=
security.selinux="system_u:object_r:ping_exec_t:s0"

可以通过查看进程 / proc/xxxx/status,来检查进程的特权集,并通过 capsh 来解码得到具体的特权集。

# ps -ef | grep dockerd | grep -v grep
root       1159      1  1 May26 ?        01:02:41 /usr/bin/dockerd -H fd:// --containerd=/run/containerd/containerd.sock
# cat /proc/1159/status | grep Cap
CapInh: 0000000000000000    #可以继承的CAP(i)
CapPrm: 0000003fffffffff    #可以使用的CAP(p)
CapEff: 0000003fffffffff    #使用的CAP(e)
CapBnd: 0000003fffffffff    #进程特有
CapAmb: 0000000000000000    #进程特有

可以看到权限一共分为5组, 分别是:

  1. Inheritable: 当前线程可以被继承的权限
  2. Permitted: 当前线程可被允许的权限
  3. Effective: 当前线程真正生效的权限, 内核在执行时会去根据这个权限来判断是否允许对于的操
  4. Bounding: 权限边界
  5. Ambient: 暂时未使用到,后面在添加
    补充
Capabilities 的主要思想在于分割 root 用户的特权,即将 root 的特权分割成不同的能力,每种能力代表一定的特权操作。

例如:能力CAP_SYS_MODULE表示用户能够加载 (或卸载) 内核模块的特权操作,而CAP_SETUID表示用户能够修改进程用户身份的特权操作。在 Capbilities 中系统将根据进程拥有的能力来进行特权操作的访问控制。

在Capilities中,只有进程和可执行文件才具有能力,每个进程拥有三组能力集,分别称为cap_effective, cap_inheritable, cap_permitted(分别简记为: PE,PI,PP)。

其中cap_permitted表示进程所拥有的最大能力集, cap_effective表示进程当前可用的能力集,可以看做是cap_permitted的一个子集, 而cap_inheitable则表示进程可以传递给其子进程的能力集。

系统根据进程的cap_effective能力集进行访问控制,cap_effective为cap_permitted的子集,进程可以通过取消cap_effective中的某些能力来放弃进程的一些特权。

可执行文件也拥有三组能力集,对应于进程的三组能力集,分别称为cap_effective, cap_allowed 和 cap_forced(分别简记为 FE,FI,FP), 其中cap_allowed表示程序运行时可从原进程的cap_inheritable中集成的能力集,cap_forced表示运行文件时必须拥有才能完成其服务的能力集, 而cap_effective则表示文件开始运行时可以使用的能力。


使用 capsh 可以翻译出每个 BIT 的含义,3=0011 表示 2 个 bit,f=1111 表示 4 个 bit,一共 2+4+4+4+4+4+4+4+4+4=38bit,从后先前,每个 bit 代表一种特权,一共 38 种特权集.

# capsh --decode=0000003fffffffff
0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read

docker Capability

Docker 也支持 Capabilities , 在运行容器的时候可以通过指定 --privileded 参数来开启容器的所有特权,可以通过 --cap-add 和 --cap-drop 这两个参数来调整.后台运行一个容器 busybox,通过查看进程,可以发现容器默认只有 14 种特权集相关特权级参考
补充

CAP_CHOWN: 修改文件属主的权限
CAP_DAC_OVERRIDE: 忽略文件的 DAC 访问限制
CAP_DAC_READ_SEARCH: 忽略文件读及目录搜索的 DAC 访问限制
CAP_FOWNER: 忽略文件属主 ID 必须和进程用户 ID 相匹配的限制
CAP_FSETID: 允许设置文件的 setuid 位
CAP_KILL: 允许对不属于自己的进程发送信号
CAP_SETGID: 允许改变进程的组 ID
CAP_SETUID: 允许改变进程的用户 ID
CAP_SETPCAP: 允许向其他进程转移能力以及删除其他进程的能力
CAP_LINUX_IMMUTABLE: 允许修改文件的 IMMUTABLE 和 APPEND 属性标志
CAP_NET_BIND_SERVICE: 允许绑定到小于 1024 的端口
CAP_NET_BROADCAST: 允许网络广播和多播访问
CAP_NET_ADMIN: 允许执行网络管理任务
CAP_NET_RAW: 允许使用原始套接字
CAP_IPC_LOCK: 允许锁定共享内存片段
CAP_IPC_OWNER: 忽略 IPC 所有权检查
CAP_SYS_MODULE: 允许插入和删除内核模块
CAP_SYS_RAWIO: 允许直接访问 / devport,/dev/mem,/dev/kmem 及原始块设备
CAP_SYS_CHROOT: 允许使用 chroot() 系统调用
CAP_SYS_PTRACE: 允许跟踪任何进程
CAP_SYS_PACCT: 允许执行进程的 BSD 式审计
CAP_SYS_ADMIN: 允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等
CAP_SYS_BOOT: 允许重新启动系统
CAP_SYS_NICE: 允许提升优先级及设置其他进程的优先级
CAP_SYS_RESOURCE: 忽略资源限制
CAP_SYS_TIME: 允许改变系统时钟
CAP_SYS_TTY_CONFIG: 允许配置 TTY 设备
CAP_MKNOD: 允许使用 mknod() 系统调用
CAP_LEASE: 允许修改文件锁的 FL_LEASE 标志

相关操作验证:

默认无cap_sys_nice特权功能的情况:

在默认无cap_sys_nice能里的情况下启动容器docker run --name test1 -td busybox  /bin/httpd -f

在主机侧执行ps -ef | grep httpd | grep -v grep   , 获取容器进程内pid

root     50496 50472  0 10:42 pts/0    00:00:00 /bin/httpd -f

在主机侧查看该进程所拥有的能力:$ cat /proc/50496/status|grep Cap

CapInh:	0000000000000000

CapPrm:	00000000a80425fb

CapEff:	00000000a80425fb

CapBnd:	00000000a80425fb

CapAmb:	0000000000000000



主机侧通过capsh来解码得到具体的特权集(默认情况下是14个特权)。无cap_sys_nice特权。

$ 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




进入容器内部docker exec -it test1  /bin/sh 并执行以下命令:

/ # renice -n -9 1

renice: setpriority: Permission denied



添加cap_sys_nice特权功能的情况:

通过--cap-add=cap_sys_nice添加特权并启动容器docker run  --name test2 -td --cap-add=cap_sys_nice  busybox  /bin/httpd -f

在主机侧执行ps -ef | grep httpd | grep -v grep   , 获取容器进程内pid

root     26805 26765  0 11:01 pts/0    00:00:00 /bin/httpd -f



在主机侧查看该进程所拥有的能力:cat /proc/26805/status|grep -i cap

CapInh:	0000000000000000

CapPrm:	00000000a88425fb

CapEff:	00000000a88425fb

CapBnd:	00000000a88425fb

CapAmb:	0000000000000000



主机侧通过capsh来解码得到具体的特权集。存在cap_sys_nice特权。

$ capsh --decode=00000000a88425fb   

0x00000000a88425fb=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_sys_nice,cap_mknod,cap_audit_write,cap_setfcap

进入容器内部docker exec -it test2  /bin/sh 并执行以下命令,正常执行:


/ # renice -n -9 -p 1



添加所有特权的情况下--cap-add=ALL:

通过--cap-add=ALL添加所有特权并启动容器docker run  --name test3 -td --cap-add=ALL  busybox  /bin/httpd -f

在主机侧执行ps -ef | grep httpd | grep -v grep   , 获取容器进程内pid

$  ps -ef | grep httpd | grep -v grep                               

root      1390  1365  2 13:55 pts/0    00:00:00 /bin/httpd -f



在主机侧查看该进程所拥有的能力:cat /proc/1390/status|grep -i cap

CapInh:	0000000000000000

CapPrm:	0000003fffffffff

CapEff:	0000003fffffffff

CapBnd:	0000003fffffffff

CapAmb:	0000000000000000

主机侧通过capsh来解码得到具体的特权集(38个特权)。

$ capsh --decode=0000003fffffffff                

0x0000003fffffffff=cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,cap_audit_read

进入容器内部docker exec -it test3  /bin/sh 并执行以下命令,正常执行:


/ # renice -n -9 -p 1



特权集--cap-drop和--cap-add是在基础的14种特权集的基础上先减后加的。使用--cap-drop=ALL --cap-add=cap_net_bind_service,则只有cap_net_bind_service 特权集.

通过--cap-drop=ALL删除所有特权并只添加一个特权--cap-add=cap_net_bind_service,启动容器docker run  --name test3 -td --cap-drop=ALL --cap-add=cap_net_bind_service busybox  /bin/sh

在主机侧执行 ps -ef |grep cid(容器id)  ,获取容器进程,并获取容器子进程。

$ ps -ef |grep 53920 |grep -v grep

root     53920     1  0 14:52 ?        00:00:00 /usr/bin/containerd-shimxxxxxx -address /run/containerd/containerd.sock

root     53938 53920  0 14:52 ?        00:00:00 /bin/sh

在主机侧查看该子进程所拥有的能力:cat /proc/53938/status|grep -i cap 

$ cat /proc/53938/status|grep Cap

CapInh:	0000000000000000

CapPrm:	0000000000000400

CapEff:	0000000000000400

CapBnd:	0000000000000400

CapAmb:	0000000000000000



主机侧通过capsh来解码得到具体的特权集。


$ capsh --decode=0000000000000400                                    

0x0000000000000400=cap_net_bind_service

进入容器内部docker exec -it test3  /bin/sh 并执行以下命令:

/ # renice -n -9 -p 1

renice: setpriority: Permission denied




删除cap_mknod默认特权功能的情况:

通过--cap-drop=cap_mknod添加特权并启动容器docker run  --name test4 -td --cap-add=cap_sys_nice  busybox  /bin/sh

在主机侧执行 ps -ef |grep cid(容器id)  ,获取容器进程,并获取容器子进程。

$ ps -ef |grep 63158|grep -v grep 

root     63158     1  0 16:30 ?        00:00:00 /usr/bin/containerdxxxxxx -address /run/containerd/containerd.sock

root     63179 63158  0 16:30 ?        00:00:00 /bin/sh

在主机侧查看该子进程所拥有的能力:cat /proc/63179/status|grep -i cap 

CapInh:	0000000000000000

CapPrm:	00000000a00425fb

CapEff:	00000000a00425fb

CapBnd:	00000000a00425fb

CapAmb:	0000000000000000



主机侧通过capsh来解码得到具体的特权集(默认情况下是14个特权级,现在为13个)。

$ capsh --decode=00000000a00425fb                

0x00000000a00425fb=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_audit_write,cap_setfcap

进入容器内部docker exec -it test4  /bin/sh 并执行以下命令:

/ # mknod /tmp/sda b 8 0 && echo ok

mknod: /tmp/sda: Operation not permitted
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值