Namespace

Namespace简介

Linux Namespace 是 Linux 内核提供的一个功能,可以实现系统资源的隔离。目前共有六种namespace:

类型 系统调用参数 内核版本
Mount Namespace CLONE_NEWNS 2.4.19
UTS Namespace CLONE_NEWUTS 2.6.19
IPC Namespace CLONE_NEWIPC 2.6.19
PID Namespace CLONE_NEWPID 2.6.24
Network Namespace CLONE_NEWNET 2.6.29
User Namespace CLONE_NEWUSER 3.8

可以通过三个系统调用的方式:

  • clone, 创建新的进程和新的namespace,新创建的进程 attach 到新创建的 namespace
  • unshare,不创建新的进程,创建新的 namespace 并把当前进程 attach 上
  • setns, attach 进程到已有的 namespace 上

shell 也提供了一个和系统调用同名的 unshare 命令可以非常简单的创建 namespace。

1
sudo unshare --fork --pid --mount-proc bash

六种类型说明

  1. UTS(UNIX Timesharing System) Namespace 可以用来隔离 nodename 和 domainname 两个系统标识。在 UTS Namespace 中,每个 Namespace 可以有自己的 hostname。

  2. IPC(Interprocess Communication) Namespace 用来隔离 System V IPC 和 POSIX message queues。每一个 IPC Namespace 都有自己的 System V IPC 和 POSIX message queue。

  3. PID(Process ID) Namespace 可以用来隔离进程 ID。同一个进程在不同的 PID Namespace 中可以拥有不同的 PID。在 Docker Container 中,使用 ps -ef 可以看到启动容器的进程 PID 为 1,但是在宿主机上,该进程却又有不同的 PID。

  4. Mount Namespace 用来隔离各个进程看到的挂载点视图。在不同的 Namespace 中,看到的挂载点文件系统层次是不一样的。在 Mount Namespace 中调用 mountunmount 仅仅会影响当前 Namespace 内的文件系统,而对全局文件系统是没有影响的。

  5. User Namespace 主要是隔离用户的用户组 ID。也就是说,一个进程的 User ID 和 Group ID 在 User Namespace 内外可以是不同的。比较常用的是,在宿主机上以一个非 root 用户运行创建一个 User Namespace,然后在 User Namespace 中被映射为了 root 用户。*这意味着这个进程在 User Namespace 中有 root 权限,但是在宿主机上却没有 root 权限。 *

  6. Network Namespace 用来隔离网络设置、IP 地址和端口号等网络栈的 Namespace。Network Namespace 可以让每个容器拥有自己独立的网络设备,而且容器内的应用可以绑定到自己的端口,每个 Namespace 的端口都不会有冲突。在宿主机搭建网桥后,就能很方便地实现容器之间的通信。

Cgroups

简介

Linux Namespace 帮助进程隔离出自己的单独空间,而 Cgroups 则可以限制每个空间的大小。 Linux cgroups 的全称是 Linux Control Groups,它是 Linux 内核的特性,主要作用是限制、记录和隔离进程组(process groups)使用的物理资源(cpu、memory、IO 等)

Cgroups 从设计之初使命就很明确,为进程提供资源控制,它主要的功能包括:

  • 资源限制:限制进程使用的资源上限,比如最大内存、文件系统缓存使用限制
  • 优先级控制:不同的组可以有不同的优先级,比如 CPU 使用和磁盘 IO 吞吐
  • 审计:计算 group 的资源使用情况,可以用来计费
  • 控制:挂起一组进程,或者重启一组进程

cgroups 核心概念

前面说过,cgroups 是用来对进程进行资源管理的,因此 cgroup 需要考虑如何抽象这两种概念:进程和资源,同时如何组织自己的结构。cgroups 中有几个非常重要的概念:

  • task:任务,对应于系统中运行的一个实体,一般是指进程
  • subsystem:子系统,具体的资源控制器(resource class 或者 resource controller),控制某个特定的资源使用。比如 CPU 子系统可以控制 CPU 时间,memory 子系统可以控制内存使用量
  • cgroup:控制组,一组任务和子系统的关联关系,表示对这些任务进行怎样的资源管理策略
  • hierarchy:层级树,一系列 cgroup 组成的树形结构。每个节点都是一个 cgroup,cgroup 可以有多个子节点,子节点默认会继承父节点的属性。系统中可以有多个 hierarchy

