---
title: 容器运行配置规则
description: "为了防止通过耗尽系统资源引发拒绝服务（DoS）攻击，可使用特定的命令行参数被来启用一些资源限制。"
url: https://www.hikunpeng.com/document/detail/zh/kunpengboostkithistory/240RC2/armnative/kunpengcpskbox_20_0110.html
sourcePath: /source/zh/kunpengboostkithistory/240RC2/armnative/kunpengcpskbox_20_0110.html
indexId: 5f23b7a56665f8e39c84453ccc1c3178dbefdcd21d991c7f3211841688d8cfe178
---
# 容器运行配置规则

#### 启用cgroups能力进行恰当的资源限制

为了防止通过耗尽系统资源引发拒绝服务（DoS）攻击，可使用特定的命令行参数被来启用一些资源限制。

Kbox的base_box脚本中通过docker启动参数“--cpuset-cpus”和“--memory”限制CPU和内存的使用。由于Kbox使用ext4文件系统，其不支持“--storage-opt”参数，因此Kbox未限制存储使用。


#### 限制运行容器的Linux内核Capability能力

在默认情况下，Docker会通过有限的Linux内核Capability启动容器。也就是说，任何进程都会被授予必要的Capability，而不是root访问。通过Linux内核Capability，在通常需要root权限的几乎所有特定区域，进程都无需作为root运行。使用非默认配置文件的用户可以通过Docker来增加或删减Capability。这样，通过删减Capability，Docker会更安全；而增加Capability，Docker安全性会降低。

- Kbox的base_box脚本中通过以下方式默认关闭所有Capability再按需增加必要的，其中{"Capability 1", ..., "Capability n"}集合具体值可查询base_box脚本。
  1 docker run --cap-drop=ALL --cap-add={"Capability 1", ..., "Capability n"}

  可通过以下命令查看是否只有必要的Capability被添加。 1 docker ps --quiet --all |xargs docker inspect --format '{{ .Id }}:CapAdd={{ .HostConfig.CapAdd }}CapDrop={{ .HostConfig.CapDrop }}'

- 在Android容器运行时需要开启SYS_ADMIN Capability，且在apparmor中打开mount能力，容器具有mount能力后可以通过挂载cgroup、proc、sysfs等文件系统进行容器逃逸，建议用户在apparmor中对敏感文件系统进行过滤或对宿主机OS、内核进行安全加固。


#### 限制容器通过SUID/GUID位获得额外权限

限制容器通过SUID或GUID位获取额外权限。SUID和GUID程序在受攻击导致任意代码执行（如缓冲区溢出）时将非常危险，因为它们将可以运行在进程文件所有者或组的上下文中。

建议通过以下步骤删除系统中不需要的SUID和GUID程序。

1. 找到系统中不需要的SUID和GUID程序。
  1 2 find / -perm -4000 -exec ls -l {} \; 2>/dev/null find / -perm -2000 -exec ls -l {} \; 2>/dev/null

2. 移除SUID和GUID文件权限，下列命令中的“filename”和“directory”请根据实际情况修改。
  1 2 sudo chmod u-s filename sudo chmod -R g-s directory


#### 不要在容器上挂载主机系统敏感目录

主机系统敏感目录（包括根目录、/boot、/dev、/etc、/lib、/proc、/sys、/usr）不能作为容器卷挂载，尤其是在读写模式下。如果在读写模式下挂载，敏感目录中的文件可能会被更改。这些更改可能没有必要，还可能会带来安全问题，侵害docker主机。

Kbox的base_box脚本中将“/proc”、“/sys”、“/dev”目录下子目录的挂载方式修改为只读。

可通过以下命令确认，结果不匹配“Source:(/|/boot|/dev|/etc|/lib|/proc|/sys|/usr)\s+.*RW:true”，则修改成功。

```
docker ps --quiet --all| xargs docker inspect --format '{{ .Id }}: Volumes={{ .Mounts }}' 2>/dev/null
```


#### 容器中只运行必需的软件，不以root权限运行不受信的应用

容器中若使用不必要的软件，可能会加大容器的攻击面，同时也违背了最小和精简容器镜像的概念。因此，不要为容器安装或运行任何不必要的软件。


#### 只打开容器需要的端口

容器可以只使用Dockerfile中为其镜像定义的端口运行，也可以任意传递运行时参数以打开端口列表。此外，随着时间的推移，Dockerfile可能会经历各种更改，暴露的端口列表可能与容器中运行的应用程序相关，也可能不相关。打开不需要的端口会加大容器和容器化应用程序的攻击面。因此不要暴露不需要的端口。

建议修改方式：

启动容器时，使用“--publish”或“-p”选项明确指定特定容器实例所需的端口。例如：

```
docker run --interactive --tty --publish 5000 --publish 5001 --publish 5002 my_container /bin/bash
```

Kbox的base_box脚本中通过以下方式指定容器实例所需的端口。

```
local PORT
for PORT in ${PORTS[@]}; do
    RUN_OPTION+=" -p $PORT "
done
```


#### 设置容器CPU适当优先级

CPU时间默认在各容器之间平均分配。如有需要，可以使用CPU共享特性控制CPU时间在容器实例之间的分配。CPU共享功能将容器进行优先级排序，并禁止优先级低的容器频繁地占用CPU资源，确保优先级高的容器得到更好的服务。

Kbox的base_box脚本中通过启动参数“--cpu-shares”管理容器之间的CPU份额。


#### 将传入的容器流量绑定到特定主机接口

