如何防止对我的Docker容器进行根访问

时间:2019-08-30 18:08:35

标签: shell docker docker-compose dockerfile hardening

我正在加强我们的docker镜像,对此我已经有点了解了。话虽如此,我目前的步骤是防止用户以root用户身份运行容器。对我来说,这就是“当用户运行'docker exec -it my-container bash'时,他将是没有特权的用户”(如果我错了,请纠正我)。

当我通过docker-compose启动我的容器时,运行的启动脚本需要以root身份运行,因为它处理导入证书和已挂载文件(在外部创建并通过卷挂载查看)。完成之后,我希望该用户成为以后任何访问的“ appuser”。这个问题似乎很符合我的要求,但是我使用的是docker-compose,而不是docker run:How to disable the root access of a docker container?

这似乎很相关,因为启动命令不同于tomcat。我们正在运行一个Spring Boot应用程序,该应用程序以一个简单的'java -jar jarFile'启动,该映像是使用maven的dockerfile-maven-plugin构建的。话虽如此,我应该在运行该用户之前还是之后将其更改为非特权用户?

我相信在Dockerfile而不是启动脚本中更改用户可以做到这一点...但是,它将不会以root用户身份运行启动脚本,因此会激怒需要root的调用。我也曾用ENTRYPOINT弄乱了,但在那儿可能做错了。同样,在yml文件中使用“ user:”似乎可以使start.sh脚本以该用户而不是root用户的身份运行,因此无法正常工作。

Dockerfile:

FROM parent/image:latest

ENV APP_HOME                            /apphome
ENV APP_USER                            appuser
ENV APP_GROUP                           appgroup

# Folder containing our application, i.e. jar file, resources, and scripts.
# This comes from unpacking our maven dependency
ADD target/classes/app ${APP_HOME}/

# Primarily just our start script, but some others
ADD target/classes/scripts /scripts/

