概述
docker容器运行时,默认情况下容器内进程的运行用户就是docker host上的root用户,这样运行时如果将host中的某些目录挂载到容器中时,容器内的进程拥有这些目录的所有权限,这样时不安全的。
解决方法有两种,一种是使用非root用户运行容器,另一种就是使用下面讲的user namespace方式。
Linux的user namespace可以对运行的进程做用户隔离,在这些进程不感知的情况下,限制它们对系统资源的访问。可以通过Linux的user namespace功能,将容器内的root用户映射为docker host中的低权限用户。
docker启用user namespace
docker在1.10(2016-02-04)版本中才实现了使用user namespace的功能,称之为 userns-remap
首先在docker host中创建用户和组
1
2
3
4[root@localhost ~]# groupadd -g 5000 dockertest
[root@localhost ~]# useradd -u 5000 -g dockertest dockertest
[root@localhost ~]# id dockertest
uid=5000(dockertest) gid=5000(dockertest) groups=5000(dockertest)修改docker host中的 /etc/subuid 和 /etc/subgid 配置
1
2
3
4
5
6[root@localhost ~]# cat /etc/subuid
dockertest:5000:1 # 容器中root用户(uid=0)映射为docker host中的uid为5000的用户
dockertest:100000:65535 # 容器中的用户 1 ~ 65536 映射为 host中的 uid 为 100000 ~ 100000+65535
[root@localhost ~]# cat /etc/subgid
dockertest:5000:1 # 同subuid
dockertest:100000:65535 # 同subuid
也可以直接配置dockertest:100000:65536,这样的话,容器的root映射为host的uid=100000的用户
修改
/etc/docker/daemon.json
文件,增加"userns-remap":"dockertest"
配置,然后重启docker服务启动容器进行检查
1
2
3
4
5
6
7
8
9
10
11
12
13
14[root@localhost ~]# docker run -d --rm centos:8 sleep 300
152a7eed420e3d84eefebf1fadc1f1f9d8cfa2fd607d59c03a806d822f5e57d3
[root@localhost ~]# docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
152a7eed420e centos:8 "sleep 300" 6 seconds ago Up 3 seconds jovial_sutherland
[root@localhost ~]# ps -ef |grep -i sleep
dockert+ 12387 12371 0 20:20 ? 00:00:00 /usr/bin/coreutils --coreutils-prog-shebang=sleep /usr/bin/sleep 300
[root@localhost ~]# cat /proc/12387/uid_map
0 5000 1 # 将host 上的 5000 用户映射为容器内的 0(root)用户
1 100000 65535 # 将host 上的 100000 用户映射为容器内的 1 用户
[root@localhost ~]# cat /proc/12387/gid_map
0 5000 1
1 100000 65535
[root@localhost ~]#
docker使用userns-remap时,在docker_home目录下会自动创建一个5000.5000(根据实际情况会有变化)的目录
在修改daemon.json文件时,可以将userns-remap的值设置为已经存在的用户。也可以指定为默认值(default),如果指定为 default,那么会自动创建用户和组 dockremap。
如果使用default配置,RHEL/centos不会自动将 dockremap 添加到 /etc/subuid 和 /etc/subgid 中,需要手动添加。
容器中禁用namespace映射
当docker daemon启用了user namespace后,所有启动的容器默认都会使用user namespace功能。
此时如果想要禁用容器的user namespace(如想要启动一个具有特权的容器),可以在docker create/docker run/docker exec命令中增加 --userns=host
选项实现。
使用 --userns=host
选项时,不会为该容器进行用户映射,但是由于容器之间共享read-only(image) layers,容器的文件系统所有者仍然会映射为daemon中配置userns-remap用户。这样可能会导致容器内某些程序运行时出现一些意外,For instance sudo (which checks that its binaries belong to user 0) or binaries with a setuid flag。
docker使用user namespace的限制
当docker启用user namespace时,会与docker的下面的一些特性无法兼容:
- sharing PID or NET namespaces with the host(–pid=host or –network=host)
- external (volume or storage) drivers which are unaware or incapable of using daemon user mappings
- Using the –privileged mode flag on docker run without also specifying –userns=host。(docker run中使用了–privileged但是没有使用–userns=host)
常见问题
检查Linux内核是否开启了user namespace功能
- 首先确认内核版本,linux是在内核3.8开始才引入了user namespace功能
查看内核编译选项
1
2[root@localhost ~]# cat /boot/config-$(uname -r) |grep -i config_user_ns
CONFIG_USER_NS=y