Docker容器默认可以连接到外部世界，但外部世界不能连接到容器。每个对外连接显示都是源自主机的IP地址。只允许通过主机上的特定外部接口接触容器服务。如果主机上有多个网络接口，则容器可以接受任何网络接口上暴露的端口连接。这可能不是期望的结果，也可能不受保护。很多时候，特定接口会对外暴露，并且在这些接口上运行诸如入侵检测，入侵防御，防火墙，负载平衡等服务以筛选传入的公共流量。因此，不应接受任何接口上的传入连接，只接受来自特定外部接口的传入连接。这里主机接口通指网络接口，是主机与外部系统的连接通道，而主机端口是指该主机接口对应的TCP/UDP端口，接口一般包含IP地址和端口。

建议修改方式：

将容器端口绑定到所需主机端口上特定的主机接口。如下所示，将容器端口80绑定到49153上的主机端口，并且只接受来自10.2.3.4外部接口的传入链接。

```
docker run --detach --publish 10.2.3.4:49153:80 nginx
```

实现此安全加固措施可修改Kbox的base_box脚本中“-p”选项内容，配置格式请参考以下示例，并根据实际情况自行配置可用IP地址：

```
RUN_OPTION+=" -p XXX.XXX.XXX.XXX:$PORT "
```


#### 将容器的根文件系统挂载为只读

容器的根文件系统应该被视为“黄金镜像”，避免任何写操作。应明确定义专门用于写操作的容器卷。

将容器的根文件系统挂载为只读可能会出现兼容性问题，请按照实际业务需求评估是否需要采纳该建议。


#### 不要禁用默认seccomp配置文件

默认seccomp配置文件是一个指定可以执行哪些系统调用的白名单，进程可利用seccomp过滤来为传入的系统调用指定过滤器。Docker默认的seccomp配置文件在白名单基础上工作，允许311个系统调用而阻止其他所有的调用。大量的系统调用暴露给每个用户空间进程，其中许多系统调用在整个进程周期中都未使用。大多数应用程序根本不需要这些系统调用，因此可以使用精简版系统调用。精简版系统调用减小了暴露给应用程序的总内核面，从而提高了应用程序的安全性。

在Ubuntu操作系统中，seccomp配置文件默认开启。除非想修改或使用修改的seccomp配置文件，否则不需做任何操作。

在openEuler系统方案中，Android容器运行时需要禁用seccomp配置文件（seccomp=unconfined）。用户需要评估应用场景是否允许禁用seccomp配置文件以及禁用的风险，建议禁用seccomp配置文件后对宿主机OS、内核进行安全加固。


#### 限制文件句柄和fork进程数量

攻击者可以在容器内使用单个命令启动fork炸弹。该fork炸弹能使整个系统崩溃，需要重启主机才能使崩溃系统再次运行。同时攻击者可以开启大量文件句柄，耗尽文件句柄资源，造成拒绝服务攻击。具体设置fork进程、文件句柄的阈值，根据产品实际业务情况决定。

实现此安全加固措施可以修改Kbox的base_box脚本，修改方式请参考以下示例。该阈值需要客户根据应用场景进行合理的设置，数值不正确可能会导致容器无法使用。

```
RUN_OPTION+=" --pids-limit XXX --files-limit XXX "
```


#### 不要使用Docker默认的网络桥接接口Docker0

使用Docker用户自定义的容器网络，而不使用Docker默认的网络桥接接口docker0。docker0作为默认的网络接口，在没有配置相应网络过滤前，容易遭受ARP欺骗和MAC泛洪攻击。注意：Docker默认是运行在docker0桥接的。

建议修改方式：

1. 删除旧网桥。在执行此操作之前，先删除服务器上所有容器。
  1 2 3 sudo systemctl stop docker sudo ip link set dev docker0 down sudo brctl delbr docker0

  若提示Command 'brctl' not found，则先进行安装bridge-utils。 Ubuntu系统请使用命令： apt install bridge-utils -y openEuler系统请使用命令： yum install bridge-utils -y

2. 创建一个名称为“bridge0”的新网桥，以下示例仅作为格式参考，请根据实际情况自行配置可用网段，以保证容器连接网络正常。
  1 2 3 sudo brctl addbr bridge0 sudo ip addr add XXX.XXX.XXX.XXX/XX dev bridge0 sudo ip link set dev bridge0 up

  上述可用网段可参考默认网桥接口docker0的配置。输入命令查询docker0配置。 ip addr show docker0 以下图回显为例，网段应设置为172.17.0.1/16。 可通过以下命令确认创建的新网桥“bridge0”详细信息。 1 ip addr show bridge0

3. 添加新网桥的配置信息。

  a. 打开“/etc/docker/daemon.json”文件。

```
vim /etc/docker/daemon.json
```


  b. 按“i”进入编辑模式，在文件中添加属性“"bridge": "bridge0"”，格式如下。

```
{
"debug": true,
"ipv6": true,
"fixed-cidr-v6": "2001:db8::/64",
"bridge": "bridge0"
}
```


  c. 按“Esc”键，输入:wq!，按“Enter”保存并退出编辑。
    若“/etc/docker/daemon.json”文件不存在，则自行创建该文件。并添加“"bridge":"bridge0"”，遵循json格式。 1 2 touch /etc/docker/daemon.json vim /etc/docker/daemon.json

4. 重启Docker服务。
  重启Docker服务前需要确保没有其他容器运行，如果有需要清理。

  1 2 systemctl daemon-reload systemctl restart docker

  每次重启服务器后，都需要先执行2重新创建新网桥“bridge0”，才能重启Docker服务。 重启Docker服务后，可能会重新拉起默认的网络桥接接口“docker0”，因此在执行4后，需要通过以下命令检查当前环境是否还存在“docker0”。 1 ip addr show docker0 若仍然能够查询到“docker0”，则需要通过以下命令手动删除。 1 2 sudo ip link set dev docker0 down sudo brctl delbr docker0
