第一层:容器安全与运行时原理

一、Seccomp/AppArmor安全机制

1.1 Seccomp(安全计算模式)

核心原理
┌─────────────────────────────────────────────────────────────────┐
│                    Seccomp 工作原理                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  用户进程                                                        │
│      │                                                           │
│      │ 系统调用 (syscall)                                        │
│      ▼                                                           │
│  ┌──────────────────────┐                                        │
│  │   Seccomp BPF Filter │ ◄── Seccomp Profile (JSON)           │
│  │   (内核eBPF程序)      │                                      │
│  └──────────┬───────────┘                                        │
│             │                                                     │
│      ┌──────┼──────┐                                            │
│      ▼      ▼      ▼                                            │
│   ALLOW  ERRNO  KILL                                            │
│   (允许) (返回错误)(终止进程)                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
Seccomp Profile结构
{
  "defaultAction": "ERRNO",
  "defaultErrnoRet": 1,
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": ["read", "write", "exit", "sigreturn"],
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "names": ["chmod", "chown"],
      "action": "SCMP_ACT_ERRNO",
      "errnoRet": 1
    },
    {
      "names": ["mount", "umount2"],
      "action": "SCMP_ACT_KILL"
    }
  ]
}
Kubernetes中使用Seccomp
apiVersion: v1
kind: Pod
metadata:
  name: seccomp-demo
  annotations:
    seccomp.security.alpha.kubernetes.io/pod: "runtime/default"
    # 自定义Profile:
    # seccomp.security.alpha.kubernetes.io/pod: "localhost/profiles/custom.json"
spec:
  securityContext:
    seccompProfile:
      type: RuntimeDefault  # 或 Localhost
      localhostProfile: profiles/custom.json  # type=Localhost时指定
  containers:
  - name: app
    image: nginx
    securityContext:
      seccompProfile:
        type: RuntimeDefault
常见系统调用分类
类别系统调用典型操作
文件I/Oread, write, open, close文件读写
进程管理fork, clone, execve, exit进程创建/退出
网络socket, bind, listen, accept网络通信
内存mmap, mprotect, brk内存管理
信号kill, sigaction, sigprocmask信号处理
危险操作mount, pivot_root, chroot文件系统操作
Seccomp BPF程序加载流程详解
┌─────────────────────────────────────────────────────────────────┐
│              Seccomp BPF 程序加载流程                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  1. 用户态: 解析JSON Profile                                     │
│     ┌──────────────────────┐                                    │
│     │ seccomp.json         │                                    │
│     │ (defaultAction,      │                                    │
│     │  syscalls rules)     │                                    │
│     └──────────┬───────────┘                                    │
│                │ libseccomp解析                                  │
│                ▼                                                 │
│  2. 用户态: 生成BPF程序                                         │
│     ┌──────────────────────┐                                    │
│     │ BPF指令序列          │                                    │
│     │ - 加载arch           │                                    │
│     │ - 比较syscall号      │                                    │
│     │ - 跳转至匹配规则     │                                    │
│     │ - 返回Action         │                                    │
│     └──────────┬───────────┘                                    │
│                │ prctl(PR_SET_SECCOMP,                           │
│                │       SECCOMP_MODE_FILTER, &prog)              │
│                ▼                                                 │
│  3. 内核态: seccomp过滤器安装                                   │
│     ┌──────────────────────┐                                    │
│     │ 内核验证BPF程序      │                                    │
│     │ - 检查指令数限制     │                                    │
│     │   (MAX_BPF_SIZE)     │                                    │
│     │ - 验证无循环         │                                    │
│     │ - 验证无危险操作     │                                    │
│     └──────────┬───────────┘                                    │
│                │                                                 │
│                ▼                                                 │
│  4. 运行时: 系统调用拦截                                        │
│     ┌──────────────────────┐                                    │
│     │ 进程发起syscall      │                                    │
│     │      │               │                                    │
│     │      ▼               │                                    │
│     │ BPF过滤器执行        │ ◄── 在syscall入口点                 │
│     │ (SECCOMP_RET_xxx)    │     上下文切换之前                  │
│     └──────────────────────┘                                    │
│                                                                  │
│  关键系统调用:                                                   │
│  - prctl(PR_SET_SECCOMP): 安装过滤器                            │
│  - seccomp(SECCOMP_SET_MODE_FILTER): 新版安装接口               │
│  - seccomp(SECCOMP_GET_NOTIF_SIZES): 获取通知大小               │
│                                                                  │
│  BPF程序执行上下文:                                              │
│  - seccomp_data结构体包含:                                       │
│    · int nr          (系统调用号)                                │
│    · __u32 arch      (架构, AUDIT_ARCH_X86_64等)               │
│    · __u64 instruction_pointer (指令指针)                       │
│    · __u64 args[6]   (系统调用参数)                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
Seccomp BPF程序示例(编译后的指令序列)
// BPF程序伪代码 - 拦截mount系统调用
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),  // 加载syscall号
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, __NR_mount, 0, 1),                 // 比较是否为mount
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL_PROCESS),                   // 匹配则杀死进程
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_ALLOW),                          // 不匹配则允许

// 带架构检查的完整示例
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, arch)),  // 加载架构
BPF_JUMP(BPF_JMP | BPF_JEQ | BPF_K, AUDIT_ARCH_X86_64, 1, 0),            // 检查x86_64
BPF_STMT(BPF_RET | BPF_K, SECCOMP_RET_KILL),                              // 架构不匹配则终止
BPF_STMT(BPF_LD | BPF_W | BPF_ABS, offsetof(struct seccomp_data, nr)),    // 加载syscall号
// ... 后续规则匹配
系统调用追踪方法

方法一: strace追踪

# 追踪容器所有系统调用
strace -f -e trace=all -p <container_pid> -o /tmp/strace.log

# 仅追踪特定类别
strace -f -e trace=file,network,process -p <container_pid>

# 统计系统调用频率(用于生成Profile)
strace -c -f -p <container_pid>
# 输出示例:
# % time     seconds  usecs/call     calls    errors syscall
# ------ ----------- ----------- --------- --------- ----------------
#   25.34    0.002534           2      1200         3 read
#   18.72    0.001872           3       680           write
#   12.45    0.001245           1      1100         1 openat
#    5.67    0.000567           4       142           mmap
#    0.01    0.000001           1         1           mount  ← 可能需要拦截

# 追踪特定进程的系统调用并生成列表
strace -f -e trace=all -p <pid> 2>&1 | \
  awk '/^[0-9]+ /{print $2}' | sort -u > /tmp/syscalls.txt

方法二: oci-seccomp-bpf-hook(推荐)

# 安装oci-seccomp-bpf-hook
make && sudo make install

# 配置Podman/Docker使用hook
# /etc/oci/hooks.d/oci-seccomp-bpf-hook.json
{
  "hook": "/usr/libexec/oci/hooks.d/oci-seccomp-bpf-hook",
  "stages": ["prestart"],
  "conditions": [
    {
      "type": "annotation",
      "key": "io.containers.trace-syscall",
      "value": ".*"
    }
  ]
}

# 运行容器并自动追踪系统调用
podman run --annotation io.containers.trace-syscall=of:/tmp/profile.json \
  alpine:latest sh -c "apk add --no-cache curl && curl https://example.com"

# 生成的Profile可直接用于后续容器启动
podman run --security-opt seccomp=/tmp/profile.json alpine:latest curl https://example.com

方法三: sysdig高级追踪

# 实时监控容器系统调用
sysdig -c syscalllog container.id=<container_id>

# 过滤特定系统调用
sysdig -c syscalllog "container.id=<id> and evt.type in (mount, umount2, chroot)"

