不要以root用户启动docker进程
默认docker是没有开启user namespace的(开启需要修改docker配置文件),也就是说默认容器和宿主机用的是同一个user namespace,linux内核只认uid和gid,容器root(uid=0)用户和宿主机root(uid=0)是同一个,并没有隔离
- 如果不是必须以root用户运行,就不要以root用户运行。
- 如果root用户逃逸容器,很危险。我们很容易地错误地假设容器是“完全”隔离的,在一个容器中做的事情,不会影响到其他容器,也不会影响到宿主机。就像我们在云供应商上租用一个虚拟机(ECS)不会担心会被其他人的虚拟机影响到。但是相比虚拟机的隔离,容器的隔离是比较弱的。这就意味着,在一个容器内做的危险操作,可能会影响到其他容器,甚至影响到宿主机。这种突破容器的隔离性的行为也叫容器逃逸(container escape)。如果容器内以root用户运行,就会使得恶意攻击变得更加容易。
分析宿主机UID和容器UID关系
执行docker的用户,和真正运行起来的docker用户不一样
宿主机marc用户执行docker run命令启动docker进程,不指定-u指定用户,默认会用容器里的用户,通常是root命令启动docker进程
marc@server:~$ docker run -d ubuntu:latest sleep infinity
92c57a8a4eda60678f049b906f99053cbe3bf68a7261f118e411dee173484d10
marc@server:~$ ps aux | grep sleep
root 15638 0.1 0.0 4380 808 ? Ss 19:49 0:00 sleep infinity
- 在宿主机上查看docker进程
- 所属用户是root(uid=0)。。。这个权限变大了,所以容器里执行命令不建议用root,他的uid会映射到宿主机的root uid
- 在容器内登录用户,指定id显示当前用户是root
- 默认是root(uid=0)
指定docker进程用户,再分析用户uid关系
宿主机用uid=1001(宿主机上用户名是marc)启动docker进程,在宿主机查看docker进程,是marc用户
FROM ubuntu:latest
RUN useradd -r -u 1001 -g appuser appuser
USER appuser
ENTRYPOINT [“sleep”, “infinity”]
marc@server:~$ docker run -d test
8ad0cd43592e6c4314775392fb3149015adc25deb22e5e5ea07203ff53038073
marc@server:~$ ps aux | grep sleep
marc 16507 0.3 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity
容器里面查看当前登录容器的用户,uid=1001(容器内用户名是appuser)
marc@server:~$ docker exec -it 8ad0 /bin/bash
appuser@8ad0cd43592e:/$ ps aux | grep sleep
appuser 1 0.0 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity
- 总结:
- 默认docker是没有开启user namespace的(开启需要修改docker配置文件)
- 在没开启user namespace情况下,默认容器和宿主机用的是同一个user namespace,uid都是共享的,只是uid在不同的操作系统(容器操作系统rootfs和宿主机操作系统)对应的username不一样
- uid=1001(容器内用户名是appuser)
- uid=1001(宿主机上用户名是marc)
- 为什么可以这样?
- 因为username不是Linux kernel的一部分,只是属于外部工具,在rootfs上面
- That’s because the username (and group names) that show up in common linux tools aren’t part of the kernel, but are managed by external tools (/etc/passwd, LDAP, Kerberos, etc). So, you might see different usernames, but you can’t have different privileges for the same uid/gid, even inside different containers
指定docker启动用户的两种方式:
方式一:在dockerfile上指定
在Dockerfile中创建用户和用户组,并指定以该用户和用户组运行。
指定容器USER为appuser
FROM ubuntu:latest
RUN useradd -r -u 1001 -g appuser appuser
USER appuser
ENTRYPOINT [“sleep”, “infinity”]
宿主机启动docker进程,docker进程用户1001(marc)
marc@server:~$ docker run -d test
8ad0cd43592e6c4314775392fb3149015adc25deb22e5e5ea07203ff53038073
marc@server:~$ ps aux | grep sleep
marc 16507 0.3 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity
查看容器内登录用户:uid=1001(appuser)
marc@server:~$ docker exec -it 8ad0 /bin/bash
appuser@8ad0cd43592e:/$ ps aux | grep sleep
appuser 1 0.0 0.0 4380 668 ? Ss 20:02 0:00 sleep infinity
方式二:在docker run -u上指定
$ docker run --user www-data busybox id
uid=33(www-data) gid=33(www-data)
docker run -u(--user)[user:group] 或 --group-add 参数方式
-u表示,创建容器时,创建对应用户和用户组,也可以指定uid.(如果用户已存在则不创建)