虽然 cgroups 支持 hierarchy,允许不同的子资源挂到不同的目录,但是多个树之间有各种限制,增加了理解和维护的复杂性。在实际使用中,所有的子资源都会统一放到某个路径下(比如 ubuntu16.04 的 /sys/fs/cgroup/),因此本文并不详细介绍多个树的情况,感兴趣的可以参考 RedHat 的这篇文档。

子资源系统(Resource Classes or SubSystem)

目前有下面这些资源子系统:

  • Block IO(blkio):限制块设备(磁盘、SSD、USB 等)的 IO 速率
  • CPU Set(cpuset):限制任务能运行在哪些 CPU 核上
  • CPU Accounting(cpuacct):生成 cgroup 中任务使用 CPU 的报告
  • CPU (CPU):限制调度器分配的 CPU 时间
  • Devices (devices):允许或者拒绝 cgroup 中任务对设备的访问
  • Freezer (freezer):挂起或者重启 cgroup 中的任务
  • Memory (memory):限制 cgroup 中任务使用内存的量,并生成任务当前内存的使用情况报告
  • Network Classifier(net_cls):为 cgroup 中的报文设置上特定的 classid 标志,这样 tc 等工具就能根据标记对网络进行配置
  • Network Priority (net_prio):对每个网络接口设置报文的优先级
  • perf_event:识别任务的 cgroup 成员,可以用来做性能分析

Hierarchy

Linux 进程之间组成一棵树的结构,每个进程(除了 init 根进程之外)都有一个父进程,子进程创建之后会继承父进程的一些属性(比如环境变量,打开的文件描述符等)。

和进程模型类似,只不过 cgroups 是一个森林结构。

使用 cgroups

cgroup 内核功能比较有趣的地方是它没有提供任何的系统调用接口,而是对 linux vfs 的一个实现,因此可以用类似文件系统的方式进行操作。

使用 cgroups 的方式有几种:

  • 使用 cgroups 提供的虚拟文件系统,直接通过创建、读写和删除目录、文件来控制 cgroups
  • 使用命令行工具,比如 libcgroup 包提供的 cgcreate、cgexec、cgclassify 命令
  • 使用 rules engine daemon 提供的配置文件
  • 当然,systemd、lxc、docker 这些封装了 cgroups 的软件也能让你通过它们定义的接口控制 cgroups 的内容

查看 cgroups 挂载信息

在 ubuntu 16.04 的机器上,cgroups 已经挂载到文件系统上了,可以通过 mount 命令查看:

1
root@PEK1000251892:~# mount -t cgroup
2
cgroup on /sys/fs/cgroup/systemd type cgroup (rw,nosuid,nodev,noexec,relatime,xattr,release_agent=/lib/systemd/systemd-cgroups-agent,name=systemd)
3
cgroup on /sys/fs/cgroup/net_cls,net_prio type cgroup (rw,nosuid,nodev,noexec,relatime,net_cls,net_prio)
4
cgroup on /sys/fs/cgroup/cpu,cpuacct type cgroup (rw,nosuid,nodev,noexec,relatime,cpu,cpuacct)
5
cgroup on /sys/fs/cgroup/hugetlb type cgroup (rw,nosuid,nodev,noexec,relatime,hugetlb,release_agent=/run/cgmanager/agents/cgm-release-agent.hugetlb)
6
cgroup on /sys/fs/cgroup/cpuset type cgroup (rw,nosuid,nodev,noexec,relatime,cpuset,clone_children)
7
cgroup on /sys/fs/cgroup/freezer type cgroup (rw,nosuid,nodev,noexec,relatime,freezer)
8
cgroup on /sys/fs/cgroup/perf_event type cgroup (rw,nosuid,nodev,noexec,relatime,perf_event,release_agent=/run/cgmanager/agents/cgm-release-agent.perf_event)
9
cgroup on /sys/fs/cgroup/pids type cgroup (rw,nosuid,nodev,noexec,relatime,pids,release_agent=/run/cgmanager/agents/cgm-release-agent.pids)
10
cgroup on /sys/fs/cgroup/devices type cgroup (rw,nosuid,nodev,noexec,relatime,devices)
11
cgroup on /sys/fs/cgroup/blkio type cgroup (rw,nosuid,nodev,noexec,relatime,blkio)
12
cgroup on /sys/fs/cgroup/memory type cgroup (rw,nosuid,nodev,noexec,relatime,memory)