# 生成系统调用热力图
sysdig -c spectrogram "container.id=<id>"
自定义Seccomp Profile生成工具链
┌─────────────────────────────────────────────────────────────────┐
│             Seccomp Profile 生成工具链                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────────┐    ┌──────────────────┐                   │
│  │ strace/sysdig   │───►│ 原始syscall列表   │                   │
│  │ (运行时追踪)     │    │                  │                   │
│  └─────────────────┘    └────────┬─────────┘                   │
│                                  │                              │
│  ┌─────────────────┐             │                              │
│  │ oci-seccomp-    │───►│ 自动生成JSON      │                   │
│  │ bpf-hook        │    │ Profile           │                   │
│  └─────────────────┘    └────────┬─────────┘                   │
│                                  │                              │
│                                  ▼                              │
│  ┌──────────────────────────────────────────────────────┐      │
│  │              Profile加工与优化                        │      │
│  │  ┌────────────────┐  ┌────────────────┐             │      │
│  │  │ seccomp-profile│  │ security-profile│             │      │
│  │  │ -operator      │  │ -operator (SPO) │             │      │
│  │  │ (自动管理)      │  │ (K8s集成)       │             │      │
│  │  └────────────────┘  └────────────────┘             │      │
│  └──────────────────────────────────────────────────────┘      │
│                                                                  │
│  工具对比:                                                       │
│  ┌──────────────────┬──────────────┬──────────────────┐        │
│  │ 工具             │ 输出格式      │ 特点              │        │
│  ├──────────────────┼──────────────┼──────────────────┤        │
│  │ strace -c        │ 文本统计      │ 最简单,通用       │        │
│  │ oci-seccomp-bpf  │ JSON Profile │ 运行时BPF,精确    │        │
│  │ seccomp-json     │ JSON Profile │ 手动编辑,灵活     │        │
│  │ SPO(security-    │ CRD+Profile  │ K8s原生管理       │        │
│  │   profile-op)    │              │                   │        │
│  └──────────────────┴──────────────┴──────────────────┘        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

使用security-profiles-operator在Kubernetes中管理Seccomp Profile

# 安装SPO
kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/security-profiles-operator/main/deploy/operator.yaml

# 定义Seccomp Profile
apiVersion: security-profiles-operator.x-k8s.io/v1beta1
kind: SeccompProfile
metadata:
  name: nginx-profile
  namespace: security-profiles
spec:
  defaultAction: SCMP_ACT_ERRNO
  targetWorkload:
    kind: Deployment
    selector:
      matchLabels:
        app: nginx
  syscalls:
  - action: SCMP_ACT_ALLOW
    names:
    - read
    - write
    - openat
    - close
    - fstat
    - newfstatat
    - lseek
    - mmap
    - mprotect
    - munmap
    - brk
    - rt_sigaction
    - rt_sigprocmask
    - ioctl
    - access
    - faccessat
    - faccessat2
    - pipe
    - poll
    - select
    - sched_yield
    - mremap
    - nanosleep
    - clock_nanosleep
    - alarm
    - getpid
    - sendfile
    - socket
    - connect
    - accept
    - sendto
    - recvfrom
    - bind
    - listen
    - setsockopt
    - getsockopt
    - clone
    - fork
    - vfork
    - execve
    - exit
    - wait4
    - kill
    - uname
    - semget
    - semop
    - semctl
    - shmdt
    - dup
    - dup2
    - dup3
    - fcntl
    - flock
    - fsync
    - fdatasync
    - truncate
    - ftruncate
    - getdents
    - getdents64
    - getcwd
    - chdir
    - rename
    - renameat
    - renameat2
    - mkdir
    - mkdirat
    - rmdir
    - creat
    - link
    - unlink
    - unlinkat
    - readlink
    - readlinkat
    - chmod
    - fchmod
    - fchmodat
    - chown
    - fchown
    - lchown
    - fchownat
    - umask
    - gettimeofday
    - getrlimit
    - getrusage
    - sysinfo
    - times
    - getuid
    - getgid
    - setuid
    - setgid
    - geteuid
    - getegid
    - getgroups
    - setgroups
    - getresuid
    - getresgid
    - sigaltstack
    - arch_prctl
    - set_tid_address
    - set_robust_list
    - futex
    - sched_getaffinity
    - exit_group
    - epoll_create
    - epoll_create1
    - epoll_ctl
    - epoll_wait
    - tgkill
    - clock_gettime
    - clock_getres
  - action: SCMP_ACT_ERRNO
    names:
    - mount
    - umount2
    - pivot_root
    - chroot
    - ptrace
    - kexec_load
    - kexec_file_load
    - reboot
    - init_module
    - finit_module
    - delete_module
    - iopl
    - ioperm
    - swapon
    - swapoff
    - sysctl
AppArmor与SELinux对比
┌─────────────────────────────────────────────────────────────────┐
│            AppArmor vs SELinux 深度对比                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  维度             AppArmor              SELinux                  │
│  ─────────────    ──────────            ────────                │
│  访问控制模型     路径名(文件路径)       标签(inode扩展属性)     │
│  策略语言         简洁(路径规则)         复杂(type enforcement)   │
│  默认发行版       Ubuntu/SUSE           RHEL/Fedora/CentOS      │
│  学习模式         是(complain模式)       是(permissive模式)      │
│  策略生成         aa-genprof/aa-logprof  audit2allow             │
│  MLS/MCS支持      否                     是(多级/多类安全)       │
│  文件系统依赖     无(路径名)             需要扩展属性支持         │
│  容器支持         Docker/Podman原生      需sVirt适配             │
│  内核模块         apparmor               selinux(挂钩到LSM)      │
│  策略热加载       支持                   支持                    │
│  网络控制         粗粒度(协议族)         细粒度(端口+类型)       │
│                                                                  │
│  选择建议:                                                       │
│  ┌─────────────────────────────────────────────────────┐        │
│  │ 场景                    推荐方案                      │        │
│  ├─────────────────────────────────────────────────────┤        │
│  │ Ubuntu/Debian环境        AppArmor                    │        │
│  │ RHEL/CentOS环境          SELinux                     │        │
│  │ 容器安全(简单)           AppArmor                    │        │
│  │ 多级安全(政府/军事)      SELinux (MLS)               │        │
│  │ 快速原型/开发            AppArmor (complain模式)     │        │
│  │ 生产强制访问控制         SELinux (enforcing模式)     │        │
│  │ NFS/无扩展属性FS         AppArmor (路径名不受限)     │        │
│  └─────────────────────────────────────────────────────┘        │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

SELinux容器策略示例(sVirt)

# 查看容器SELinux标签
ps -eZ | grep container_t

# 容器类型:
# container_t      - 普通容器(受限)
# svirt_lxc_net_t  - 虚拟化容器
# container_runtime_t - 容器运行时本身

# SELinux文件标签与容器
# container_file_t - 容器可读写的文件
# container_share_t - 容器只读共享文件
# container_ro_file_t - 容器只读文件

# 为卷设置正确的SELinux标签
docker run -v /host/path:/container:path:z nginx   # 自动重新标记(私有)
docker run -v /host/path:/container:path:Z nginx   # 自动重新标记(共享)

# 查看SELinux拒绝日志
ausearch -m AVC,USER_AVC,SELINUX_ERR -ts recent
sealert -a /var/log/audit/audit.log
生产环境Seccomp Profile模板(按应用类型分类)

