如何阻止对Docker容器的根访问 [英] How do I prevent root access to my docker container

查看:145
本文介绍了如何阻止对Docker容器的根访问的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I am working on hardening our docker images, which I already have a bit of a weak understanding of. With that being said, the current step I am on is preventing the user from running the container as root. To me, that says "when a user runs 'docker exec -it my-container bash', he shall be an unprivileged user" (correct me if I'm wrong).

当我通过docker-compose启动容器时,运行的启动脚本需要以root用户身份运行,因为它处理导入证书和已挂载文件(在外部创建并通过卷挂载查看)。完成之后,我希望该用户成为以后任何访问的 appuser。这个问题似乎与我要找的东西非常匹配,但是我使用的是docker-compose,而不是docker run:如何禁用Docker容器的根访问权限?

When I start up my container via docker-compose, the start script that is run needs to be as root since it deals with importing certs and mounted files (created externally and seen through a volume mount). After that is done, I would like the user to be 'appuser' for any future access. This question seems to match pretty well what I'm looking for, but I am using docker-compose, not docker run: How to disable the root access of a docker container?

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

This seems to be relevant, as the startup command differs from let's say tomcat. We are running a Spring Boot application that we start up with a simple 'java -jar jarFile', and the image is built using maven's dockerfile-maven-plugin. With that being said, should I be changing the user to an unprivileged user before running that, or still after?

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

I believe changing the user inside of the Dockerfile instead of the start script will do this... but then it will not run the start script as root, thus blowing up on calls that require root. I had messed with using ENTRYPOINT as well, but could have been doing it wrong there. Similarly, using "user:" in the yml file seemed to make the start.sh script run as that user instead of root, so that wasn't working.

Dockerfile :

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脚本:

start.sh script:

#!/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文件:

app.yml file:

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 shell script:

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

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

What I would expect is that anyone trying to access the container internally will be doing so as appuser and not root. The goal is to prevent someone from messing with things they shouldn't (i.e. docker itself).

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

What is happening is that the script will change users after the app has started (proven via an echo command), but it doesn't seem to be maintained. If I exec into it, I'm still root.

推荐答案

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

As David mentions, once someone has access to the docker socket (either via API or with the docker CLI), that typically means they have root access to your host. It's trivial to use that access to run a privileged container with host namespaces and volume mounts that let the attacker do just about anything.

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

When you need to initialize a container with steps that run as root, I do recommend gosu over something like su since su was not designed for containers and will leave a process running as the root pid. Make sure that you exec the call to gosu and that will eliminate anything running as root. However, the user you start the container as is the same as the user used for docker exec, and since you need to start as root, your exec will run as root unless you override it with a -u flag.

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

There are additional steps you can take to lock down docker in general:


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

  1. Use user namespaces. These are defined on the entire daemon, require that you destroy all containers, and pull images again, since the uid mapping affects the storage of image layers. The user namespace offsets the uid's used by docker so that root inside the container is not root on the host, while inside the container you can still bind to low numbered ports and run administrative activities.

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

Consider authz plugins. Open policy agent and Twistlock are two that I know of, though I don't know if either would allow you to restrict the user of a docker exec command. They likely require that you give users a certificate to connect to docker rather than giving them direct access to the docker socket since the socket doesn't have any user details included in API requests it receives.

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

Consider rootless docker. This is still experimental, but since docker is not running as root, it has no access back to the host to perform root activities, mitigating many of the issues seen when containers are run as root.

这篇关于如何阻止对Docker容器的根访问的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