如果没有的话,也可以通过以下命令来把想要的 subsystem mount 到系统中:

1
root@PEK1000251892:~# mount mount -t cgroup -o cpu,cpuset,memory cpu_and_mem /cgroup/cpu_and_mem

上述命令表示把 cpu、cpuset、memory 三个子资源 mount 到 /cgroup/cpu_and_mem 目录下。

每个 cgroup 目录下面都会有描述该 cgroup 的文件,除了每个 cgroup 独特的资源控制文件,还有一些通用的文件:

  • tasks:当前 cgroup 包含的任务(task)pid 列表,把某个进程的 pid 添加到这个文件中就等于把进程移到该 cgroup
  • cgroup.procs:当前 cgroup 中包含的 thread group 列表,使用逻辑和 tasks 相同
  • notify_on_release:0 或者 1,是否在 cgroup 销毁的时候执行 notify。如果为 1,那么当这个 cgroup 最后一个任务离开时(退出或者迁移到其他 cgroup),并且最后一个子 cgroup 被删除时,系统会执行 release_agent 中指定的命令
  • release_agent:需要执行的命令

创建 cgroup

创建 cgroup,可以直接用 mkdir 在对应的子资源中创建一个目录:

1
root@PEK1000251892:~# mkdir /sys/fs/cgroup/cpu/mycgroup
2
root@PEK1000251892:~# ls /sys/fs/cgroup/cpu/mycgroup
3
cgroup.clone_children  cpuacct.stat   cpuacct.usage_percpu  cpu.cfs_quota_us  cpu.stat           tasks
4
cgroup.procs           cpuacct.usage  cpu.cfs_period_us     cpu.shares        notify_on_release

上面命令在 cpu 子资源中创建了 mycgroup,创建 cgroup 之后,目录中会自动创建需要的文件。

删除 cgroup

删除子资源,就是删除对应的目录:

1
root@PEK1000251892:~# rmdir /sys/fs/cgroup/cpu/mycgroup/

删除之后,如果 tasks 文件中有进程,它们会自动迁移到父 cgroup 中。

设置 cgroup 参数

设置 group 的参数就是直接往特定的文件中写入特定格式的内容,比如要限制 cgroup 能够使用的 CPU 核数:

1
root@PEK1000251892:~# echo 0-1 > /sys/fs/cgroup/cpuset/mycgroup/cpuset.cpus

把进程加入到 cgroup

要把某个已经运行的进程加入到 cgroup,可以直接往需要的 cgroup tasks 文件中写入进程的 PID:

1
root@PEK1000251892:~# echo 2358 > /sys/fs/cgroup/memory/mycgroup/tasks

在 cgroup 中运行进程

如果想直接把进程运行在某个 cgroup,但是运行前还不知道进程的 Pid 应该怎么办呢?

我们可以利用 cgroup 的继承方式来实现,因为子进程会继承父进程的 cgroup,因此我们可以把当前 shell 加入到要想的 cgroup:

1
root@PEK1000251892:~# echo $$ > /sys/fs/cgroup/cpu/mycgroup/tasks

上面的方案有个缺陷,运行完之后原来的 shell 还在 cgroup 中。如果希望进程运行完不影响当前使用的 shell,可以另起一个临时的 shell:

1
sh -c "echo \$$ > /sys/fs/cgroup/memory/mycgroup/tasks & & stress -m 1"