Web服务器(Nginx)Profile

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 1,
  "architectures": ["SCMP_ARCH_X86_64", "SCMP_ARCH_AARCH64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "close", "fstat", "newfstatat", "lseek",
        "mmap", "mprotect", "munmap", "brk", "rt_sigaction",
        "rt_sigprocmask", "ioctl", "access", "faccessat",
        "pipe", "poll", "sched_yield", "mremap", "nanosleep",
        "clock_nanosleep", "getpid", "sendfile", "socket",
        "connect", "accept", "accept4", "sendto", "recvfrom",
        "bind", "listen", "setsockopt", "getsockopt", "clone",
        "execve", "exit", "exit_group", "wait4", "uname",
        "fcntl", "flock", "fsync", "fdatasync", "dup", "dup2",
        "dup3", "getdents", "getdents64", "getcwd", "chdir",
        "rename", "mkdir", "mkdirat", "rmdir", "creat", "link",
        "unlink", "unlinkat", "readlink", "readlinkat", "chmod",
        "fchmod", "fchmodat", "chown", "fchown", "lchown",
        "fchownat", "umask", "gettimeofday", "getrlimit",
        "getrusage", "sysinfo", "times", "getuid", "getgid",
        "setuid", "setgid", "geteuid", "getegid", "getgroups",
        "setgroups", "getresuid", "getresgid", "sigaltstack",
        "arch_prctl", "set_tid_address", "set_robust_list",
        "futex", "sched_getaffinity", "epoll_create",
        "epoll_create1", "epoll_ctl", "epoll_wait", "epoll_pwait",
        "tgkill", "clock_gettime", "clock_getres", "openat",
        "prctl", "prlimit64", "getrandom", "membarrier",
        "madvise", "recvmsg", "sendmsg", "shutdown",
        "getsockname", "getpeername", "socketpair",
        "sigaltstack", "pipe2", "statfs", "fstatfs",
        "statx", "pread64", "pwrite64", "splice", "tee",
        "copy_file_range", "getcpu", "sysinfo"
      ],
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "names": ["personality"],
      "action": "SCMP_ACT_ALLOW",
      "args": [
        {
          "index": 0,
          "op": "SCMP_CMP_EQ",
          "value": 0
        }
      ]
    }
  ]
}

数据库(PostgreSQL)Profile关键差异

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 1,
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "close", "fstat", "newfstatat", "lseek",
        "mmap", "mprotect", "munmap", "brk", "rt_sigaction",
        "rt_sigprocmask", "ioctl", "access", "faccessat",
        "pipe", "poll", "sched_yield", "mremap", "nanosleep",
        "clock_nanosleep", "getpid", "sendfile", "socket",
        "connect", "accept", "accept4", "sendto", "recvfrom",
        "bind", "listen", "setsockopt", "getsockopt", "clone",
        "fork", "execve", "exit", "exit_group", "wait4",
        "uname", "fcntl", "flock", "fsync", "fdatasync",
        "dup", "dup2", "dup3", "getdents", "getdents64",
        "getcwd", "chdir", "rename", "mkdir", "mkdirat",
        "rmdir", "unlink", "unlinkat", "readlink", "chmod",
        "fchmod", "fchmodat", "chown", "fchown", "fchownat",
        "umask", "gettimeofday", "getrlimit", "getrusage",
        "sysinfo", "getuid", "getgid", "setuid", "setgid",
        "geteuid", "getegid", "getgroups", "setgroups",
        "getresuid", "getresgid", "sigaltstack", "arch_prctl",
        "set_tid_address", "set_robust_list", "futex",
        "sched_getaffinity", "epoll_create1", "epoll_ctl",
        "epoll_wait", "epoll_pwait", "tgkill", "clock_gettime",
        "openat", "prctl", "prlimit64", "getrandom",
        "membarrier", "madvise", "recvmsg", "sendmsg",
        "shutdown", "getsockname", "getpeername",
        "semget", "semop", "semctl", "shmget", "shmat",
        "shmdt", "shmctl", "msgget", "msgsnd", "msgrcv",
        "msgctl", "ftruncate", "truncate", "statfs", "fstatfs",
        "statx", "pread64", "pwrite64", "copy_file_range",
        "getcpu", "process_vm_readv", "process_vm_writev",
        "seccomp", "pipe2", "preadv", "pwritev"
      ],
      "action": "SCMP_ACT_ALLOW"
    }
  ]
}

Go应用通用Profile

{
  "defaultAction": "SCMP_ACT_ERRNO",
  "defaultErrnoRet": 1,
  "architectures": ["SCMP_ARCH_X86_64"],
  "syscalls": [
    {
      "names": [
        "read", "write", "close", "fstat", "newfstatat", "lseek",
        "mmap", "mprotect", "munmap", "brk", "rt_sigaction",
        "rt_sigprocmask", "ioctl", "access", "faccessat",
        "pipe", "pipe2", "poll", "sched_yield", "mremap",
        "nanosleep", "clock_nanosleep", "getpid", "sendfile",
        "socket", "connect", "accept", "accept4", "sendto",
        "recvfrom", "bind", "listen", "setsockopt", "getsockopt",
        "clone", "fork", "execve", "exit", "exit_group", "wait4",
        "kill", "uname", "fcntl", "flock", "fsync", "fdatasync",
        "dup", "dup2", "dup3", "getdents", "getdents64",
        "getcwd", "chdir", "rename", "mkdir", "mkdirat",
        "rmdir", "unlink", "unlinkat", "readlink", "readlinkat",
        "chmod", "fchmod", "fchmodat", "chown", "fchown",
        "fchownat", "umask", "gettimeofday", "getrlimit",
        "getrusage", "sysinfo", "times", "getuid", "getgid",
        "setuid", "setgid", "geteuid", "getegid", "getgroups",
        "setgroups", "getresuid", "getresgid", "sigaltstack",
        "arch_prctl", "set_tid_address", "set_robust_list",
        "futex", "sched_getaffinity", "epoll_create1",
        "epoll_ctl", "epoll_wait", "epoll_pwait", "tgkill",
        "clock_gettime", "clock_getres", "openat", "prctl",
        "prlimit64", "getrandom", "membarrier", "madvise",
        "recvmsg", "sendmsg", "shutdown", "getsockname",
        "getpeername", "socketpair", "statfs", "fstatfs",
        "statx", "pread64", "pwrite64", "splice", "tee",
        "copy_file_range", "getcpu", "sysinfo", "seccomp",
        "fcntl", "fadvise64", "sync_file_range", "fallocate",
        "timer_create", "timer_settime", "timer_gettime",
        "timer_delete", "clock_adjtime", "signalfd4",
        "eventfd2", "inotify_init1", "inotify_add_watch"
      ],
      "action": "SCMP_ACT_ALLOW"
    },
    {
      "names": ["personality"],
      "action": "SCMP_ACT_ALLOW",
      "args": [{"index": 0, "op": "SCMP_CMP_EQ", "value": 0}]
    }
  ]
}

Profile调试与故障排查

# 1. 查看容器当前Seccomp状态
cat /proc/<pid>/status | grep Seccomp
# Seccomp: 2  (0=禁用, 1=strict, 2=filter)

# 2. 查看当前BPF过滤器
cat /proc/<pid>/syscall
# 显示最后一次系统调用信息

# 3. 使用auditd追踪被Seccomp拒绝的操作
# /etc/audit/rules.d/audit.rules
-a always,exit -F arch=b64 -S mount -S umount2 -S chroot -F key=seccomp-deny

# 4. 将Profile从enforcing切换为permissive(日志模式)
# 修改defaultAction为SCMP_ACT_LOG, 记录但不拒绝
{
  "defaultAction": "SCMP_ACT_LOG",
  "syscalls": [...]
}

# 5. 使用journalctl查看seccomp拒绝日志
journalctl -t kernel | grep seccomp
# 或
dmesg | grep -i seccomp

# 6. 常见故障排查流程
# 容器启动失败 → 检查dmesg/journalctl → 识别被拒绝的syscall
# → 将该syscall加入允许列表 → 重新测试

1.2 AppArmor(应用程序装甲)

核心原理
┌─────────────────────────────────────────────────────────────────┐
│                   AppArmor 工作原理                               │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  进程启动                                                        │
│      │                                                           │
│      ▼                                                           │
│  内核加载AppArmor Profile                                        │
│      │                                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────┐                            │
│  │     AppArmor强制模式             │                            │
│  │  ┌────────┐  ┌────────┐        │                            │
│  │  │文件访问│  │网络访问│        │                            │
│  │  │控制    │  │控制    │        │                            │
│  │  └────────┘  └────────┘        │                            │
│  │  ┌────────┐  ┌────────┐        │                            │
│  │  │能力控制│  │资源限制│        │                            │
│  │  └────────┘  └────────┘        │                            │
│  └──────────────────────────────────┘                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
AppArmor Profile示例
#include <tunables/global>

