Shell 如何防止根用户访问docker容器

Shell 如何防止根用户访问docker容器,shell,docker,docker-compose,dockerfile,hardening,Shell,Docker,Docker Compose,Dockerfile,Hardening,我正在努力强化我们的docker形象,对此我已经有点不太了解了。话虽如此,我当前的步骤是阻止用户以root用户身份运行容器。对我来说,这意味着“当一个用户运行'docker exec-it my container bash'时,他应该是一个没有特权的用户”(如果我错了,请纠正我) 当我通过docker compose启动容器时,运行的启动脚本需要是root,因为它处理导入证书和装入的文件(在外部创建并通过卷装入查看)。完成后,我希望用户成为“appuser”,以便将来进行任何访问。这个问题似乎

我正在努力强化我们的docker形象,对此我已经有点不太了解了。话虽如此,我当前的步骤是阻止用户以root用户身份运行容器。对我来说,这意味着“当一个用户运行'docker exec-it my container bash'时,他应该是一个没有特权的用户”(如果我错了,请纠正我)

当我通过docker compose启动容器时,运行的启动脚本需要是root,因为它处理导入证书和装入的文件(在外部创建并通过卷装入查看)。完成后,我希望用户成为“appuser”,以便将来进行任何访问。这个问题似乎很符合我的要求,但我使用的是docker compose,而不是docker run:

这似乎是相关的,因为startup命令不同于tomcat。我们正在运行一个SpringBoot应用程序,该应用程序由一个简单的“java-JARJARFile”启动,该映像是使用maven的dockerfile maven插件构建的。话虽如此,我应该在运行之前,还是之后,将用户更改为非特权用户

我相信在Dockerfile中更改用户而不是开始脚本可以做到这一点。。。但是,它不会以root用户身份运行start脚本,因此在需要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编写shell脚本:

docker-compose -f app.yml -f another-app.yml $@
我所期望的是,任何试图在内部访问容器的人都将以appuser而不是root用户的身份进行访问。目标是防止有人弄乱他们不应该做的事情(即docker本身)


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

您本质上无法阻止对容器的根级别访问

任何可以运行任何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
指令,也可以在entrypoint脚本中运行类似于您所显示的内容。但是,面对对获取权限非常感兴趣的特权用户,您无法阻止root访问。

正如David提到的,一旦有人能够访问docker套接字(通过API或使用
docker
CLI),这通常意味着他们能够访问您的主机。使用该访问来运行具有主机名称空间和卷装载的特权容器是很简单的,攻击者可以通过该访问来执行任何操作

当您需要使用以root身份运行的步骤初始化容器时,我建议您使用
su
之类的方法,因为
su
不是为容器设计的,它会让进程以root身份运行。确保
exec
调用了
gosu
,这将消除以root身份运行的任何内容。但是,您启动容器的用户与用于
docker exec
的用户相同,并且由于您需要以root用户身份启动,除非您使用
-u
标志覆盖它,否则您的exec将以root用户身份运行

一般来说,您可以采取其他步骤锁定docker:

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

  • 考虑一下。Open policy agent和Twistlock是我所知道的两个,尽管我不知道它们是否允许您限制
    docker exec
    命令的用户。它们可能要求您为用户提供一个连接到docker的证书,而不是让他们直接访问docker套接字,因为套接字接收的API请求中没有任何用户详细信息

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


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

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

    使用您制作并强化的脚本启动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


    当用户登录到主机时,将调用startserver并启动docker。调用startserver后,将
    退出
    添加到
    .bash\u rc
    不确定此操作是否有效,但您可以尝试。允许用户/组使用有限的执行命令进行sudo访问。Sudo配置仅允许执行docker cli。使用名称
    docker cli
    创建一个shell脚本,其中包含运行docker命令的内容,例如
    docker“$@”
    。在这个文件中,检查参数并强制用户提供switch--us
    sudo docker-cli exec -it containerid sh (failed)
    
    sudo docker-cli exec -u root ... (failed)
    
    sudo docker-cli exec -u mysql ... (Passed)