把进程移动到 cgroup

如果想要把进程移动到另外一个 cgroup,只要使用 echo 把进程 PID 写入到 cgroup tasks 文件中即可,原来 cgroup tasks 文件会自动删除该进程。

Docker使用cgroup

默认情况下,Docker 启动一个容器后,会在 /sys/fs/cgroup目录下的各个资源目录下生成以容器 ID 为名字的目录(group),比如:

1
/sys/fs/cgroup/cpu/docker/03dd196f415276375f754d51ce29b418b170bd92d88c5e420d6901c32f93dc14

此时 cpu.cfs_quota_us 的内容为 -1,表示默认情况下并没有限制容器的 CPU 使用。在容器被 stopped 后,该目录被删除。

运行命令 docker run -d --name web41 --cpu-quota 25000 --cpu-period 100 --cpu-shares 30 training/webapp python app.py 启动一个新的容器,结果:

1
root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_quota_us
2
25000
3
root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat tasks
4
3704
5
root@devstack:/sys/fs/cgroup/cpu/docker/06bd180cd340f8288c18e8f0e01ade66d066058dd053ef46161eb682ab69ec24# cat cpu.cfs_period_us
6
2000

Docker 会将容器中的进程的 ID 加入到各个资源对应的 tasks 文件中。表示 Docker 也是以上面的机制来使用 cgroups 对容器的 CPU 使用进行限制。

相似地,可以通过 docker runmem 相关的参数对容器的内存使用进行限制:

1
    --cpuset-mems string          MEMs in which to allow execution (0-3, 0,1)
2
    --kernel-memory string        Kernel memory limit
3
-m, --memory string               Memory limit
4
    --memory-reservation string   Memory soft limit
5
    --memory-swap string          Swap limit equal to memory plus swap: '-1' to enable unlimited swap
6
    --memory-swappiness int       Tune container memory swappiness (0 to 100) (default -1)

比如docker run -d --name web42 --blkio-weight 100 --memory 10M --cpu-quota 25000 --cpu-period 2000 --cpu-shares 30 training/webapp python app.py

1
root@devstack:/sys/fs/cgroup/memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat memory.limit_in_bytes
2
10485760
3
root@devstack:/sys/fs/cgroup/blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410# cat blkio.weight
4
 100

目前 docker 已经几乎支持了所有的 cgroups 资源,可以限制容器对包括 network,device,cpu 和 memory 在内的资源的使用,比如:

1
root@devstack:/sys/fs/cgroup# find -iname ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
2
./net_prio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
3
./net_cls/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
4
./systemd/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
5
./hugetlb/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
6
./perf_event/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
7
./blkio/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
8
./freezer/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
9
./devices/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
10
./memory/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
11
./cpuacct/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
12
./cpu/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410
13
./cpuset/docker/ec8d850ebbabaf24df572cb5acd89a6e7a953fe5aa5d3c6a69c4532f92b57410

Capbilities

capbilities查看

在上一篇文章中介绍了capbilities了,实际是一种把root权限细分的技术,现在介绍下docker中的capbilities的使用。

列出系统支持的capability使用命令 capsh --print ,查看dockerd进程所有capbilities:

1
root@PEK1000251892:~# cat /proc/`pidof dockerd`/status | grep Cap
2
CapInh: 0000000000000000
3
CapPrm: 0000003fffffffff
4
CapEff: 0000003fffffffff
5
CapBnd: 0000003fffffffff
6
CapAmb: 0000000000000000

解码

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

和getpcaps得到结果一样

