Root的危险性

docker的root权限一直是其遭受诟病的地方,docker的root权限有那么危险么?我们举个例子。

假如我们有一个用户,叫demo,它本身不具有sudo的权限,所以就有很多文件无法进行读写操作,比如/root目录它是无法查看的。

  1. [demo@docker-host ~]$ sudo ls /root
  2. [sudo] password for demo:
  3. demo is not in the sudoers file. This incident will be reported.
  4. [demo@docker-host ~]$

但是这个用户有执行docker的权限,也就是它在docker这个group里。

  1. [demo@docker-host ~]$ groups
  2. demo docker
  3. [demo@docker-host ~]$ docker image ls
  4. REPOSITORY TAG IMAGE ID CREATED SIZE
  5. busybox latest a9d583973f65 2 days ago 1.23MB
  6. [demo@docker-host ~]$

这时,我们就可以通过Docker做很多越权的事情了,比如,我们可以把这个无法查看的/root目录映射到docker container里,你就可以自由进行查看了。

  1. [demo@docker-host vagrant]$ docker run -it -v /root/:/root/tmp busybox sh
  2. / # cd /root/tmp
  3. ~/tmp # ls
  4. anaconda-ks.cfg original-ks.cfg
  5. ~/tmp # ls -l
  6. total 16
  7. -rw------- 1 root root 5570 Apr 30 2020 anaconda-ks.cfg
  8. -rw------- 1 root root 5300 Apr 30 2020 original-ks.cfg
  9. ~/tmp #

更甚至我们可以给我们自己加sudo权限。我们现在没有sudo权限

  1. [demo@docker-host ~]$ sudo vim /etc/sudoers
  2. [sudo] password for demo:
  3. demo is not in the sudoers file. This incident will be reported.
  4. [demo@docker-host ~]$

但是我可以给自己添加。

  1. [demo@docker-host ~]$ docker run -it -v /etc/sudoers:/root/sudoers busybox sh
  2. / # echo "demo ALL=(ALL) ALL" >> /root/sudoers
  3. / # more /root/sudoers | grep demo
  4. demo ALL=(ALL) ALL
  5. </pre>
  6. 然后退出containerbingo,我们有sudo权限了。
  7. <pre style="box-sizing: border-box; font-family: SFMono-Regular, Menlo, Monaco, Consolas, &quot;Liberation Mono&quot;, &quot;Courier New&quot;, Courier, monospace; font-size: 12px; white-space: pre; line-height: 1.4; margin: 0px; padding: 12px; display: block; overflow: auto;">[demo@docker-host ~]$ sudo more /etc/sudoers | grep demo
  8. demo ALL=(ALL) ALL
  9. [demo@docker-host ~]$

如何使用非root用户

我们准备两个Dockerfile,第一个Dockerfile如下:
app.py文件

  1. from flask import Flask
  2. app = Flask(__name__)
  3. @app.route('/')
  4. def hello_world():
  5. return 'Hello World!'

dockerfile

  1. FROM python:3.9.5-slim
  2. RUN pip install flask
  3. COPY app.py /src/app.py
  4. WORKDIR /src
  5. ENV FLASK_APP=app.py
  6. EXPOSE 5000
  7. CMD ["flask", "run", "-h", "0.0.0.0"]

假设构建的镜像名字为 flask-demo

第二个Dockerfile,使用非root用户来构建这个镜像,名字叫 flask-no-root Dockerfile如下:

  • 通过groupadduseradd创建一个flask的组和用户
  • 通过USER指定后面的命令要以flask这个用户的身份运行
  1. FROM python:3.9.5-slim
  2. RUN pip install flask && \
  3. groupadd -r flask && useradd -r -g flask flask && \
  4. mkdir /src && \
  5. chown -R flask:flask /src
  6. USER flask
  7. COPY app.py /src/app.py
  8. WORKDIR /src
  9. ENV FLASK_APP=app.py
  10. EXPOSE 5000
  11. CMD ["flask", "run", "-h", "0.0.0.0"]
  1. $ docker image ls
  2. REPOSITORY TAG IMAGE ID CREATED SIZE
  3. flask-no-root latest 80996843356e 41 minutes ago 126MB
  4. flask-demo latest 2696c68b51ce 49 minutes ago 125MB
  5. python 3.9.5-slim 609da079b03a 2 weeks ago 115MB

分别使用这两个镜像创建两个容器

  1. $ docker run -d --name flask-root flask-demo
  2. b31588bae216951e7981ce14290d74d377eef477f71e1506b17ee505d7994774
  3. $ docker run -d --name flask-no-root flask-no-root
  4. 83aaa4a116608ec98afff2a142392119b7efe53617db213e8c7276ab0ae0aaa0
  5. $ docker container ps
  6. CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
  7. 83aaa4a11660 flask-no-root "flask run -h 0.0.0.0" 4 seconds ago Up 3 seconds 5000/tcp flask-no-root
  8. b31588bae216 flask-demo "flask run -h 0.0.0.0" 16 seconds ago Up 15 seconds 5000/tcp flask-root