容器的安全模型是纵深防御,Namespace 提供第一层隔离,Capabilities 限制特权操作,seccomp 过滤系统调用,AppArmor 控制文件访问。这四层防护叠加在一起,构成了容器的安全边界。
但这个边界并非无懈可击。特权容器可以访问宿主内核的所有系统调用,内核漏洞可以突破 Namespace 隔离,配置不当的 seccomp 规则形同虚设。理解每一层安全机制的原理和局限,是构建安全容器的基础。
容器安全的历史是一部”事故驱动”的演进史。容器早期默认以 root 身份运行,Capabilities 几乎不做限制,seccomp 和 AppArmor 更是无人问津。2015 到 2016 年间,keyctl、add_key 等内核密钥环漏洞接连被用来从容器提权逃逸,Docker 在 1.11(2016 年)把 seccomp 从”可选”变为默认启用,就是对这些内核攻击面的直接回应。此后逃逸事件仍在继续:2019 年的 CVE-2019-5736 允许攻击者通过 /proc/self/exe 符号链接覆盖宿主机上的 runc 二进制文件实现容器逃逸,它推动的不是 seccomp,而是 runc 自身的加载机制改造(改用 memfd_create 加载自身)以及 noNewPrivileges 的普及;2021 年的 CVE-2021-22555 则是内核 netfilter 提权逃逸,再次提醒共享内核始终是容器隔离的最大缺口。每一次逃逸事件都推动了特定安全机制的加固:Capabilities 从”全部授予”变为”最小子集”,rootless 容器从”实验性”变为”生产可用”。容器安全配置之所以复杂,是因为每一个限制都是对真实攻击的回应,而且对应关系要落到具体机制上,不能笼统归因。
前置知识
Ch02 Linux Namespace 深入:Namespace 是容器安全的第一层防线,理解 Namespace 的隔离边界是理解安全加固的前提
Ch03 Cgroup v2 深入:Cgroup 是资源限制的第二层防线,防止容器耗尽宿主资源
Linux 安全模块基础:DAC(自主访问控制)、MAC(强制访问控制)、Capabilities 机制
本章讨论的安全机制基于当前最佳实践,新的 CVE 和防御手段会不断出现。
一、容器安全模型
1.1 纵深防御层级
先说清一个常见的误区:容器之所以不靠 chroot 做根隔离。chroot 只改了进程看到的根目录,对 root 用户几乎不构成约束。一个在 chroot 环境里的 root 进程,可以靠 mknod 创建内存块设备直接读写宿主磁盘、靠 ptrace 附加到 chroot 外的宿主进程、或者通过重新挂载 /proc 访问宿主文件系统,这三条逃逸路径在 Ch01 容器全景 里有过交代。正因如此,容器改用 mount Namespace 配合 pivot_root 切换根文件系统,再叠加下面几层把 root 的能力收窄,才形成可用边界。chroot 在容器里更多作为 pivot_root 之后的补充手段,而不是独立的安全机制。
另一处容易漏的盲区是 /dev/shm。容器默认有独立的 /dev/shm(tmpfs),但如果用 --ipc=host 或手动把宿主的 /dev/shm 挂进容器,两个容器就能通过共享内存文件互相读写,IPC Namespace 的隔离就此失效。runc 为每个容器挂载独立 tmpfs 就是为了堵这个口子,机制详见 Ch02 Namespace 深入。
1.2 容器 vs 虚拟机的安全边界
容器共享宿主内核,这是它与虚拟机安全模型的根本差异。容器与虚拟机的整体对比详见 Ch01 容器全景,这里只关注安全维度:
| 安全维度 | 容器 | 虚拟机 |
|---|---|---|
| 内核漏洞影响 | 影响所有容器 | 只影响一个 VM |
| 攻击面 | 系统调用接口 | 虚拟硬件接口 |
| 逃逸难度 | 较低(内核漏洞) | 较高(需突破 VMM) |
| 安全模块 | seccomp/AppArmor/SELinux | 硬件虚拟化扩展 |
容器共享宿主内核意味着:一个内核漏洞可能导致所有容器被逃逸,这也是容器隔离弱于虚拟机的根本原因。
二、Linux Capabilities
2.1 从 root 到 Capabilities
传统 UNIX 模型只有 root 和非 root 两种权限,过于粗粒度。Linux Capabilities 将 root 权限拆分为 40+ 个细粒度能力:
# 查看所有 Capabilitiescapsh --print
# 查看当前进程的 Capabilitiescat /proc/self/status | grep Cap# CapInh: 0000000000000000# CapPrm: 0000003fffffffff# CapEff: 0000003fffffffff# CapBnd: 0000003fffffffff# CapAmb: 0000000000000000
# 解码 Capabilitiespython3 -c "caps = 0x3ffffffffffor i in range(40): if caps & (1 << i): print(f'CAP_{i}')"2.2 容器相关的 Capabilities
| Capability | 功能 | 容器默认 | 风险等级 |
|---|---|---|---|
| CAP_AUDIT_WRITE | 写审计日志 | 是 | 低 |
| CAP_KILL | 发送信号 | 是 | 低 |
| CAP_NET_BIND_SERVICE | 绑定特权端口 | 是 | 低 |
| CAP_CHOWN | 修改文件所有者 | 是 | 中 |
| CAP_DAC_OVERRIDE | 绕过文件权限检查 | 是 | 中 |
| CAP_FOWNER | 绕过文件所有者检查 | 是 | 中 |
| CAP_SETFCAP | 设置文件 Capabilities | 否 | 高 |
| CAP_SYS_ADMIN | 系统管理操作 | 否 | 极高 |
| CAP_SYS_PTRACE | 追踪进程 | 否 | 极高 |
| CAP_NET_ADMIN | 网络管理 | 否 | 高 |
| CAP_SYS_MODULE | 加载内核模块 | 否 | 极高 |
2.3 Docker 的默认 Capabilities
# 查看 Docker 容器的默认 Capabilitiesdocker run --rm alpine capsh --print | grep "Current:"
# Docker 默认授予的 Capabilities:# CAP_AUDIT_WRITE, CAP_CHOWN, CAP_DAC_OVERRIDE,# CAP_FOWNER, CAP_FSETID, CAP_KILL,# CAP_MKNOD, CAP_NET_BIND_SERVICE, CAP_NET_RAW,# CAP_SETGID, CAP_SETUID, CAP_SETFCAP,# CAP_SETPCAP, CAP_SYS_CHROOT
# 添加/删除 Capabilitiesdocker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginxdocker run --cap-add=SYS_ADMIN alpine # 危险!2.4 Capability Sets 及其关系
每个进程有五组 Capability 集合,它们共同决定进程实际能执行哪些特权操作:
| 集合 | 含义 | 限制作用 |
|---|---|---|
| Bounding(边界集) | 进程可获得 Capability 的上限 | 任何 Capability 一旦从 Bounding set 移除,就无法再被加入任何集合 |
| Permitted(许可集) | 进程可以使用的 Capability | Effective 和 Ambient 的子集上限 |
| Effective(生效集) | 进程当前正在使用的 Capability | 内核检查权限时看的就是这个集合 |
| Inheritable(可继承集) | exec 后可以保留的 Capability | 决定新程序能否继承这些 Capability |
| Ambient(环境集) | exec 后自动生效的 Capability(Linux 4.3+) | 非 root 进程通过 exec 执行新程序时,Ambient 中的 Capability 自动加入新进程的 Permitted 和 Effective |
Bounding set 是单向门:只能从中移除 Capability,不能添加。一旦某个 Capability 从 Bounding set 中被 drop,该进程及其所有子进程都永远无法重新获得它。这是 Capability 机制的安全基石。
Ambient set 解决了一个长期痛点:非 root 进程 exec 新程序后,即使文件有 file capability,如果 Inheritable 为空,Capability 也会丢失。Ambient 让非 root 进程也能跨 exec 保留 Capability,这对 rootless 容器至关重要。
runc 在启动容器时的 Capability 设置流程:
- 在容器进程 fork 之后、exec 之前,通过
prctl(PR_CAPBSET_DROP, cap_value)逐个将不需要的 Capability 从 Bounding set 移除。第二个参数cap_value是 Capability 的数值编号(如CAP_SYS_ADMIN为 21) - 通过
capset()系统调用设置 Permitted、Effective、Inheritable 三个集合,它们的值都不能超过 Bounding set - 通过
prctl(PR_CAP_AMBIENT, PR_CAP_AMBIENT_RAISE, cap_value)逐个设置 Ambient 集合 - exec 执行容器入口程序后,内核根据文件的 file capability 和进程的 Inheritable/Ambient 集合,重新计算新进程的 Permitted 和 Effective set
# 手动操作 Capability 集合的示例(使用 libcap 的 capsh 命令)
# 查看当前进程的五个集合cat /proc/self/status | grep Cap# CapInh: 0000000000000000 ← Inheritable# CapPrm: 0000003fffffffff ← Permitted# CapEff: 0000003fffffffff ← Effective# CapBnd: 0000003fffffffff ← Bounding# CapAmb: 0000000000000000 ← Ambient
# 从 Bounding set 移除 CAP_SYS_ADMIN(capability number 21)# 移除后无法恢复capsh --drop=cap_sys_admin -- -c "cat /proc/self/status | grep CapBnd"# CapBnd: 0000003fffdfffff ← 第 21 位变为 0
# 同时设置 Permitted 和 Effective# capsh 会先 drop Bounding,再 capset Permitted/Effective/Inheritablecapsh --drop=cap_sys_admin --caps="cap_net_bind_service+ep" -- -c "./my-server"# +ep 表示添加到 Effective 和 Permittedcapsh --drop 操作的是 Bounding set,是单向的。--caps 操作的是 Permitted/Effective/Inheritable,受 Bounding set 限制。如果 Bounding set 中没有某个 Capability,--caps 也无法添加它。
三、seccomp
3.1 seccomp 原理
seccomp(Secure Computing Mode)限制进程可以调用的系统调用。它使用 BPF(Berkeley Packet Filter)程序在内核层面过滤系统调用:
3.2 Docker 的默认 seccomp 配置
Docker 默认使用 seccomp 配置文件,禁止约 44 个危险系统调用:
{ "defaultAction": "SCMP_ACT_ERRNO", "architectures": ["SCMP_ARCH_X86_64"], "syscalls": [ { "names": ["accept", "access", "arch_prctl", "bind", "brk", ...], "action": "SCMP_ACT_ALLOW" }, { "names": ["keyctl", "add_key", "request_key"], "action": "SCMP_ACT_ERRNO" }, { "names": ["mount"], "action": "SCMP_ACT_ERRNO", "args": [] } ]}3.3 被默认 seccomp 禁止的系统调用
| 系统调用 | 原因 | 风险 |
|---|---|---|
keyctl | 内核密钥环操作 | 内核漏洞利用 |
add_key | 添加密钥 | 内核漏洞利用 |
request_key | 请求密钥 | 内核漏洞利用 |
mount | 挂载文件系统 | 文件系统逃逸 |
umount2 | 卸载文件系统 | 文件系统逃逸 |
pivot_root | 切换根目录 | 文件系统逃逸 |
bpf | 加载 BPF 程序 | 内核代码执行 |
perf_event_open | 性能监控 | 信息泄露 |
kcmp | 比较进程资源 | 信息泄露 |
userfaultfd | 用户态页错误处理 | 内核漏洞利用 |
3.4 自定义 seccomp 配置
# 使用自定义 seccomp 配置docker run --security-opt seccomp=/path/to/seccomp.json nginx
# 禁用 seccomp(危险!)docker run --security-opt seccomp=unconfined nginx
# 使用 Docker 默认 seccomp 配置作为模板wget https://raw.githubusercontent.com/moby/moby/master/profiles/seccomp/default.json3.5 用 seccomp-tools 分析
# 安装 seccomp-toolsgem install seccomp-tools
# 分析容器的系统调用seccomp-tools dump -c "docker run alpine ls" | head -30
# 追踪特定系统调用seccomp-tools trace -c "docker run alpine cat /etc/passwd"四、AppArmor
4.1 AppArmor 原理
AppArmor 是 Linux 的强制访问控制(MAC)系统,基于路径定义文件访问规则:
# 查看 AppArmor 状态sudo aa-status
# 查看容器使用的 AppArmor 配置docker inspect mycontainer --format '{{.AppArmorProfile}}'
# Docker 默认使用 docker-default 配置4.2 Docker 的默认 AppArmor 配置
# 查看 docker-default 配置sudo cat /etc/apparmor.d/docker-default
# 关键规则(简化):# deny /sys/[^f]/** wklx, # 禁止写 /sys(除 /sys/fs)# deny /sys/f[^s]/** wklx, # 禁止写 /sys/f(除 /sys/fs/cgroup)# deny /sys/fs/[^c]/** wklx, # 禁止写 /sys/fs(除 /sys/fs/cgroup)# owner /** rw, # 允许读写自己拥有的文件# /proc/** r, # 允许读 /proc# /dev/** rw, # 允许读写 /dev4.3 自定义 AppArmor 配置
# 创建自定义 AppArmor 配置sudo cat > /etc/apparmor.d/mycontainer << 'EOF'#include <tunables/global>
profile mycontainer flags=(attach_disconnected,mediate_deleted) { #include <abstractions/base>
# 允许读 /etc /etc/** r,
# 允许写 /tmp /tmp/** rw,
# 禁止读 /etc/shadow deny /etc/shadow r,
# 允许网络连接 network inet tcp, network inet udp,
# 允许信号 signal (receive) peer=/usr/bin/docker,}EOF
# 加载配置sudo apparmor_parser -r /etc/apparmor.d/mycontainer
# 使用自定义配置docker run --security-opt apparmor=mycontainer nginx五、Rootless 容器
5.1 Rootless 容器原理
Rootless 容器利用 User Namespace 将容器内的 root 映射到宿主机的普通用户,无需 root 权限即可运行容器:
5.2 Podman 的 Rootless 模式
# Podman 天然支持 rootlesspodman run -d nginx
# 底层原理:# 1. 创建 User Namespace# 2. 配置 UID 映射:0 → 100000, 1 → 100001, ...# 3. 在 User Namespace 内创建其他 Namespace# 4. 使用 fuse-overlayfs 替代 OverlayFS(无需 root)# 5. 使用 slirp4netns 或 pasta 替代 veth pair(无需 root)5.3 Docker 的 Rootless 模式
# 安装 Docker rootless 模式dockerd-rootless-setuptool.sh install
# 运行 rootless 容器docker run -d nginx
# 限制:# - 不能绑定特权端口(< 1024)# - 网络性能较低(slirp4netns)# - 不能使用 AppArmor# - 不能修改 sysctl 参数5.4 Rootless 容器的技术栈
| 组件 | 传统容器 | Rootless 容器 |
|---|---|---|
| 运行时 | runc | runc (rootless mode) |
| 文件系统 | OverlayFS | fuse-overlayfs |
| 网络 | veth + bridge | slirp4netns / pasta |
| Cgroup | Cgroup v2 (root) | Cgroup v2 (delegation) |
| UID 映射 | 无 | User Namespace |
六、安全基线与最佳实践
6.1 容器安全检查清单
| 检查项 | 安全配置 | 风险等级 |
|---|---|---|
| 特权容器 | 不使用 —privileged | 极高 |
| Capabilities | —cap-drop=ALL + 按需添加 | 高 |
| seccomp | 使用默认或自定义配置 | 高 |
| AppArmor | 使用默认或自定义配置 | 中 |
| 只读文件系统 | —read-only | 中 |
| PID 限制 | —pids-limit=100 | 中 |
| 内存限制 | —memory=512m | 中 |
| User Namespace | rootless 模式 | 高 |
| 镜像签名 | Docker Content Trust | 中 |
| 镜像扫描 | Trivy/Snyk/Grype | 中 |
清单里”不使用 --privileged”排在极高,值得说清它到底关掉了什么。--privileged 一次性做了四件事:赋予全部 Capabilities、禁用 seccomp、禁用 AppArmor、把宿主所有设备挂进容器。等于把前面几层防护全部拆掉,容器进程对宿主内核几乎和真 root 一样。验证很简单,对比一下就看得见差距:
# 普通容器的 capability 集(被裁剪)docker run --rm alpine capsh --print# 特权容器的 capability 集(全部恢复)docker run --rm --privileged alpine capsh --print和 --privileged 并列的高危操作是挂载 docker.sock。把宿主的 /var/run/docker.sock 挂进容器,等于把宿主 root 交了出去:容器进程通过这个 socket 调 Docker API,可以再起一个 --privileged 容器并把宿主根文件系统挂进去,逃逸就完成了。这条路径不靠任何内核漏洞,纯粹是配置失误,所以 CI 构建、监控类容器一旦需要访问 Docker,都该换成受限的 socket 代理或 rootless 方案,而不是直接挂 socket。
# Kubernetes Pod 安全上下文apiVersion: v1kind: Podspec: securityContext: runAsNonRoot: true runAsUser: 1000 fsGroup: 2000 seccompProfile: type: RuntimeDefault containers: - name: nginx securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true capabilities: drop: ["ALL"] add: ["NET_BIND_SERVICE"] resources: limits: memory: "512Mi" cpu: "1"YAML 里的 allowPrivilegeEscalation: false 对应 OCI 配置里的 noNewPrivileges,它堵的是 setuid 这条路。即使容器 drop 了所有 Capabilities,只要容器里有 setuid 的二进制(比如 su、newgrp),进程 exec 它之后就会拿到完整 root,之前的 capability 裁剪全部作废。noNewPrivileges 通过 prctl(PR_SET_NO_NEW_PRIVS, 1) 让 exec 后不再因 setuid bit 提权,把 capability 模型补成闭环。机制细节在 Ch05 OCI 规范 的 config.json 安全字段里展开过。
6.3 容器安全扫描
# 使用 Trivy 扫描镜像漏洞trivy image nginx:latest
# 输出示例:# nginx:latest (debian 12.4)# ===========================# Total: 42 (UNKNOWN: 0, LOW: 15, MEDIUM: 20, HIGH: 6, CRITICAL: 1)# ┌──────────────┬────────────┬──────────┬───────────────────┐# │ Library │ Vulnerability│ Severity │ Installed Version │# ├──────────────┼────────────┼──────────┼───────────────────┤# │ libc-bin │ CVE-2021-3042│ CRITICAL │ 2.34-9 │# │ libssl3 │ CVE-2020-1356│ HIGH │ 1.1.1 │# └──────────────┴────────────┴──────────┴───────────────────┘七、动手实践
7.1 容器安全审计脚本
#!/bin/bash# 容器安全审计脚本
CONTAINER=$1
echo "=== 容器安全审计: $CONTAINER ==="
echo ""echo "1. 特权模式检查"PRIVILEGED=$(docker inspect -f '{{.HostConfig.Privileged}}' $CONTAINER)if [ "$PRIVILEGED" = "true" ]; then echo " 容器运行在特权模式!"else echo " 容器未运行在特权模式"fi
echo ""echo "2. Capabilities 检查"CAPS=$(docker inspect -f '{{.HostConfig.CapAdd}}' $CONTAINER)echo " 添加的 Capabilities: $CAPS"if echo "$CAPS" | grep -q "SYS_ADMIN"; then echo " CAP_SYS_ADMIN 已添加,风险极高"fi
echo ""echo "3. seccomp 检查"SECCOMP=$(docker inspect -f '{{.HostConfig.SecurityOpt}}' $CONTAINER)if echo "$SECCOMP" | grep -q "unconfined"; then echo " seccomp 已禁用!"else echo " seccomp 已启用"fi
echo ""echo "4. AppArmor 检查"APPARMOR=$(docker inspect -f '{{.AppArmorProfile}}' $CONTAINER)if [ "$APPARMOR" = "" ] || [ "$APPARMOR" = "unconfined" ]; then echo " AppArmor 未配置"else echo " AppArmor: $APPARMOR"fi
echo ""echo "5. 资源限制检查"MEM=$(docker inspect -f '{{.HostConfig.Memory}}' $CONTAINER)CPU=$(docker inspect -f '{{.HostConfig.NanoCpus}}' $CONTAINER)PIDS=$(docker inspect -f '{{.HostConfig.PidsLimit}}' $CONTAINER)echo " 内存限制: $MEM"echo " CPU 限制: $CPU"echo " PID 限制: $PIDS"
echo ""echo "6. 只读文件系统检查"RO=$(docker inspect -f '{{.HostConfig.ReadonlyRootfs}}' $CONTAINER)if [ "$RO" = "true" ]; then echo " 根文件系统为只读"else echo " 根文件系统可写"fi
echo ""echo "7. 挂载检查"MOUNTS=$(docker inspect -f '{{.Mounts}}' $CONTAINER)echo " 挂载点: $MOUNTS"if echo "$MOUNTS" | grep -q "/var/run/docker.sock"; then echo " 挂载了 Docker socket,可逃逸到宿主机!"fi附、实践:容器安全审计
本节用真实命令审计容器的安全配置,包括 Capabilities、Seccomp、只读文件系统等。需要 Docker 环境和 root 权限。
附.1 默认容器的 Capabilities
# 启动一个默认配置的容器docker run -d --name sec-demo alpine:latest sleep 300
# 查看容器进程的实际 CapabilitiesCONTAINER_PID=$(docker inspect -f '{{.State.Pid}}' sec-demo)cat /proc/$CONTAINER_PID/status | grep -i CapCapInh: 0000000000000000CapPrm: 00000000a80425fbCapEff: 00000000a80425fbCapBnd: 00000000a80425fbCapAmb: 0000000000000000这个十六进制掩码 a80425fb 对应 Docker 默认授予的约 14 个 Capabilities(包括 CAP_NET_BIND_SERVICE、CAP_KILL、CAP_SETUID 等)。虽然比 root 的全部 Capabilities 少很多,但仍然包含潜在风险。
附.2 最小权限容器:丢弃所有 Capabilities
docker run --rm --cap-drop=ALL alpine:latest sh -c 'cat /proc/self/status | grep Cap'CapInh: 0000000000000000CapPrm: 0000000000000000CapEff: 0000000000000000CapBnd: 0000000000000000CapAmb: 0000000000000000所有 Capabilities 为 0,容器进程没有任何特权操作能力。这是最安全的配置,但可能导致某些应用无法正常运行(如 ping 需要 CAP_NET_RAW)。
附.3 只读根文件系统
docker run --rm --read-only alpine:latest sh -c \ 'echo "read-only fs works" && touch /tmp/test 2>&1 || echo "写入 /tmp 失败(预期行为)"'read-only fs workstouch: /tmp/test: Read-only file system写入 /tmp 失败(预期行为)--read-only 让容器的根文件系统变为只读,攻击者无法写入恶意文件。如果应用需要写入临时文件,可以用 --tmpfs /tmp 挂载内存文件系统。
附.4 安全基线检查脚本
CONTAINER=sec-demo
echo "=== 容器安全基线检查 ==="echo "1. 镜像: $(docker inspect -f '{{.Config.Image}}' $CONTAINER)"echo "2. 运行用户: $(docker inspect -f '{{.Config.User}}' $CONTAINER || echo '(默认 root)')"echo "3. 特权模式: $(docker inspect -f '{{.HostConfig.Privileged}}' $CONTAINER)"echo "4. 只读根 FS: $(docker inspect -f '{{.HostConfig.ReadonlyRootfs}}' $CONTAINER)"echo "5. CapAdd: $(docker inspect -f '{{.HostConfig.CapAdd}}' $CONTAINER)"echo "6. CapDrop: $(docker inspect -f '{{.HostConfig.CapDrop}}' $CONTAINER)"echo "7. SecurityOpt: $(docker inspect -f '{{.HostConfig.SecurityOpt}}' $CONTAINER)"安全基线建议:
- 运行用户:非 root(
USER指令或--user) - 特权模式:必须为
false - 只读根 FS:建议
true - CapAdd:应为空或仅添加必要 Capabilities
- CapDrop:建议
ALL,然后按需添加
实验结束后清理:docker rm -f sec-demo
八、本章小结
上一章理解了 docker run 的完整流程。
| 安全机制 | 防护范围 | 默认启用 | 配置方式 |
|---|---|---|---|
| Namespace | 视图隔离 | 是 | runc spec |
| Cgroup | 资源限制 | 是 | —memory, —cpus |
| Capabilities | 权限细分 | 是(部分) | —cap-add, —cap-drop |
| seccomp | 系统调用过滤 | 是 | —security-opt seccomp= |
| AppArmor | 文件访问控制 | 宿主支持时1 | —security-opt apparmor= |
| SELinux | 类型强制访问 | 宿主支持时1 | —security-opt label= |
| User Namespace | 用户映射 | 否 | rootless 模式 |
| 只读文件系统 | 文件不可变 | 否 | —read-only |
容器安全不是单一机制能解决的,而是多层防护的组合。最安全的容器配置是:rootless + —cap-drop=ALL + 自定义 seccomp + AppArmor + 只读文件系统 + 资源限制。但这种配置可能影响应用兼容性,需要根据实际场景权衡。
Footnotes
支持与分享
如果这篇文章对你有帮助,欢迎支持作者或分享给更多人
部分信息可能已经过时






