美文网首页365日更挑战
Linux CAP介绍与k8s下配置使用

Linux CAP介绍与k8s下配置使用

作者: 微凉哇 | 来源:发表于2021-11-01 09:58 被阅读0次

    关于capability

    发音

    美[keɪpəˈbɪləti] 英[keɪpə'bɪləti]
    

    译为能力功能,一般缩写CAP,以下我们简称CapabilitiesCAP

    CAP历史回溯

    从内核2.2开始,Linux将传统上与超级用户root关联的特权划分为不同的单元,称为CAP

    CAP作为线程(Linux并不真正区分进程和线程)的属性存在,每个单元可以独立启用和禁用。
    如此一来,权限检查的过程就变成了:
    在执行特权操作时,如果进程的有效身份不是root,就去检查是否具有该特权操作所对应的CAP,并以此决定是否可以进行该特权操作。

    比如要向进程发送信号(kill()),就得具有CAP_KILL;如果设置系统时间,就得具有CAP_SYS_TIME

    CAP出现之前,系统进程分为两种:

    • 特权进程
    • 非特权进程

    特权进程可以做所有的事情: 进行管理级别的内核调用;而非特权进程被限制为标准用户的子集调用

    某些可执行文件需要由标准用户运行,但也需要进行有特权的内核调用,它们需要设置suid位,从而有效地授予它们特权访问权限。(典型的例子是ping,它被授予进行ICMP调用的完全特权访问权。)

    这些可执行文件是黑客关注的主要目标——如果他们可以利用其中的漏洞,他们就可以在系统上升级他们的特权级别。
    由此内核开发人员提出了一个更微妙的解决方案:CAP

    意图很简单: 将所有可能的特权内核调用划分为相关功能组,赋予进程所需要的功能子集。
    因此,内核调用被划分为几十个不同的类别,在很大程度上是成功的。

    回到ping的例子,CAP的出现使得它仅被赋予一个CAP_NET_RAW功能,就能实现所需功能,这大大降低了安全风险。

    注意: 比较老的操作系统上,会通过为ping添加SUID权限的方式,实现普通用户可使用。
    这存在很大的安全隐患,笔者所用操作系统(CentOS7)上ping指令已通过CAP方式实现

    $ ls -l /usr/bin/ping
    -rwxr-xr-x. 1 root root 66176 8月   4 2017 /usr/bin/ping
    $ getcap /usr/bin/ping
    /usr/bin/ping = cap_net_admin,cap_net_raw+p
    

    设置容器的CAP

    Set capabilities for a Container

    基于Linux capabilities ,您可以授予某个进程某些特权,而不授予root用户的所有特权。

    要为容器添加或删除Linux功能,请在容器清单的securityContext部分中包含capability字段。

    首先,看看未设置capability字段时会发生什么。下面是不添加或删除任何CAP的配置文件:

    apiVersion: v1
    kind: Pod
    metadata:
      name: security-context-demo-3
    spec:
      containers:
      - name: sec-ctx-3
        image: centos:7
        command: ["tail","-f", "/dev/null"]
    
    1. 创建Pod
    $ kubectl apply -f https://k8s.io/examples/pods/security/security-context-3.yaml
    
    1. 查看Pod运行状态
    $ kubectl get pod security-context-demo-3
    
    1. 在运行的容器中获取一个shell:
    kubectl exec -it security-context-demo-3 -- sh
    
    1. shell中,列出正在运行的进程:
    $ ps aux
    

    输出显示了容器的进程id (pid):

    USER  PID %CPU %MEM    VSZ   RSS TTY   STAT START   TIME COMMAND
    root    1  0.0  0.0   4336   796 ?     Ss   18:17   0:00 /bin/sh -c node server.js
    root    5  0.1  0.5 772124 22700 ?     Sl   18:17   0:00 node server.js
    
    1. shell中,查看进程1的状态:
    $ cd /proc/1
    $ cat status
    

    输出显示了进程的能力位图:

    ...
    CapPrm: 00000000a80425fb
    CapEff: 00000000a80425fb
    ...
    

    解码

    $ 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
    
    1. 记下能力位图,然后退出shell:
    $ exit
    

    接下来,运行一个与前一个容器相同的容器,只是它有额外的功能集。

    1. 运行一个配置增加了CAP_NET_ADMINCAP_SYS_TIME功能的Pod:
    cat <<EOF kubectl apply -f -
    apiVersion: v1
    kind: Pod
    metadata:
      name: security-context-demo-4
    spec:
      containers:
      - name: sec-ctx-4
        image: centos:7
        command: ["tail","-f", "/dev/null"]
        securityContext:
          capabilities:
            add: ["NET_ADMIN", "SYS_TIME"]
    EOF
    
    1. 在运行的容器中获取一个shell:
    kubectl exec -it security-context-demo-4 -- sh
    
    1. shell中,查看进程1的状态:
    $ cd /proc/1
    $ cat status
    

    进程的能力位图:

    ...
    CapPrm: 00000000aa0435fb
    CapEff: 00000000aa0435fb
    ...
    

    进程的能力位图值解码

    $ capsh --decode=00000000aa0435fb
    0x00000000aa0435fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_audit_write,cap_setfcap
    
    1. 对比两个进程的能力位图(解码后)
    # 未配置CAP
    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_NET_ADMIN和CAP_SYS_TIME
    0x00000000aa0435fb=cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_admin,cap_net_raw,cap_sys_chroot,cap_sys_time,cap_mknod,cap_audit_write,cap_setfcap
    

    有关常capability数的定义,请参阅capability.h

    注意: Linux capability常量的形式是CAP_XXX
    但是,当您在容器清单中列出功能时,必须忽略常量的CAP_部分。
    例如,要添加CAP_SYS_TIME,请在功能列表中包含SYS_TIME

    关于进程状态值

    这里我们介绍进程状态中与Capabilities相关的几个值:

    • CapInh: 当前进程子进程可继承的能力
    • CapPrm: 当前进程可使用的能力(可以包含CapEff中没有的能力,CapEffCapPrm的一个子集,进程放弃没有必要的能力有利于提高安全性)
    • CapEff: 当前进程已使用/开启的能力

    1.非容器特权进程CAP缺省值解析(共计35个)

    $ capsh --decode=000001ffffffffff
    0x000001ffffffffff=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,35,36,37,38,39,40
    
    1. cap_chown: 允许修改文件所有者权限
    2. cap_dac_override: 忽略对文件的DAC访问权限控制
    3. cap_dac_read_search: 忽略文件读及目录检索的DAC访问权限
    4. cap_fowner: 忽略文件属主ID必须与进程用户ID一致的权限
    5. cap_fsetid: 修改文件时保留setuid/setgid位的权限
    6. cap_kill: 允许对不属于自己的进程发送信号的权限
    7. cap_setgid: 允许普通用户使用setgid函数
    8. cap_setuid: 允许普通用户使用setuid函数
    9. cap_setpcap: 允许对子进程进行CAP授权
    10. cap_linux_immutable: 允许修改文件的IMMUTABLEAPPEND属性权限
    11. cap_net_bind_service: 允许绑定小于1024端口的权限
    12. cap_net_broadcast: 允许网络广播及多播访问的权限
    13. cap_net_admin: 允许执行网络管理任务的权限
    14. cap_net_raw: 允许使用原始套接字的权限
    15. cap_ipc_lock: 允许锁定共享内存片段的权限
    16. cap_ipc_owner: 忽略IPC所有权检查的权限
    17. cap_sys_module: 允许插入和删除内核模块的权限
    18. cap_sys_rawio: 允许直接访问/devport,/dev/mem,/dev/kmem及原始块设备的权限
    19. cap_sys_chroot: 允许使用chroot()系统调用的权限
    20. cap_sys_ptrace: 允许追踪任何进程的权限
    21. cap_sys_pacct: 允许执行进程的BSD式审计的权限
    22. cap_sys_admin: 允许执行系统管理任务(如加载或卸载文件系统、设置磁盘配额等)的权限
    23. cap_sys_boot: 允许重启系统的权限
    24. cap_sys_nice: 允许提升优先级及设置其他进程优先级的权限
    25. cap_sys_resource: 忽略资源限制的权限
    26. cap_sys_time: 允许改变系统时钟的权限
    27. cap_sys_tty_config: 允许配置TTY设备的权限
    28. cap_mknod: 允许使用mknod()系统调用的权限
    29. cap_lease: 允许修改文件锁的FL_LEASE标志的权限
    30. cap_audit_write: 允许将记录写入内核审计日志的权限
    31. cap_audit_control: 启用和禁用内核审计、改变审计过滤规则、检索审计状态和过滤规则的权限
    32. cap_setfcap: 允许为可执行文件设置CAP的权限
    33. cap_mac_override: 可覆盖Mandatory Access Control(MAC)的权限
    34. cap_mac_admin: 允许MAC配置或状态改变的权限
    35. cap_syslog: 允许使用syslog()系统调用的权限

    2.容器特权进程默认CAP缺省值解析(共计14个)

    借用上述例子中未配置CAP的进程能力位图

    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
    
    1. cap_chown: 允许修改文件所有者权限
    2. cap_dac_override: 忽略文件的DAC访问权限
    3. cap_fowner: 忽略文件属主ID必须与进程用户ID一致的权限
    4. cap_fsetid: 允许设置文件setuid位的权限
    5. cap_kill: 允许对不属于自己的进程发送信号的权限
    6. cap_setgid: 允许修改进程的GID权限
    7. cap_setuid: 允许修改进程的UID权限
    8. cap_setpcap: 允许对子进程进行CAP授权
    9. cap_net_bind_service: 允许绑定小于1024端口的权限
    10. cap_net_raw: 允许使用原始套接字的权限
    11. cap_sys_chroot: 允许使用chroot()系统调用的权限
    12. cap_mknod: 允许使用mknod()系统调用的权限
    13. cap_audit_write: 允许将记录写入内核审计日志的权限
    14. cap_setfcap: 允许为可执行文件设置CAP的权限

    对比发现,容器运行时内的root用户并非拥有全部权限,仅仅是默认拥有14条权限,其他权限如果使用需要额外开启。

    3.查看容器非特权进程默认CAP缺省值(0个)

    $ id
    uid=1000 gid=0(root) groups=0(root)
    $ cat /proc/1/status|grep CapEff
    CapEff: 0000000000000000
    

    思考一个问题: 当运行时为非特权用户,CAP配置是否生效?

    1. Deployment配置如下(镜像以非特权USER运行)
    kind: Deployment
    apiVersion: apps/v1
    metadata:
      name: eureka-app
      namespace: champ
      labels:
        app: eureka-app
        app.kubernetes.io/instance: eureka-app
      annotations:
        configmap.reloader.stakater.com/reload: eureka-app-cm
        deployment.kubernetes.io/revision: '25'
    spec:
      replicas: 1
      selector:
        matchLabels:
          app: eureka-app
      template:
        metadata:
          labels:
            app: eureka-app
          annotations:
            kubesphere.io/containerSecrets: ''
        spec:
          containers:
            - name: eureka-app
              image: 'xxx.xxx.xxx/xxx/xxx:xxx'
              ports:
                - name: http-8080
                  containerPort: 8080
                  protocol: TCP
                - name: http-5005
                  containerPort: 5005
                  protocol: TCP
              securityContext:
                capabilities:
                  add:
                    - SYS_TIME
    ...
    
    1. 查看进程状态
    $ cat /proc/1/status
    CapPrm: 0000000000000000
    CapEff: 0000000000000000
    

    显然当镜像指定USER为非特权用户运行时,CAP配置并不生效

    结论

    1. 当镜像指定USER为非特权用户运行时,CAP配置并不生效
    2. 容器内特权进程默认拥有14CAP权限配置,相对非容器特权进程要少的多
    3. Linux CAP旨在将特权细粒度划分

    参考文献

    Linux Capabilities 简介
    Linux Capabilities: Why They Exist and How They Work

    相关文章

      网友评论

        本文标题:Linux CAP介绍与k8s下配置使用

        本文链接:https://www.haomeiwen.com/subject/vtlzaltx.html