1
root@PEK1000251892:~# getpcaps `pidof dockerd`
2
Capabilities for `116548': = cap_chown,cap_dac_override,cap_dac_read_search,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_linux_immutable,cap_net_bind_service,cap_net_broadcast,cap_net_admin,cap_net_raw,cap_ipc_lock,cap_ipc_owner,cap_sys_module,cap_sys_rawio,cap_sys_chroot,cap_sys_ptrace,cap_sys_pacct,cap_sys_admin,cap_sys_boot,cap_sys_nice,cap_sys_resource,cap_sys_time,cap_sys_tty_config,cap_mknod,cap_lease,cap_audit_write,cap_audit_control,cap_setfcap,cap_mac_override,cap_mac_admin,cap_syslog,cap_wake_alarm,cap_block_suspend,37+ep

Docker默认capbilities

Docker 能调整容器中的进程针对主机上的 OS 功能的访问授权,这些功能访问授权称为 capability。 Docker 在创建容器时,会默认去除一组 capability,包括:

  • SETPCAP: 修改进程的 capability
  • SYS_MODULE: 插入/删除内核模块
  • SYS_RAWIO: 修改内核内存
  • SYS_PACCT: 配置进程的记账
  • SYS_NICE: 修改进程的优先级
  • SYS_RESOURCE: 覆盖资源的限制
  • SYS_TIME: 修改系统时钟
  • SYS_TTY_CONFIG: 配置 TTY 设备
  • AUDIT_WRITE: 写审计日志
  • AUDIT_CONTROL: 配置审计子系统
  • MAC_OVERRIDE: 忽略内核 MAC 策略
  • MAC_ADMIN: 配置 MAC 设置信息
  • SYSLOG: 修改内核的 print 行为
  • NET_ADMIN: 配置网络
  • SYS_ADMIN: 表示系统管理的全部功能

Docker为了确保容器的安全,仅仅支持了其中的14项基本的 Capabilities,现在,我们不妨来看看这些 Capabilities 到底有哪些,它们分别是: CAP_CHOWNCAP_DAC_OVERRIDECAP_FSETIDCAP_MKNODFOWNERNET_RAWSETGIDSETUIDSETFCAPSETPCAPNET_BIND_SERVICESYS_CHROOTKILLAUDIT_WRITE 。 在这 14 项中几乎没有一项涉及到系统管理权限,比如 Docker 容器的 root 用户不具备 CAP_SYS_ADMIN,磁盘限额操作、mount 操作、创建进程新命名空间等均无法实现;比如由于没有 CAP_NET_ADMIN,网络方面的配置管理也将受到管制。因此,默认情况下,Docker 容器中的 root 用户并没有以往我们想象得那么能力超群,Docker 依然对其存在限制,这样设计的出发点之一自然是安全。

添加容器的 capability 用 --cap-add,去除容器的 capability 用 --cap-drop。 Linux 文档中的所有 capability 名都是以 CAP_ 开头的全部大写字母,但是这里用其不带前缀的小字版本。例子:

1
$ docker run --rm -u nobody \
2
    ubuntu:latest \
3
    /bin/bash -c "capsh --print | grep net_raw"
4
5
Current: = 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+i
6
    Bounding set =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
7
8
$ docker run --rm -u nobody \
9
    --cap-drop net_raw \ # drop NET_RAW capability
10
    ubuntu:latest \
11
    /bin/bash -c "capsh --print | grep net_raw" # no output
12
13
$ docker run --rm -u nobody \
14
    ubuntu:latest \
15
    /bin/bash -c "capsh --print | grep sys_admin" # no output
16
17
$ docker run --rm -u nobody \
18
    --cap-add sys_admin \
19
    ubuntu:latest \
20
    /bin/bash -c "capsh --print | grep sys_admin"
21
22
urrent: = cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_admin,cap_mknod,cap_audit_write,cap_setfcap+i
23
Bounding set =cap_chown,cap_dac_override,cap_fowner,cap_fsetid,cap_kill,cap_setgid,cap_setuid,cap_setpcap,cap_net_bind_service,cap_net_raw,cap_sys_chroot,cap_sys_admin,cap_mknod,cap_audit_write,cap_setfcap
24
hp

seccomp

使用

SeccompSecure computing mode的缩写,它是Linux内核提供的一个操作,用于限制一个进程可以执行的系统调用。当然,我们需要有一个配置文件来指明进程到底可以执行哪些系统调用,不可以执行哪些系统调用。

在Docker中,它使用Seccomp来限制一个容器可以执行的系统调用。

默认情况下,Seccomp会禁止容器执行64位Linux系统的313个系统调用的44个。我找不到这个Seccomp的默认配置文件在哪,可能是写在了源码中。

我们下面来描述如何使用Seccomp

1
$ grep CONFIG_SECCOMP= /boot/config-$(uname -r)
2
CONFIG_SECCOMP=y

首先,创建一个配置文件:/home/ygy/seccomp/profile.json,其内容为:

1
{
2
    "defaultAction": "SCMP_ACT_ALLOW",
3
    "syscalls": [
4
        {
5
            "name": "chmod",
6
            "action": "SCMP_ACT_ERRNO"
7
        }
8
    ]
9
}

在上面的这个配置文件中,默认情况下,我们允许容器执行全部的系统调用.但是,禁止它执行chmod这个系统调用.

然后,我们用这个Seccomp配置文件来启动一个Docker容器:

1
docker run --rm -it --security-opt seccomp:/home/ygy/seccomp/profile.json busybox chmod 400 /etc/hosts

结果如下:

1
chmod: /etc/hosts: Operation not permitted

使用docker inspect查看容器详细信息,有如下输出:

1
"SecurityOpt": [
2
               "seccomp:     
3
                 {"defaultAction":"SCMP_ACT_ALLOW",
4
                 "syscalls":[{"name":"chmod","action":"SCMP_ACT_ERRNO"}]}"
5
           ],

我们也可以在run一个容器的时候,通过--security-opt seccomp:unconfined参数来允许容器执行全部的系统的调用。

1
docker run --rm -it --security-opt seccomp:unconfined busybox chmod 400 /etc/hosts

默认策略

docker seccomp使用白名单策机制,默认的策略列表: https://github.com/moby/moby/blob/master/profiles/seccomp/default.json

一些重要的系统调用如下:(不完整列表)

Syscall Description
acct Accounting syscall which could let containers disable their own resource limits or process accounting. Also gated by CAP_SYS_PACCT.
add_key Prevent containers from using the kernel keyring, which is not namespaced.
bpf Deny loading potentially persistent bpf programs into kernel, already gated by CAP_SYS_ADMIN.
clock_adjtime Time/date is not namespaced. Also gated by CAP_SYS_TIME.
clock_settime Time/date is not namespaced. Also gated by CAP_SYS_TIME.
clone Deny cloning new namespaces. Also gated by CAP_SYS_ADMIN for CLONE_* flags, except CLONE_USERNS.
create_module Deny manipulation and functions on kernel modules. Obsolete. Also gated by CAP_SYS_MODULE.
delete_module Deny manipulation and functions on kernel modules. Also gated by CAP_SYS_MODULE.
finit_module Deny manipulation and functions on kernel modules. Also gated by CAP_SYS_MODULE.
get_kernel_syms Deny retrieval of exported kernel and module symbols. Obsolete.
get_mempolicy Syscall that modifies kernel memory and NUMA settings. Already gated by CAP_SYS_NICE.
init_module Deny manipulation and functions on kernel modules. Also gated by CAP_SYS_MODULE.
ioperm Prevent containers from modifying kernel I/O privilege levels. Already gated by CAP_SYS_RAWIO.
iopl Prevent containers from modifying kernel I/O privilege levels. Already gated by CAP_SYS_RAWIO.
kcmp Restrict process inspection capabilities, already blocked by dropping CAP_PTRACE.
kexec_file_load Sister syscall of kexec_load that does the same thing, slightly different arguments. Also gated by CAP_SYS_BOOT.
kexec_load Deny loading a new kernel for later execution. Also gated by CAP_SYS_BOOT.
keyctl Prevent containers from using the kernel keyring, which is not namespaced.
lookup_dcookie Tracing/profiling syscall, which could leak a lot of information on the host. Also gated by CAP_SYS_ADMIN.
mbind Syscall that modifies kernel memory and NUMA settings. Already gated by CAP_SYS_NICE.
mount Deny mounting, already gated by CAP_SYS_ADMIN.
move_pages Syscall that modifies kernel memory and NUMA settings.
name_to_handle_at Sister syscall to open_by_handle_at. Already gated by CAP_DAC_READ_SEARCH.
nfsservctl Deny interaction with the kernel nfs daemon. Obsolete since Linux 3.1.
open_by_handle_at Cause of an old container breakout. Also gated by CAP_DAC_READ_SEARCH.
perf_event_open Tracing/profiling syscall, which could leak a lot of information on the host.
personality Prevent container from enabling BSD emulation. Not inherently dangerous, but poorly tested, potential for a lot of kernel vulns.
pivot_root Deny pivot_root, should be privileged operation.
process_vm_readv Restrict process inspection capabilities, already blocked by dropping CAP_PTRACE.
process_vm_writev Restrict process inspection capabilities, already blocked by dropping CAP_PTRACE.
ptrace Tracing/profiling syscall, which could leak a lot of information on the host. Already blocked by dropping CAP_PTRACE. Blocked in Linux kernel versions before 4.8 to avoid seccomp bypass.
query_module Deny manipulation and functions on kernel modules. Obsolete.
quotactl Quota syscall which could let containers disable their own resource limits or process accounting. Also gated by CAP_SYS_ADMIN.
reboot Don’t let containers reboot the host. Also gated by CAP_SYS_BOOT.
request_key Prevent containers from using the kernel keyring, which is not namespaced.
set_mempolicy Syscall that modifies kernel memory and NUMA settings. Already gated by CAP_SYS_NICE.
setns Deny associating a thread with a namespace. Also gated by CAP_SYS_ADMIN.
settimeofday Time/date is not namespaced. Also gated by CAP_SYS_TIME.
stime Time/date is not namespaced. Also gated by CAP_SYS_TIME.
swapon Deny start/stop swapping to file/device. Also gated by CAP_SYS_ADMIN.
swapoff Deny start/stop swapping to file/device. Also gated by CAP_SYS_ADMIN.
sysfs Obsolete syscall.
_sysctl Obsolete, replaced by /proc/sys.
umount Should be a privileged operation. Also gated by CAP_SYS_ADMIN.
umount2 Should be a privileged operation. Also gated by CAP_SYS_ADMIN.
unshare Deny cloning new namespaces for processes. Also gated by CAP_SYS_ADMIN, with the exception of unshare --user.
uselib Older syscall related to shared libraries, unused for a long time.
userfaultfd Userspace page fault handling, largely needed for process migration.
ustat Obsolete syscall.
vm86 In kernel x86 real mode virtual machine. Also gated by CAP_SYS_ADMIN.
vm86old In kernel x86 real mode virtual machine. Also gated by CAP_SYS_ADMIN.

不使用seccomp

1
$ docker run --rm -it --security-opt seccomp=unconfined debian:jessie \
2
    unshare --map-root-user --user sh -c whoami

AppArmor和Selinux

docker支持apparmor和selinux,默认不启用selinux,启用apparmor。 AppArmor 是一个 Linux 内核安全模块,可用于限制主机操作系统上运行的进程的功能。每个进程都可以拥有自己的安全配置文件。安全配置文件用来允许或禁止特定功能,例如网络访问或文件读/写/执行权限。

加载和卸载profiles

加载一个新的profile

1
$ apparmor_parser -r -W /path/to/your_profile

docker运行自定义的apparmor策略

1
$ docker run --rm -it --security-opt apparmor=your_profile hello-world

卸载一个

1
$ apparmor_parser -R /path/to/profile

默认策略

Docker默认策略生成模板 https://github.com/moby/moby/blob/master/profiles/apparmor/template.go

参考:

https://zhuanlan.zhihu.com/p/67586925

https://zhuanlan.zhihu.com/p/55099839

https://chuanleiguo.com/2018/08/05/Docker-Namespace-Cgroup/

https://cizixs.com/2017/08/25/linux-cgroup/

https://zhuanlan.zhihu.com/p/98920705

https://www.atjiang.com/limiting-risk-with-isolation-in-docker/