近期Docker 19.03中发布了一个重要的特性 “Rootless Container支持”。趁着五一假期,快速验证一下。本文参考了Experimenting with Rootless Docker 一文的内容,并且补充了更多的细节和上手内容。
Rootless容器背景与架构Docker和Kubernetes已经成为企业IT架构的基础设施,其自身安全越来越被关注。Docker基于Linux操作系统提供了应用虚拟化能力,通过namespace, cgroup实现了资源的隔离和配额约束。Docker Engine是一个典型的 Client-Server 结构:
Docker Client (TCP/Unix Socket) -> Docker Daemon (Parent/Child Processes) -> Container
由于Linux需要特权用户来创建namespace,挂载分层文件系统等,所以 Docker Daemon 一直以来是以root用户来运行的。这也导致了有Docker访问权限的用户可以通过连接Docker Engine获取root权限,而且可以绕开系统的审计能力对系统进行攻击。这阻碍了容器在某些场景的应用:比如在高性能计算领域,由于传统的资源管理和调度系统需要非特权用户来运行容器,社区实现了另外的容器运行时Singularity 。
Moby社区的 Akihiro Suda,为Docker Engine和Buildkit贡献了rootless容器支持,让Docker Engine以非特权用户方式运行,更好地复用Linux的安全体系。
注意:
- 目前rootless容器还在实验阶段,cgroups 资源控制, apparmor安全配置, checkpoint/restore等能力还不支持。
- 目前只有Ubuntu提供了在rootless模式下对overlay fs的支持,由于安全顾虑,这个方案尚未得到upstream的支持。其他操作系统需要利用VFS存储驱动,有一定性能影响,并不适合I/O密集型应用。
Rootless容器有几个核心技术
首先是利用 user namespaces 将容器中的root用户uid/gid映射到宿主机的非特权用户范围内。Docker Engine已经提供了 --userns-remap 标志支持了相关能力,提升了容器的安全隔离性。Rootless容器在此之上,让Docker daemon也运行在重映射的用户名空间中。
其次,虽然Linux中的非特权用户可以在用户名空间中创建网络名空间,并且执行iptables规则管理和tcpdump等操作,然而非特权用户无法在宿主机和容器之间创建veth pairs, 这也意味着容器没有外网访问能力。为了解决这个问题,Akihiro 利用用户态的网络“SLiRP”,通过一个TAP设备连接到非特权用户名空间,为容器提供外网连接能力。其架构如下
相关细节请参考,slirp4netns项目
环境准备本文在一台 CentOS 7.6的虚拟机上进行的验证
创建用户
$ useradd moby
$ passwd moby
将新建用户添加到 sudoers 组
usermod -aG wheel moby
切换到非特权用户
$ su - moby
$ id
uid=1000(moby) gid=1000(moby) groups=1000(moby),10(wheel)
进行uid/gid映射配置
echo "moby:100000:65536" | sudo tee /etc/subuid
echo "moby:100000:65536" | sudo tee /etc/subgid
安装Rootless Docker
curl -sSL https://get.docker.com/rootless | sh
如果第一次安装,需要安装所需软件包
$ curl -sSL https://get.docker.com/rootless | sh
# Missing system requirements. Please run following commands to
# install the requirements and run this installer again.
# Alternatively iptables checks can be disabled with SKIP_IPTABLES=1
cat
关注
打赏