profile nginx-profile flags=(attach_disconnected,mediate_deleted) {
  #include <abstractions/base>
  #include <abstractions/nameservice>

  # 文件访问规则
  /usr/sbin/nginx mr,
  /etc/nginx/** r,
  /var/log/nginx/** rw,
  /var/cache/nginx/** rw,
  /usr/share/nginx/** r,

  # 网络规则
  network inet tcp,
  network inet6 tcp,

  # 能力规则
  capability setgid,
  capability setuid,
  capability net_bind_service,

  # 拒绝规则
  deny /etc/shadow r,
  deny /root/** rw,
}
Kubernetes中使用AppArmor
apiVersion: v1
kind: Pod
metadata:
  name: apparmor-demo
  annotations:
    container.apparmor.security.beta.kubernetes.io/app: "localhost/nginx-profile"
spec:
  containers:
  - name: app
    image: nginx

1.3 Seccomp vs AppArmor对比

特性SeccompAppArmor
控制粒度系统调用级别文件/网络/能力级别
配置复杂度高(需了解syscall)中(路径规则)
学习曲线陡峭中等
适用场景限制系统调用限制文件/网络访问
默认启用容器运行时默认需手动配置
BPF支持是(seccomp-bpf)

二、Rootless容器

2.1 Rootless容器原理

传统容器 vs Rootless容器
┌─────────────────────────────────────────────────────────────────────┐
│                   传统容器(Rootful)                                  │
├─────────────────────────────────────────────────────────────────────┤
│  用户空间    │  容器进程(root)  │  宿主机root映射                    │
│             │  UID 0          │  UID 0                            │
│             │  全部能力       │  全部能力                          │
└─────────────────────────────────────────────────────────────────────┘

┌─────────────────────────────────────────────────────────────────────┐
│                   Rootless容器                                      │
├─────────────────────────────────────────────────────────────────────┤
│  用户空间    │  容器进程(root)  │  宿主机普通用户映射                │
│             │  UID 0(容器内)  │  UID 100000(宿主机)               │
│             │  子集能力       │  受限能力                          │
└─────────────────────────────────────────────────────────────────────┘
User Namespace映射机制
┌─────────────────────────────────────────────────────────────────┐
│              User Namespace UID映射                              │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  容器内UID          宿主机UID                                     │
│  ──────────         ──────────                                   │
│  0 (root)    ───►   100000                                      │
│  1 (daemon)  ───►   100001                                      │
│  2 (bin)     ───►   100002                                      │
│  ...              ...                                            │
│  65534       ───►   165534                                      │
│                                                                  │
│  /etc/subuid: username:100000:65536                              │
│  /etc/subgid: username:100000:65536                              │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

2.2 Rootless容器运行时配置

Podman Rootless模式
# 配置subuid/subgid
echo "username:100000:65536" >> /etc/subuid
echo "username:100000:65536" >> /etc/subgid

# 运行rootless容器
podman run --rm -it alpine:latest whoami
# 输出: root (但实际是普通用户)

# 检查容器内进程在宿主机的UID
podman run --rm alpine ps aux
Docker Rootless模式
# 安装rootless模式
dockerd-rootless-setuptool.sh install

# 配置环境变量
export DOCKER_HOST=unix:///run/user/$UID/docker.sock

# 运行容器
docker run --rm -it alpine:latest whoami
Kubernetes Rootless模式
# 使用kind创建rootless集群
kind create cluster --image kindest/node:v1.28.0 \
  --config - <<EOF
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
nodes:
- role: control-plane
  extraMounts:
  - containerPath: /var/lib/kubelet
    hostPath: /tmp/kubelet
EOF

2.3 Rootless容器限制与解决方案

限制原因解决方案
端口<1024无net_bind_service能力sysctl设置net.ipv4.ip_unprivileged_port_start
网络限制无NET_ADMIN能力Slirp4netns/Pasta
Cgroup限制无cgroup管理权限cgroup v2 + systemd delegation
NFS挂载内核限制FUSE解决方案
性能开销用户空间网络Pasta替代Slirp4netns
User Namespace内核实现原理
┌─────────────────────────────────────────────────────────────────┐
│           User Namespace 内核实现                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  数据结构关系:                                                   │
│  ┌───────────────────────────────────────────────────────┐     │
│  │ task_struct (进程描述符)                               │     │
│  │   ├── nsproxy                                         │     │
│  │   │     ├── uts_ns                                    │     │
│  │   │     ├── ipc_ns                                     │     │
│  │   │     ├── mnt_ns                                     │     │
│  │   │     ├── pid_ns_for_children                       │     │
│  │   │     ├── net_ns                                     │     │
│  │   │     └── cgroup_ns                                  │     │
│  │   │                                                    │     │
│  │   ├── real_cred (真实凭据)                            │     │
│  │   │     ├── uid, gid, suid, sgid                     │     │
│  │   │     └── user_namespace (指向所属user_ns)          │     │
│  │   │                                                    │     │
│  │   └── nsproxy->user_ns (或单独的user_ns)              │     │
│  └───────────────────────────────────────────────────────┘     │
│                                                                  │
│  UID映射内核结构:                                                │
│  ┌───────────────────────────────────────────────────────┐     │
│  │ uid_gid_map (在/proc/<pid>/uid_map)                   │     │
│  │   ├── first: 容器内起始UID                            │     │
│  │   ├── lower_first: 宿主机起始UID(需要权限)            │     │
│  │   └── count: 映射范围大小                             │     │
│  │                                                        │     │
│  │ 示例: 0 100000 65536                                   │     │
│  │ 含义: 容器UID 0-65535 → 宿主机UID 100000-165535       │     │
│  └───────────────────────────────────────────────────────┘     │
│                                                                  │
│  权限检查流程(关键函数):                                         │
│  ┌───────────────────────────────────────────────────────┐     │
│  │ 1. ns_capable(user_ns, CAP_SYS_ADMIN)                 │     │
│  │    - 检查是否在目标user_ns中具有CAP_SYS_ADMIN         │     │
│  │                                                        │     │
│  │ 2. mapped_kuid(user_ns, uid_in_container)             │     │
│  │    - 将容器UID映射到内核kuid_t                         │     │
│  │    - from_kuid(user_ns->parent, kuid)                  │     │
│  │                                                        │     │
│  │ 3. cap_raise_nscapable(user_ns, cap)                  │     │
│  │    - 在嵌套namespace中提升能力                         │     │
│  │    - 最多嵌套32层(USER_NS_LIMIT)                       │     │
│  └───────────────────────────────────────────────────────┘     │
│                                                                  │
│  关键系统调用:                                                   │
│  - unshare(CLONE_NEWUSER): 创建新user namespace                 │
│  - clone(CLONE_NEWUSER): 创建进程时同时创建user ns              │
│  - setns(fd, CLONE_NEWUSER): 加入已有user ns                    │
│                                                                  │
│  /proc接口:                                                      │
│  - /proc/<pid>/uid_map: UID映射配置                             │
│  - /proc/<pid>/gid_map: GID映射配置                             │
│  - /proc/<pid>/projid_map: Project ID映射(极少使用)            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

User Namespace创建与配置流程

# 手动创建user namespace并配置映射
# 步骤1: 创建新user namespace
unshare --user --map-root-user bash
# 或手动:
unshare -U bash

# 步骤2: 配置UID映射(需要父namespace权限)
# 在父namespace中:
echo "0 100000 65536" > /proc/<child_pid>/uid_map
echo "0 100000 65536" > /proc/<child_pid>/gid_map

# 步骤3: 禁用setgroups(必须先于gid_map)
echo "deny" > /proc/<child_pid>/setgroups

# 验证映射
cat /proc/self/uid_map
# 输出:          0     100000      65536

# 查看当前进程在各级namespace中的UID
# /proc/self/status中的字段:
# Uid:  0(root)  0(root)  0(root)  0(root)  # 容器内视角
# 在宿主机视角(另一个终端):
ps -o pid,uid,user,cmd -p <pid>
# 显示UID为100000

内核源码关键路径

// kernel/user_namespace.c - 关键函数

// 创建user namespace
static struct ucounts *inc_user_namespaces(struct user_namespace *ns)
{
    return inc_ucount(ns, current_euid(), UCOUNT_USER_NAMESPACES);
}

// UID映射写入
static ssize_t map_write(struct file *file, const char __user *buf,
                         size_t count, loff_t *ppos,
                         int cap_setid,
                         struct uid_gid_map *map,
                         struct uid_gid_map *parent_map)
{
    // 权限检查:
    // 1. 写入者必须在父namespace中
    // 2. 需要CAP_SETUID/CAP_SETGID(在父namespace中)
    // 3. 或需要CAP_SYS_ADMIN(在父namespace中)
    
    // 映射规则验证:
    // - 不能映射到父namespace之外的UID
    // - 不能覆盖已映射的范围
}

// 权限检查: 进程A能否向进程B发送信号
static int kill_userns_check(int sig, struct pid *pid,
                             struct user_namespace *targ_ns)
{
    // 检查信号发送者是否有权限:
    // 1. 相同user namespace: 正常权限检查
    // 2. 父namespace: 如果子ns的UID映射回父ns且有权限
    // 3. 否则拒绝
}
Rootless容器网络方案深度对比
┌─────────────────────────────────────────────────────────────────┐
│           Rootless 网络方案对比                                   │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  方案           原理              性能     功能     推荐度       │
│  ────────       ──────            ────     ────     ──────       │
│  slirp4netns    用户态TCP/IP栈    低       基础     ★★☆☆☆       │
│  pasta          libpnetns+tap     中       完整     ★★★★☆       │
│  Bypass4netns   非绕过模式        高       完整     ★★★★★       │
│  CNI-plugins    (需要setuid)      高       完整     ★★★★☆       │
│                                                                  │
│  性能对比(bandwidth):                                            │
│  ┌──────────────────────────────────────────────────────┐       │
│  │ 方案          TCP下载      TCP上传      UDP          │       │
│  │ slirp4netns   ~500MB/s    ~400MB/s    ~300MB/s      │       │
│  │ pasta         ~800MB/s    ~700MB/s    ~600MB/s      │       │
│  │ bypass4netns  ~1000MB/s   ~900MB/s    ~800MB/s      │       │
│  │ rootful       ~1000MB/s   ~1000MB/s   ~900MB/s      │       │
│  └──────────────────────────────────────────────────────┘       │
│                                                                  │
│  延迟对比(ping localhost):                                       │
│  slirp4netns:  0.3-0.5ms                                        │
│  pasta:        0.1-0.2ms                                        │
│  bypass4netns: 0.05-0.1ms                                       │
│  rootful:       0.01-0.05ms                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

slirp4netns详解

┌─────────────────────────────────────────────────────────────────┐
│              slirp4netns 架构                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  容器进程                                                        │
│      │                                                           │
│      │ eth0 (tap设备)                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────┐              │
│  │           slirp4netns 进程                    │              │
│  │  ┌────────────────────────────────────────┐  │              │
│  │  │         用户态TCP/IP栈 (libslirp)       │  │              │
│  │  │  - ARP处理                             │  │              │
│  │  │  - IP路由                              │  │              │
│  │  │  - TCP状态机                           │  │              │
│  │  │  - NAT (端口映射)                       │  │              │
│  │  │  - DHCP服务器                          │  │              │
│  │  │  - DNS代理                             │  │              │
│  │  └────────────────────────────────────────┘  │              │
│  │                     │                         │              │
│  │                     │ tap接口                 │              │
│  │                     ▼                         │              │
│  │              宿主机网络栈                      │              │
│  └──────────────────────────────────────────────┘              │
│                                                                  │
│  默认网络配置:                                                   │
│  - 容器IP: 10.0.2.100                                           │
│  - 网关: 10.0.2.2                                               │
│  - DNS: 10.0.2.3                                                │
│  - 子网: 10.0.2.0/24                                            │
│                                                                  │
│  启动命令:                                                       │
│  slirp4netns --configure --mtu=65520 <pid> tap0                 │
│                                                                  │
│  端口映射:                                                       │
│  slirp4netns --port-handler=builtin:0.0.0.0:8080-80 \           │
│              --port-handler=builtin:0.0.0.0:8443-443 <pid> tap0 │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

pasta详解(推荐方案)

┌─────────────────────────────────────────────────────────────────┐
│              pasta ( passt + netns )                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  容器进程                                                        │
│      │                                                           │
│      │ eth0 (tap设备)                                           │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────┐              │
│  │              pasta 进程                       │              │
│  │  ┌────────────────────────────────────────┐  │              │
│  │  │         passt (用户态TCP/UDP)           │  │              │
│  │  │  - 零拷贝(splice/sendfile)              │  │              │
│  │  │  - 高性能epoll事件循环                  │  │              │
│  │  │  - 完整TCP状态机                        │  │              │
│  │  │  - DSCP/ECN支持                         │  │              │
│  │  │  - TCP_MD5SIG支持                       │  │              │
│  │  └────────────────────────────────────────┘  │              │
│  │                                               │              │
│  │  ┌────────────────────────────────────────┐  │              │
│  │  │         tap设备管理                     │  │              │
│  │  │  - 自动配置IPv4/IPv6                    │  │              │
│  │  │  - MTU发现                             │  │              │
│  │  │  - 多队列支持                          │  │              │
│  │  └────────────────────────────────────────┘  │              │
│  └──────────────────────────────────────────────┘              │
│                                                                  │
│  特点:                                                           │
│  1. 基于 passt (Passive Automatic Sockets and Splicing Tool)   │
│  2. 支持自动检测宿主机网络配置                                   │
│  3. 支持TCP/UDP端口转发                                          │
│  4. 支持IPv4和IPv6双栈                                           │
│  5. 自动处理ICMP(v4/v6)                                          │
│                                                                  │
│  使用方法:                                                       │
│  # Podman自动使用pasta(如果安装)                                │
│  podman run --network=pasta alpine                              │
│                                                                  │
│  # 手动配置端口转发                                              │
│  podman run --network=pasta:-T,8080:80,-U,53:53 alpine         │
│                                                                  │
│  # 与slirp4netns性能对比                                         │
│  pasta优势:                                                      │
│  - 零拷贝减少内存复制                                            │
│  - 更高效的epoll事件处理                                         │
│  - 原生支持IPv6                                                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

bypass4netns(高性能方案)

# bypass4netns通过绕过用户态网络栈实现接近原生性能
# 需要: 
# 1. sysctl -w net.ipv4.ip_unprivileged_port_start=0
# 2. 特殊的网络配置

# 安装
go install github.com/rootless-containers/bypass4netns@latest

# 使用bypass4netns
bypass4netnsd &
podman run --network=bypass4netns alpine

# 原理: 
# bypass4netns检测到本地连接时,直接通过socket传递,
# 跳过用户态网络栈,实现接近原生性能
Rootless模式下的存储驱动选择
┌─────────────────────────────────────────────────────────────────┐
│           Rootless 存储驱动对比                                  │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  驱动            需要权限      性能    功能完整性   推荐度       │
│  ────────        ────────      ────    ────────     ──────       │
│  overlayfs       无           高      完整         ★★★★★       │
│  fuse-overlayfs  无           中      完整         ★★★★☆       │
│  vfs             无           低      基础         ★★☆☆☆       │
│  devmapper       需要root     高      完整         N/A          │
│  btrfs           无*          高      完整         ★★★★☆       │
│  zfs             无*          高      完整         ★★★★☆       │
│                                                                  │
│  *btrfs/zfs需要宿主机内核支持相应文件系统                        │
│                                                                  │
│  推荐选择流程:                                                   │
│  ┌──────────────────────────────────────────────────────┐       │
│  │ 1. 检查内核支持:                                      │       │
│  │    cat /proc/filesystems | grep overlay              │       │
│  │    → 有: 使用 overlayfs                               │       │
│  │    → 无: 继续检查                                     │       │
│  │                                                       │       │
│  │ 2. 检查fuse-overlayfs:                                │       │
│  │    which fuse-overlayfs                              │       │
│  │    → 有: 使用 fuse-overlayfs                         │       │
│  │    → 无: 使用 vfs (性能最差)                          │       │
│  └──────────────────────────────────────────────────────┘       │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

fuse-overlayfs详解

┌─────────────────────────────────────────────────────────────────┐
│              fuse-overlayfs 架构                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  容器进程                                                        │
│      │                                                           │
│      │ 文件系统操作 (read/write/open)                            │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────┐              │
│  │         FUSE (Filesystem in Userspace)        │              │
│  │  ┌────────────────────────────────────────┐  │              │
│  │  │         fuse-overlayfs 进程             │  │              │
│  │  │                                        │  │              │
│  │  │  overlay操作(用户态实现):               │  │              │
│  │  │  - lowerdir: 只读镜像层                 │  │              │
│  │  │  - upperdir: 容器可写层                 │  │              │
│  │  │  - workdir: 元数据目录                  │  │              │
│  │  │  - merged: 挂载点                       │  │              │
│  │  │                                        │  │              │
│  │  │  FUSE操作:                              │  │              │
│  │  │  - getattr: 获取文件属性                │  │              │
│  │  │  - lookup: 查找文件                     │  │              │
│  │  │  - read/write: 读写操作                 │  │              │
│  │  │  - copy-up: 写时复制                    │  │              │
│  │  └────────────────────────────────────────┘  │              │
│  │                     │                         │              │
│  │                     │ /dev/fuse              │              │
│  │                     ▼                         │              │
│  │              宿主机文件系统                    │              │
│  └──────────────────────────────────────────────┘              │
│                                                                  │
│  性能开销(相比原生overlayfs):                                    │
│  - 文件读取: +10-20% 延迟                                       │
│  - 文件写入: +15-30% 延迟                                       │
│  - 元数据操作: +20-40% 延迟                                     │
│                                                                  │
│  安装与配置:                                                     │
│  # 安装fuse-overlayfs                                           │
│  apt install fuse-overlayfs                                     │
│  # 或                                                           │
│  dnf install fuse-overlayfs                                     │
│                                                                  │
│  # Podman配置                                                    │
│  cat > ~/.config/containers/storage.conf <<EOF                  │
│  [storage]                                                      │
│  driver = "overlay"                                             │
│  runroot = "/run/user/$(id -u)/containers"                     │
│  graphroot = "$HOME/.local/share/containers/storage"           │
│  [storage.options.overlay]                                      │
│  mount_program = "/usr/bin/fuse-overlayfs"                     │
│  mountopt = "nodev,fsync=0"                                    │
│  EOF                                                            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

vfs存储驱动(备选方案)

# vfs驱动: 直接使用目录树,无overlay
# 缺点: 
# - 无写时复制,每次创建容器都完整复制镜像
# - 占用大量磁盘空间
# - 性能差

# 使用场景:
# - 内核不支持overlayfs
# - 无法安装fuse-overlayfs
# - 测试环境

# 配置
podman --storage-driver=vfs run alpine
Kubernetes Rootless模式生产部署方案
┌─────────────────────────────────────────────────────────────────┐
│         Kubernetes Rootless 部署架构                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  方案一: Usernetes (用户态Kubernetes)                            │
│  ─────────────────────────────────────────────                   │
│  ┌──────────────────────────────────────────────────────┐      │
│  │  用户空间                                              │      │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐             │      │
│  │  │ kube-    │ │ kube-    │ │ kube-    │             │      │
│  │  │ apiserver│ │ scheduler│ │ let     │             │      │
│  │  └──────────┘ └──────────┘ └──────────┘             │      │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐             │      │
│  │  │ etcd     │ │ coredns  │ │ CNI      │             │      │
│  │  │          │ │          │ │(pasta)   │             │      │
│  │  └──────────┘ └──────────┘ └──────────┘             │      │
│  └──────────────────────────────────────────────────────┘      │
│                                                                  │
│  方案二: Rootless Kind (测试环境推荐)                            │
│  ─────────────────────────────────────────────                   │
│  ┌──────────────────────────────────────────────────────┐      │
│  │  kind create cluster --rootless                       │      │
│  │                                                       │      │
│  │  支持功能:                                             │      │
│  │  - 多节点集群                                          │      │
│  │  - 端口映射                                            │      │
│  │  - 卷挂载                                              │      │
│  │  - LoadBalancer (需要cloud-provider)                  │      │
│  └──────────────────────────────────────────────────────┘      │
│                                                                  │
│  方案三: K3s Rootless (轻量生产推荐)                             │
│  ─────────────────────────────────────────────                   │
│  ┌──────────────────────────────────────────────────────┐      │
│  │  curl -sfL https://get.k3s.io | sh -s - --rootless   │      │
│  │                                                       │      │
│  │  限制:                                                 │      │
│  │  - 无NodePort Service                                 │      │
│  │  - 无LoadBalancer(需额外组件)                         │      │
│  │  - Ingress需要特殊配置                                │      │
│  └──────────────────────────────────────────────────────┘      │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

K3s Rootless生产部署配置

# 1. 系统准备
# 启用cgroup v2 delegation
sudo systemctl edit --full user@1000.service
# 添加:
[Service]
Delegate=yes

# 或在/etc/systemd/system/user@.service.d/delegate.conf
[Service]
Delegate=cpu cpuset io memory pids

# 2. 配置sysctl参数
sudo sysctl -w net.ipv4.ip_unprivileged_port_start=0
# 持久化
echo "net.ipv4.ip_unprivileged_port_start=0" | \
  sudo tee /etc/sysctl.d/rootless.conf

# 3. 安装K3s rootless
curl -sfL https://get.k3s.io | sh -s - --rootless \
  --write-kubeconfig-mode=644 \
  --kube-apiserver-arg="--enable-admission-plugins=NodeRestriction"

# 4. 配置网络
# 使用pasta作为CNI
export K3S_ROOTLESS_API_PORT=6444
cat > /etc/rancher/k3s/config.yaml <<EOF
write-kubeconfig-mode: "0644"
cni: "pasta"
disable:
  - traefik
EOF

# 5. 验证
KUBECONFIG=~/.kube/config kubectl get nodes

Pod Security Standards for Rootless

# rootless-pod-security.yaml
apiVersion: v1
kind: Namespace
metadata:
  name: rootless-apps
  labels:
    pod-security.kubernetes.io/enforce: restricted
    pod-security.kubernetes.io/enforce-version: latest
---
apiVersion: v1
kind: Pod
metadata:
  name: rootless-app
  namespace: rootless-apps
spec:
  securityContext:
    runAsNonRoot: true
    runAsUser: 1000
    seccompProfile:
      type: RuntimeDefault
  containers:
  - name: app
    image: nginx:alpine
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
    resources:
      limits:
        memory: "128Mi"
        cpu: "500m"
Rootless vs 运行时特权模式安全对比
┌─────────────────────────────────────────────────────────────────┐
│      Rootless vs 特权容器 安全深度对比                           │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  攻击面维度        Rootless        特权容器        风险差异      │
│  ────────────      ────────        ────────        ────────      │
│  宿主机UID         普通用户        root           高危           │
│  能力集            最小子集        全部(CAP_ALL)   高危          │
│  系统调用          受限(seccomp)   不受限          中危          │
│  设备访问          仅基本设备      所有设备        高危          │
│  namespace逃逸     影响有限        可控宿主机      高危          │
│  文件系统          用户目录        整个根文件系统  高危          │
│  网络攻击          受限NAT        原始网络栈      高危          │
│  内核漏洞利用      权限不足        可直接利用      高危          │
│                                                                  │
│  攻击场景分析:                                                   │
│  ┌──────────────────────────────────────────────────────┐       │
│  │ 场景: CVE-2019-5736 (runc容器逃逸)                    │       │
│  │                                                       │       │
│  │ Rootless容器:                                         │       │
│  │ - 攻击者UID为100000+                                  │       │
│  │ - 无法覆盖宿主机runc二进制                            │       │
│  │ - 逃逸后仍为普通用户权限                              │       │
│  │ - 影响范围: 仅用户目录                                │       │
│  │                                                       │       │
│  │ 特权容器:                                             │       │
│  │ - 攻击者UID为0                                        │       │
│  │ - 可以覆盖runc二进制                                  │       │
│  │ - 获得宿主机root权限                                  │       │
│  │ - 影响范围: 整个宿主机                                │       │
│  └──────────────────────────────────────────────────────┘       │
│                                                                  │
│  安全评分(CIS Docker Benchmark):                                 │
│  Rootless:  95/100 (推荐)                                       │
│  特权容器: 15/100 (强烈不推荐)                                   │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

安全配置对比

# Rootless安全Pod配置
apiVersion: v1
kind: Pod
metadata:
  name: rootless-secure
spec:
  securityContext:
    runAsNonRoot: true           # 必须
    runAsUser: 1000              # 非root用户
    fsGroup: 1000
    seccompProfile:
      type: RuntimeDefault
    sysctls:
    - name: net.ipv4.ip_unprivileged_port_start
      value: "0"
  containers:
  - name: app
    image: app:latest
    securityContext:
      allowPrivilegeEscalation: false
      readOnlyRootFilesystem: true
      capabilities:
        drop:
        - ALL
        # 仅添加必需能力
        add:
        - NET_BIND_SERVICE  # 仅绑定端口需要
---
# 特权容器配置(仅在绝对必要时使用)
apiVersion: v1
kind: Pod
metadata:
  name: privileged-only-when-necessary
  annotations:
    security.kubernetes.io/audit: "privileged-container-used"
spec:
  securityContext:
    runAsNonRoot: false
  containers:
  - name: app
    image: app:latest
    securityContext:
      privileged: true           # 危险!
      # 特权容器隐含以下权限:
      # - 所有能力(CAP_ALL)
      # - 访问所有设备
      # - 禁用seccomp
      # - 禁用AppArmor
      # - 可修改内核参数
      # - 可挂载任意文件系统

三、OCI规范深度解析

3.1 OCI三大规范

┌─────────────────────────────────────────────────────────────────┐
│                    OCI规范体系                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐          │
│  │ Image Spec  │   │ Runtime Spec│   │Distribution │          │
│  │  镜像规范    │   │  运行时规范  │   │  分发规范    │          │
│  └──────┬──────┘   └──────┬──────┘   └──────┬──────┘          │
│         │                  │                  │                  │
│         ▼                  ▼                  ▼                  │
│  ┌─────────────┐   ┌─────────────┐   ┌─────────────┐          │
│  │ 镜像格式    │   │ 容器生命周期│   │ 镜像推送/拉取│          │
│  │ 层/清单/索引│   │ 配置/根文件 │   │ 仓库API     │          │
│  └─────────────┘   └─────────────┘   └─────────────┘          │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

3.2 OCI镜像规范(Image Spec)

镜像结构
┌─────────────────────────────────────────────────────────────────┐
│                    OCI镜像结构                                    │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Image Index (多架构清单)                                        │
│  ├── mediaType: application/vnd.oci.image.index.v1+json        │
│  ├── manifests[]                                                │
│  │   ├── platform: linux/amd64 → Manifest A                    │
│  │   ├── platform: linux/arm64 → Manifest B                    │
│  │   └── platform: linux/s390x → Manifest C                    │
│  │                                                               │
│  Image Manifest (单架构清单)                                     │
│  ├── mediaType: application/vnd.oci.image.manifest.v1+json     │
│  ├── config → Config Blob                                       │
│  ├── layers[] → Layer Blobs                                     │
│  │   ├── layer 0 (基础层)                                       │
│  │   ├── layer 1 (依赖层)                                       │
│  │   └── layer 2 (应用层)                                       │
│                                                                  │
│  Image Config (配置)                                             │
│  ├── architecture: amd64                                        │
│  ├── os: linux                                                  │
│  ├── rootfs.diff_ids[]                                          │
│  ├── config.Cmd[]                                               │
│  └── config.Env[]                                               │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
镜像层存储结构
/var/lib/containerd/io.containerd.content.v1.content/blobs/sha256/
├── a1b2c3...  # Layer 0 (基础层tar+gzip)
├── d4e5f6...  # Layer 1 (依赖层tar+gzip)
├── g7h8i9...  # Layer 2 (应用层tar+gzip)
└── j0k1l2...  # Config JSON

3.3 OCI运行时规范(Runtime Spec)

容器生命周期状态机
┌──────────┐    create    ┌──────────┐    start    ┌──────────┐
│ Creating │────────────►│ Created  │────────────►│ Running  │
└──────────┘             └──────────┘             └──────────┘
                              │                        │
                              │ delete                 │ stop
                              ▼                        ▼
                         ┌──────────┐             ┌──────────┐
                         │ (deleted)│             │ Stopped  │
                         └──────────┘             └──────────┘
                                                      │
                                                      │ delete
                                                      ▼
                                                 ┌──────────┐
                                                 │ (deleted)│
                                                 └──────────┘
运行时配置结构(OCI Spec JSON)
{
  "ociVersion": "1.0.2",
  "process": {
    "terminal": true,
    "user": {"uid": 0, "gid": 0},
    "args": ["/bin/sh"],
    "env": ["PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin"],
    "cwd": "/",
    "capabilities": {
      "bounding": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"],
      "effective": ["CAP_AUDIT_WRITE", "CAP_KILL", "CAP_NET_BIND_SERVICE"]
    }
  },
  "root": {
    "path": "rootfs",
    "readonly": true
  },
  "hostname": "container",
  "mounts": [
    {"destination": "/proc", "type": "proc", "source": "proc"},
    {"destination": "/dev", "type": "tmpfs", "source": "tmpfs"},
    {"destination": "/sys", "type": "sysfs", "source": "sysfs"}
  ],
  "linux": {
    "namespaces": [
      {"type": "pid"},
      {"type": "network"},
      {"type": "ipc"},
      {"type": "uts"},
      {"type": "mount"}
    ],
    "seccomp": {
      "defaultAction": "SCMP_ACT_ERRNO",
      "syscalls": [{"names": ["read","write"], "action": "SCMP_ACT_ALLOW"}]
    }
  }
}

3.4 OCI分发规范(Distribution Spec)

仓库API核心端点
┌─────────────────────────────────────────────────────────────────┐
│                  OCI Distribution API                            │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  PUSH流程:                                                       │
│  1. POST /v2/<name>/blobs/uploads/     → 获取upload URL        │
│  2. PUT /v2/<name>/blobs/uploads/<uuid> → 上传层               │
│  3. PUT /v2/<name>/manifests/<ref>      → 上传清单             │
│                                                                  │
│  PULL流程:                                                       │
│  1. GET /v2/<name>/manifests/<ref>      → 获取清单             │
│  2. GET /v2/<name>/blobs/<digest>       → 下载层               │
│                                                                  │
│  其他:                                                           │
│  - GET /v2/_catalog                     → 仓库列表             │
│  - GET /v2/<name>/tags/list             → 标签列表             │
│  - DELETE /v2/<name>/manifests/<digest>  → 删除清单            │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

四、镜像分发原理

4.1 镜像拉取流程

┌─────────┐         ┌─────────┐         ┌─────────┐
│  Kubelet │         │containerd│         │ Registry│
└────┬────┘         └────┬────┘         └────┬────┘
     │                    │                    │
     │ CRI PullImage      │                    │
     │───────────────────►│                    │
     │                    │                    │
     │                    │ GET /manifests/tag │
     │                    │───────────────────►│
     │                    │                    │
     │                    │ Manifest JSON      │
     │                    │◄───────────────────│
     │                    │                    │
     │                    │ GET /blobs/digest  │
     │                    │ (逐层下载)         │
     │                    │───────────────────►│
     │                    │                    │
     │                    │ Layer Data         │
     │                    │◄───────────────────│
     │                    │                    │
     │                    │ 解压+组装rootfs    │
     │                    │                    │
     │ PullImage Response │                    │
     │◄───────────────────│                    │
     │                    │                    │

4.2 镜像优化策略

多阶段构建
# 构建阶段
FROM golang:1.21 AS builder
WORKDIR /app
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/server .

# 运行阶段
FROM gcr.io/distroless/static:nonroot
COPY --from=builder /app/server /server
USER nonroot:nonroot
ENTRYPOINT ["/server"]
镜像层缓存优化
# 差: 每次代码变更都重新安装依赖
COPY . /app
RUN npm install

# 好: 依赖层可缓存
COPY package.json package-lock.json /app/
RUN npm install
COPY . /app
镜像大小对比
基础镜像大小安全性适用场景
ubuntu:22.04~77MB通用开发
debian:slim~74MB通用生产
alpine:3.18~3MB中( musl)精简场景
distroless~2MB安全生产
scratch0MB最高静态编译

4.3 镜像安全扫描

# Trivy扫描
trivy image nginx:latest

# Grype扫描
grype nginx:latest

# Syft生成SBOM
syft nginx:latest -o spdx-json > sbom.json

# Cosign签名验证
cosign verify --key cosign.pub nginx:latest

五、containerd内部架构

5.1 containerd架构总览

┌─────────────────────────────────────────────────────────────────┐
│                    containerd架构                                 │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌─────────────────────────────────────────────────────────┐    │
│  │                     gRPC API                            │    │
│  │  (containerd daemon对外暴露的API)                        │    │
│  └────────────────────────┬────────────────────────────────┘    │
│                           │                                      │
│  ┌────────────────────────┼────────────────────────────────┐    │
│  │              containerd核心服务                          │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │    │
│  │  │ Metadata │ │ Content  │ │ Diff     │ │ Images   │  │    │
│  │  │ Store    │ │ Store    │ │ Service  │ │ Service  │  │    │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘  │    │
│  │  ┌──────────┐ ┌──────────┐ ┌──────────┐ ┌──────────┐  │    │
│  │  │ Containers│ │ Tasks   │ │ Events   │ │ Leases   │  │    │
│  │  │ Service  │ │ Service │ │ Service  │ │ Service  │  │    │
│  │  └──────────┘ └──────────┘ └──────────┘ └──────────┘  │    │
│  └─────────────────────────────────────────────────────────┘    │
│                           │                                      │
│  ┌────────────────────────┼────────────────────────────────┐    │
│  │                    Backend                              │    │
│  │  ┌──────────────────┐  ┌──────────────────┐            │    │
│  │  │   Snapshotter    │  │   Runtime        │            │    │
│  │  │   (overlayfs/    │  │   (runc/kata/    │            │    │
│  │  │    devmapper/    │  │    wasm)          │            │    │
│  │  │    native)       │  │                   │            │    │
│  │  └──────────────────┘  └──────────────────┘            │    │
│  └─────────────────────────────────────────────────────────┘    │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

5.2 核心子系统详解

Content Store(内容存储)
负责存储镜像的所有内容(blob)

/var/lib/containerd/io.containerd.content.v1.content/
├── blobs/
│   └── sha256/
│       ├── a1b2c3...  # 镜像层
│       └── d4e5f6...  # 配置JSON
└── ingest/            # 正在上传的内容
Snapshotter(快照管理器)
┌─────────────────────────────────────────────────────────────────┐
│                Snapshotter工作原理                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  镜像层(只读)          容器层(读写)                              │
│                                                                  │
│  Layer 3 ◄──────┐                                               │
│       ▲         │                                               │
│  Layer 2 ◄──┐   │    ┌──────────────────┐                      │
│       ▲     │   │    │  Upperdir (可写) │ ◄── 容器修改          │
│  Layer 1 ◄──┤   └────┤                  │                      │
│             │        │  Lowerdir (只读) │ ◄── 镜像层叠加        │
│  Base Layer─┘        └──────────────────┘                      │
│                              │                                  │
│                              ▼                                  │
│                        overlayfs mount                          │
│                                                                  │
│  Snapshot类型:                                                   │
│  - Committed: 只读快照(镜像层)                                  │
│  - Active: 可写快照(容器层)                                     │
│  - View: 只读视图(用于diff)                                     │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘
Snapshotter类型对比
Snapshotter文件系统特点适用场景
overlayfsoverlayfs默认、高性能通用
devmapperdevicemapper块设备生产稳定
nativebind-mount简单测试
zfszfs快照/校验ZFS存储
stargzoverlayfs+远程懒加载远程镜像
nydusRAFS按需加载大镜像加速

5.3 CRI插件架构

┌─────────────────────────────────────────────────────────────────┐
│                    CRI Plugin架构                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  Kubelet                                                        │
│      │                                                           │
│      │ CRI gRPC                                                  │
│      ▼                                                           │
│  ┌──────────────────────────────────────────────────────────┐   │
│  │                    CRI Service                           │   │
│  │  ┌────────────┐  ┌────────────┐  ┌────────────┐        │   │
│  │  │ImageService│  │RuntimeSvc  │  │  Event     │        │   │
│  │  │ PullImage  │  │CreateContainer│ │  Monitor  │        │   │
│  │  │ ListImages │  │StartContainer│ │           │        │   │
│  │  │ RemoveImage│  │ExecSync   │  │           │        │   │
│  │  └────────────┘  └────────────┘  └────────────┘        │   │
│  └──────────────────────────────────────────────────────────┘   │
│      │                    │                                       │
│      ▼                    ▼                                       │
│  ┌──────────┐      ┌──────────┐                                  │
│  │ containerd│      │  runc    │                                  │
│  │ Services  │      │ (shim)   │                                  │
│  └──────────┘      └──────────┘                                  │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

5.4 容器创建完整流程

Kubelet → CRI Plugin → containerd → shim → runc

详细步骤:
1. Kubelet调用CRI RuntimeService.CreateContainer
2. CRI插件调用containerd.CreateContainer
3. containerd创建container元数据
4. Kubelet调用CRI RuntimeService.StartContainer
5. CRI插件调用containerd.Tasks.Create
6. containerd启动containerd-shim-runc-v2
7. shim调用runc create
8. runc创建namespace、rootfs
9. shim调用runc start
10. 容器进程启动
11. shim监控容器进程
12. 事件回传至containerd→Kubelet

5.5 containerd-shim详解

┌─────────────────────────────────────────────────────────────────┐
│                   containerd-shim作用                             │
├─────────────────────────────────────────────────────────────────┤
│                                                                  │
│  ┌───────────┐    ┌───────────┐    ┌───────────┐              │
│  │containerd │    │   shim    │    │   runc    │              │
│  │ (daemon)  │    │ (per-container)│ │           │              │
│  └─────┬─────┘    └─────┬─────┘    └─────┬─────┘              │
│        │                │                 │                      │
│        │  gRPC/TTY      │  fork/exec      │                     │
│        │◄──────────────►│────────────────►│                     │
│        │                │                 │                      │
│                                                                  │
│  Shim职责:                                                       │
│  1. 解耦containerd与runc(容器退出不依赖daemon)                   │
│  2. 管理容器stdin/stdout/stderr                                  │
│  3. 报告容器退出状态                                             │
│  4. 支持容器热重启                                               │
│  5. 守护容器进程( reap子进程)                                    │
│                                                                  │
│  v2改进:                                                         │
│  - 单shim管理多个容器(容器组)                                    │
│  - 减少进程数                                                    │
│  - 更好的资源效率                                                │
│                                                                  │
└─────────────────────────────────────────────────────────────────┘

六、容器运行时对比

6.1 运行时层级关系

高层运行时 (CRI实现)
├── containerd  ←── Docker/Moby内部使用
├── CRI-O       ←── OpenShift/Kubernetes专用
└── Docker Engine(含containerd)

低层运行时 (OCI实现)
├── runc        ←── 默认OCI运行时
├── crun        ←── C语言实现,更快
├── kata-runtime←── VM隔离
├── gVisor(runsc)←── 用户态内核
└── wasmtime    ←── Wasm运行时

6.2 安全容器运行时对比

运行时隔离方式性能开销安全等级适用场景
runcnamespace+cgroup最低通用
kata硬件虚拟化高(20-30%)多租户/不可信负载
gVisor用户态内核中(5-15%)沙箱/不可信代码
Wasm沙箱隔离轻量/插件

参考资料

更多推荐