# Need to create a folder that will be used at runtime
RUN mkdir -p ${APP_HOME}/data && \
    chmod +x /scripts/*.sh && \
    chmod +x ${APP_HOME}/*.*

# Create unprivileged user
RUN groupadd -r ${APP_GROUP} && \
    useradd -g ${APP_GROUP} -d ${APP_HOME} -s /sbin/nologin  -c "Unprivileged User" ${APP_USER} && \
    chown -R ${APP_USER}:${APP_GROUP} ${APP_HOME}

WORKDIR $APP_HOME

EXPOSE 8443

CMD /opt/scripts/start.sh

start.sh脚本:

#!/bin/bash

# setup SSL, modify java command, etc

# run our java application
java -jar "boot.jar"

# Switch users to always be unprivileged from here on out? 
# Whatever "hardening" wants...  Should this be before starting our application?
exec su -s "/bin/bash" $APP_USER

app.yml文件:

version: '3.3'

services:
  app:
    image: app_image:latest
    labels:
      c2core.docker.compose.display-name: My Application
      c2core.docker.compose.profiles: a_profile
    volumes:
      - "data_mount:/apphome/data"
      - "cert_mount:/certs"
    hostname: some-hostname
    domainname: some-domain
    ports:
    - "8243:8443"
    environment:
      - some_env_vars
    depends_on:
    - another-app
    networks:
      a_network:
        aliases:
          - some-network
networks:
  a_network:
    driver: bridge
volumes:
  data_mount:
  cert_mount:

docker-compose shell脚本:

docker-compose -f app.yml -f another-app.yml $@

我希望的是,任何试图在内部访问该容器的人都将以appuser而不是root身份这样做。目标是防止某人弄乱他们不应该做的事情(即docker本身)。

正在发生的事情是,脚本将在应用程序启动后更改用户(通过echo命令证明),但似乎并未得到维护。如果我执行它,我仍然是root。

4 个答案:

答案 0 :(得分:3)

正如David所提到的,一旦有人可以访问docker套接字(通过API或使用docker CLI),这通常意味着他们可以对您的主机进行root访问。使用这种访​​问来运行具有主机名称空间和卷安装的特权容器的琐碎事情,使攻击者几乎可以做任何事情。

当您需要使用以root用户身份运行的步骤来初始化容器时,我建议在su之类的地方推荐gosu,因为su不是为容器设计的,它将使进程继续运行作为根pid。确保您execgosu的调用会消除以root用户身份运行的任何内容。但是,您启动容器的用户与docker exec所使用的用户相同,并且由于您需要以root用户身份启动,因此您的exec将以root用户身份运行,除非您使用-u标志覆盖它

您通常可以采取其他步骤来锁定Docker:

  1. 使用user namespaces。它们是在整个守护程序上定义的,要求您销毁所有容器,然后再次提取图像,因为uid映射会影响图像层的存储。用户名称空间抵消了docker使用的uid,因此容器内的根不是主机上的根,而在容器内,您仍然可以绑定到编号较低的端口并运行管理活动。

  2. 考虑authz plugins。我知道有两个开放策略代理和Twistlock,尽管我不知道二者是否会限制您使用docker exec命令的用户。他们可能要求您为用户提供连接到docker的证书,而不是直接授予他们访问docker套接字的权限,因为该套接字在接收到的API请求中没有包含任何用户详细信息。

  3. 考虑rootless docker。这仍然是实验性的,但是由于docker不是以root身份运行,因此它无权返回主机以执行root活动,从而减轻了以root身份运行容器时出现的许多问题。

答案 1 :(得分:1)

从本质上讲,您不能阻止对容器的根级别访问。

任何可以运行任何Docker命令的人始终可以运行以下三个命令中的任何一个:

# Get a shell, as root, in a running container
docker exec -it -u 0 container_name /bin/sh

# Launch a new container, running a root shell, on some image
docker run --rm -it -u 0 --entrypoint /bin/sh image_name

# Get an interactive shell with unrestricted root access to the host
# filesystem (cd /host/var/lib/docker)
docker run --rm -it -v /:/host busybox /bin/sh

通常,最佳实践是以非root用户身份运行容器,或者在Dockerfile中使用USER指令,或者在入口点脚本中运行类似gosu的内容,如下所示。但是,面对有足够特权的特权用户,您不能阻止根访问。

答案 2 :(得分:0)

当docker通常从一台主机运行时,您可以执行一些步骤。
在从接受的主机挂载的目录中寻找秘密,以确保它不是从其他主机运行的。

更改主机上用户的.bashrc,以便他们在登录后立即开始运行docker。当您的用户需要在主机上执行其他操作时,请为他们提供一个没有docker访问权限的帐户,并将他们sudo授予具有docker访问权限的特殊用户(或将startdocker脚本与setuid标志)。

使用您制作并强化的脚本启动docker,例如startserver

#!/bin/bash

settings() {
   # Add mount dirs. The homedir in the docker will be different from the one on the host.
   mountdirs="-v /mirrored_home:/home -v /etc/dockercheck:/etc/dockercheck:ro"
   usroptions="--user $(id -u):$(id -g) -v /etc/passwd:/etc/passwd:ro"   
   usroptions="${usroptions} -v/etc/shadow:/etc/shadow:ro -v /etc/group:/etc/group:ro"
}

# call function that fills special variables
settings

image="my_image:latest"

docker run -ti --rm ${usroptions} ${mountdirs} -w $HOME --entrypoint=/bin/bash "${image}"

添加变量--env HOSTSERVER=${host}无助于加强,在另一台服务器上可以添加--env HOSTSERVER=servername_that_will_be_checked

当用户登录到主机时,将调用startserver并启动docker。在对启动服务器的调用之后,将exit添加到.bash_rc

答案 3 :(得分:0)

不知道这项工作是否可行,但是您可以尝试。使用有限的执行命令允许用户/组的sudo访问。 Sudo配置仅允许执行docker-cli。创建名称为docker-cli的Shell脚本,其中包含运行docker命令的内容,例如docker "$@"。在此文件中,检查参数并在执行docker的exec或attach命令时强制用户提供--user或-u开关。还要确保验证用户不要提供带有-u root的开关。例如

sudo docker-cli exec -it containerid sh (failed)

sudo docker-cli exec -u root ... (failed)

sudo docker-cli exec -u mysql ... (Passed)

您甚至可以限制用户可以在此shell脚本中运行的docker命令