securityContext 里这些字段到底改变了进程的什么?fsGroup 为什么能让卷里的文件有一个固定的组?默认容器有哪些 Linux 能力?runAsNonRoot 是切换用户还是检查?这篇逐个实验,把 id、能力位和文件权限都读出来。
Pod default:id → uid=0(root) gid=0(root) groups=0(root),10(wheel);emptyDir /data 的权限 → 777 root:root (uid:gid=0:0)
在 /data 里新建文件:644 0:0;进程 /proc/1/status 的 Groups:Groups: 0 10
Pod user:id → uid=1000 gid=3000 groups=2000,3000,4000,5000;emptyDir /data 的权限 → 2777 root:UNKNOWN (uid:gid=0:2000)
在 /data 里新建文件:644 1000:2000;进程 /proc/1/status 的 Groups:Groups: 2000 3000 4000 5000默认 Pod:id 是 uid=0(root),emptyDir /data 是 777 root:root。设置 runAsUser: 1000、runAsGroup: 3000、fsGroup: 2000、supplementalGroups: [4000, 5000]:id 变成 uid=1000 gid=3000 groups=2000,3000,4000,5000;/data 变成 2777 root:2000(2 是 setgid 位,组是 fsGroup);在里面新建的文件属于 1000:2000,继承了目录的组;/proc/1/status 的 Groups 是 2000 3000 4000 5000。
caps-default:CapEff=00000000a80425fb → 14 个:['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'FSETID', 'KILL', 'SETGID', 'SETUID', 'SETPCAP', 'NET_BIND_SERVICE', 'NET_RAW', 'SYS_CHROOT', 'MKNOD', 'AUDIT_WRITE', 'SETFCAP']
caps-drop:CapEff=0000000000000000 → 0 个:[]
caps-add:CapEff=00000000a80435fb → 15 个:['CHOWN', 'DAC_OVERRIDE', 'FOWNER', 'FSETID', 'KILL', 'SETGID', 'SETUID', 'SETPCAP', 'NET_BIND_SERVICE', 'NET_ADMIN', 'NET_RAW', 'SYS_CHROOT', 'MKNOD', 'AUDIT_WRITE', 'SETFCAP']
caps-priv:CapEff=000001ffffffffff → 41 个:(几乎全部,41 个里的 41 个)
default 里 chown 别人的文件:成功;drop ALL 里:chown: /tmp/x: Operation not permitted
default 里创建网卡 ip link add:ip: RTNETLINK answers: Operation not permitted;add NET_ADMIN 里:成功
privileged 里 mount tmpfs:成功;default 里:mount: permission denied (are you root?)
非 root(uid 1000)+ drop ALL,监听 80 端口:nc 退出码 143(nc 退出码 143 表示被 timeout 终止=监听成功;1 才是失败)
该节点上 net.ipv4.ip_unprivileged_port_start=0(容器运行时把它设成了 0,所以不需要 NET_BIND_SERVICE)读 /proc/1/status 的 CapEff 并解码:默认容器 14 个能力(CHOWN、DAC_OVERRIDE、FOWNER、FSETID、KILL、SETGID、SETUID、SETPCAP、NET_BIND_SERVICE、NET_RAW、SYS_CHROOT、MKNOD、AUDIT_WRITE、SETFCAP);drop: [ALL] 后是 0 个;add: [NET_ADMIN] 多出 NET_ADMIN 共 15 个;privileged: true 是全部 41 个。验证:默认里 chown 成功,drop ALL 里 Operation not permitted;默认里 ip link add 被拒,add NET_ADMIN 里成功;privileged 里能 mount tmpfs,默认里 permission denied。非 root(uid 1000)+ drop ALL 监听 80 端口也成功:节点上 net.ipv4.ip_unprivileged_port_start=0,所以不需要 NET_BIND_SERVICE。
默认:NoNewPrivs=0;allowPrivilegeEscalation=false:NoNewPrivs=1 readOnlyRootFilesystem:写 /tmp → touch: /tmp/x: Read-only file system;写挂载的卷 /data → 成功
allowPrivilegeEscalation: false 让进程的 NoNewPrivs 从 0 变成 1(setuid 程序不能再提权)。readOnlyRootFilesystem: true 之后,写 /tmp 报 Read-only file system,但挂载的卷 /data 仍可写——只读的是镜像层的根文件系统,要写的目录得挂卷。
runAsNonRoot: true,但 busybox 镜像默认是 root:phase=Pending;容器状态 CreateContainerConfigError:container has runAsNonRoot and image will run as root (pod: "nonroot_k82(3897fb6e-76ee-4c6e-a7eb-e00a6436d7d8)", contain runAsNonRoot: true + runAsUser: 1000:phase=Running;id → uid=1000 gid=0(root) groups=0(root)
runAsNonRoot: true 遇到默认 root 用户的 busybox 镜像:Pod 卡在 Pending,容器状态 CreateContainerConfigError,message 是 container has runAsNonRoot and image will run as root。它是检查而不是切换用户。再加 runAsUser: 1000 就能 Running,id 是 uid=1000 gid=0(root) groups=0(root)。