最近在推进生产环境Docker容器应用权限收敛控制,由于早期公司业务快速迭代容器是放开特权模式跑的,现在需要取消特权权限,按需放开应用所需权限,提高Docker生产环境安全性,参考 → Linux 提权-Docker 容器。
权限收敛调整影响涉及面很大,需要提前测试验证,保证各系统应用使用都不受影响,大体上去除特权模式后待测试功能点如下:
1、应用启动脚本及调用的第三方库功能验证
2、容器内其它工具命令及访问文件、系统权限验证
3、由于容器使用了NVIDIA GPU卡,还需验证GPU功能
4、应用各模块功能验证(需多方配合)
要取消Docker特权权限首先需要了解Docker容器安全机制。
Docker 容器与 LXC 容器非常相似,并且具有相似的安全特性,当您使用 docker run创建或启动容器时,Docker 服务为了防止黑客在控制容器后能够对宿主机进行攻击,提供了三个主要的隔离机制,其分别是Namespace 机制、Capabilities 机制和 CGroups 机制。
Capabilities 机制
Capabilities简单来说,就是指开放给进程的权限,比如允许进程可以访问网络、读取文件等。Docker容器本质上就是一个进程,默认情况下,Docker 会删除必须的 capabilities 外的所有 capabilities,可以在 Linux 手册页 中看到完整的可用 capabilities 列表。
下面是从 capabilities man page 中摘取的 Capabilites 列表:
Docker Capability | Linux Capability | 描述 |
---|---|---|
CHOWN | CAP_CHOWN | 修改文件所有者的权限 |
DAC_OVERRIDE | CAP_DAC_OVERRIDE | 忽略文件的 DAC 访问限制 |
KILL | CAP_KILL | 允许对不属于自己的进程发送信号 |
SYS_CHROOT | CAP_SYS_CHROOT | 允许使用 chroot() 系统调用 |
NET_BIND_SERVICE | CAP_NET_BIND_SERVICE | 允许绑定到小于 1024 的端口 |
SETUID | CAP_SETUID | 允许改变进程的 UID |
SETGID | CAP_SETGID | 允许改变进程的 GID |
FSETID | CAP_FSETID | 允许设置文件的 setuid 位 |
FOWNER | CAP_FOWNER | 忽略文件属主 ID 必须和进程用户 ID 相匹配的限制 |
SETFCAP | CAP_SETFCAP | 允许为文件设置任意的 capabilities |
SETPCAP | CAP_SETPCAP | 允许向其它进程转移能力以及删除其它进程的任意能力(只限init进程) |
NET_RAW | CAP_NET_RAW | 允许使用原始套接字 |
MKNOD | CAP_MKNOD | 允许使用 mknod() 系统调用 |
AUDIT_WRITE | CAP_AUDIT_WRITE | 将记录写入内核审计日志 |
NET_ADMIN | CAP_NET_ADMIN | 允许执行网络管理任务 |
AUDIT_CONTROL | CAP_AUDIT_CONTROL | 启用和禁用内核审计;改变审计过滤规则;检索审计状态和过滤规则 |
AUDIT_READ | CAP_AUDIT_READ | 允许通过 multicast netlink 套接字读取审计日志 |
BLOCK_SUSPEND | CAP_BLOCK_SUSPEND | 使用可以阻止系统挂起的特性 |
DAC_READ_SEARCH | CAP_DAC_READ_SEARCH | 忽略文件读及目录搜索的 DAC 访问限制 |
IPC_LOCK | CAP_IPC_LOCK | 允许锁定共享内存片段 |
IPC_OWNER | CAP_IPC_OWNER | 忽略 IPC 所有权检查 |
LEASE | CAP_LEASE | 允许修改文件锁的 FL_LEASE 标志 |
LINUX_IMMUTABLE | CAP_LINUX_IMMUTABLE | 允许修改文件的 IMMUTABLE 和 APPEND 属性标志 |
MAC_ADMIN | CAP_MAC_ADMIN | 允许 MAC 配置或状态更改 |
MAC_OVERRIDE | CAP_MAC_OVERRIDE | 覆盖 MAC(Mandatory Access Control) |
NET_BROADCAST | CAP_NET_BROADCAST | 允许网络广播和多播访问 |
SYS_ADMIN | CAP_SYS_ADMIN | 允许执行系统管理任务,如加载或卸载文件系统、设置磁盘配额等 |
SYS_BOOT | CAP_SYS_BOOT | 允许重新启动系统 |
SYS_MODULE | CAP_SYS_MODULE | 允许插入和删除内核模块 |
SYS_NICE | CAP_SYS_NICE | 允许提升优先级及设置其他进程的优先级 |
SYS_PACCT | CAP_SYS_PACCT | 允许执行进程的 BSD 式审计 |
SYS_PTRACE | CAP_SYS_PTRACE | 允许跟踪任何进程 |
SYS_RAWIO | CAP_SYS_RAWIO | 允许直接访问 /devport、/dev/mem、/dev/kmem 及原始块设备 |
SYS_RESOURCE | CAP_SYS_RESOURCE | 忽略资源限制 |
SYS_TIME | CAP_SYS_TIME | 允许改变系统时钟 |
SYS_TTY_CONFIG | CAP_SYS_TTY_CONFIG | 允许配置 TTY 设备 |
SYSLOG | CAP_SYSLOG | 允许使用 syslog() 系统调用 |
WAKE_ALARM | CAP_WAKE_ALARM | 允许触发一些能唤醒系统的东西(比如 CLOCK_BOOTTIME_ALARM 计时器) |
Docker 0.6版本以后支持在启动参数中增加 --privileged 选项为容器开启超级权限。
Docker支持Capabilities对于容器安全意义重大,因为在容器中我们经常会以root用户来运行,使用Capability限制后,容器中的 root 比真正的 root用户权限少得多。这就意味着,即使入侵者设法在容器内获取了 root 权限,也难以做到严重破坏或获得主机 root 权限。
Capabilities 提供了更细粒度的授权机制,它定义了主体对象能够进行的某一类操作。例如当一个容器的Web服务需要绑定 到80端口,但是80端口的绑定是需要ROOT权限的。而Docker为了防止 ROOT 权限滥用会通过 Capabilities 机制,给予该容器Web 服务对象 net_bind_service 的权限(其允许绑定到小于 1024 的端口)。
同样地Docker服务对容器中的ROOT权限用户添加了很多默认的限制,比如:拒绝所有的挂载操作、拒绝部分文件的操作(如修改文件所有者等)、拒绝内核模块加载;
虽然 Capabilities 可以最大程度解决容器安全问题, 但Capabilities对容器可进行操作的限制程度是难以把控的,如果设置过松会导致 Docker 容器影响宿主机系统,让 Docker 隔离失效。而如果设置过为严格的话会让容器以及容器内的服务功能受限,导致Docker容器无法正常运行。
所以在默认情况下,Docker 会采用白名单机制(白名单列表你可以在 Docker 源码中查看)进行限制,即只允许 Docker 容器拥有几个默认的能力。那有了白名单限制,即使攻击者成功拿到了容器中的 ROOT 权限,能够对宿主机造成的影响也相对较小,所以“Docker 逃逸”并不是一件不容易的事。
Docker特权权限与普通权限区别
Docker中的特权权限(privileged mode)和普通权限之间存在明显的区别。特权权限允许容器获得主机系统上的所有设备的根权限。这意味着容器可以修改App Arm和SELinux配置,并且可以在特权容器内安装新的Docker平台实例。另外,特权容器也可能导致容器逃逸(Container Escape)的安全问题,即攻击者通过特权容器内的漏洞或者权限提升,成功逃离容器并获取主机系统的权限。这种情况下,容器的隔离性受到破坏,容器内的恶意代码可能对主机系统造成严重影响。
特权容器中的 root 权限允许执行一些高级操作,包括但不限于:
访问主机文件系统:特权容器中的 root 用户可以访问主机文件系统中的所有文件和目录。
修改主机内核设置:特权容器可以修改主机的内核设置,这可能导致潜在的安全风险。
访问主机设备:特权容器可以访问主机上的所有设备,包括磁盘和网络设备。
修改 AppArmor 和 SELinux 配置:特权容器可以绕过安全模块的限制,对系统进行更改。
当我们在docker run时指定了--privileded 选项,docker其实会完成两件事情:
获取系统root用户所有能力赋值给容器;
扫描宿主机所有设备文件挂载到容器内。
普通权限容器的使用可以通过限制容器的权限范围,从而减少潜在的安全风险。相比之下,特权容器可能会导致潜在的安全漏洞,因为它们允许容器获得主机系统的全部权限,包括CAP_SYS_ADMIN等所有可用权限。为了最大程度地保护主机系统,建议尽量避免使用特权容器,而是使用普通权限容器并采取相应的安全措施来最小化潜在的特权升级风险
特权容器和普通权限容器之间的主要区别在于对主机系统权限的访问范围。特权容器中的 root 权限拥有对主机系统的完全控制,而普通权限容器受到更严格的限制,从而降低了潜在的安全风险。因此,生产环境中不建议使用特权容器,而是建议采用普通权限容器,并通过用户命名空间重映射等方式来最小化潜在的安全风险。
Docker特权模式的安全风险及补救措施:
Docker特权模式(--privileged)可以极大地提升容器的权限,使其几乎具备与宿主机同等的权限。这种模式带来了一些潜在的安全问题,主要包括:
1、访问所有设备:
在特权模式下,容器可以访问宿主机的所有设备,包括硬盘、网络接口、USB设备等。这可能导致敏感数据泄露或硬件被滥用。
2、内核模块加载:
特权容器可以加载和卸载宿主机的内核模块,这可能导致内核被破坏或者加载恶意模块,危及系统安全。
3、修改系统配置:
特权容器可以修改宿主机的系统配置文件,如网络设置、系统安全配置等,可能导致宿主机的安全配置被篡改。
4、进程和文件系统访问:
特权容器可以访问和控制宿主机的进程以及文件系统,可能导致宿主机上的进程被恶意终止或文件被恶意篡改或删除。
5、提权攻击:
如果特权容器被攻陷,攻击者可以利用该容器对宿主机进行提权攻击,从而完全控制宿主机。
为了规范Docker特权模式的使用,减少潜在的安全风险,可以采取以下措施:
1、最小权限原则:
仅在确有必要时才使用特权模式。尽量避免为容器授予超过其实际需求的权限。
2、使用能力控制(Capability):
利用Docker的--cap-add和--cap-drop选项,只授予容器所需的特定能力(Capabilities),而不是赋予完全的特权。
3、限制设备访问:
使用--device选项,仅将必要的设备挂载到容器中,而不是所有设备。
4、资源限制:
使用cgroups和namespaces等Linux内核特性对容器的资源(CPU、内存、IO等)进行限制,防止资源滥用。
5、监控和日志:
部署监控系统和日志系统,实时监控容器的行为和访问日志,及时发现和响应异常行为。
6、网络隔离:
使用Docker的网络隔离功能(如bridge网络、overlay网络等),将容器与宿主机以及其他容器进行隔离,减少网络攻击面。
7、定期更新和补丁:
定期更新Docker引擎和底层操作系统,及时应用安全补丁,修复已知的漏洞。
通过严格控制和监控特权模式的使用,可以显著降低Docker容器对宿主机的安全风险,保障系统的整体安全性。
针对1、2项测试验证相关记录:
1、taskset chrt:使用--cpuset-cpus选项来指定容器可以使用的CPU核心范围,--cpuset-cpus="0-7",这样就可以在非特权容器中使用taskset和chrt命令 2、调用系统及外部工具或命令:cp mv chmod find md5sum mkdir cat sync flock jobs curl chown bash roslaunch python python3 dmesg addr2line date perf... 3、修改系统内核参数: 将/proc/sys bind到容器里面 mount --bind /proc/sys/vm /host_proc/sys/vm 直接bind /proc/sys/vm报错,容器构建时报错 Error response from daemon: OCI runtime create failed: container_linux.go:349: starting container process caused "process_linux.go:449: container init caused \"rootfs_linux.go:58: mounting \\\"/proc/sys/vm\\\" to rootfs \\\"/data/docker/overlay2/ad600fb922c18c991758c0fc16b82082bcc7f1db629052b6d4628d16e6a72dc6/merged\\\" at \\\"/proc/sys/vm\\\" caused \\\"\\\\\\\"/data/docker/overlay2/ad600fb922c18c991758c0fc16b82082bcc7f1db629052b6d4628d16e6a72dc6/merged/proc/sys/vm\\\\\\\" cannot be mounted because it is inside /proc\\\"\"": unknown echo 0 > /proc/sys/vm/swappiness echo 500 > /proc/sys/vm/watermark_scale_factor ... ===================================> echo 0 > /host_proc/sys/vm/swappiness echo 500 > /host_proc/sys/vm/watermark_scale_factor ... 4.dmesg无法正常使用,dmesg命令需要访问系统内核日志,需要放开 CAP_SYSLOG 权限
compose.yaml配置文件修改如下:
version: '3.x' services: default: image: chegva.com:v1 restart: always # privileged: true # 去除特权权限 cpuset: "0-7" # 绑定CPU cap_add: - SYS_NICE # 修改进程优先级权限 - NET_ADMIN # 修改系统网络权限 - CAP_SYSLOG # 获取系统内核日志(如dmesg使用) volumes: - ... - /proc/sys/vm:/host_proc/sys/vm # 修改系统内核参数 - /sys/fs/cgroup:/sys/fs/cgroup # 使用系统cgroup权限
篇幅有点长了,针对第三点:GPU在Docker容器中的测试验证下次再写。
参考: