我正在加强我们的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。
答案 0 :(得分:3)
正如David所提到的,一旦有人可以访问docker套接字(通过API或使用docker
CLI),这通常意味着他们可以对您的主机进行root访问。使用这种访问来运行具有主机名称空间和卷安装的特权容器的琐碎事情,使攻击者几乎可以做任何事情。
当您需要使用以root用户身份运行的步骤来初始化容器时,我建议在su
之类的地方推荐gosu,因为su
不是为容器设计的,它将使进程继续运行作为根pid。确保您exec
对gosu
的调用会消除以root用户身份运行的任何内容。但是,您启动容器的用户与docker exec
所使用的用户相同,并且由于您需要以root用户身份启动,因此您的exec将以root用户身份运行,除非您使用-u
标志覆盖它
您通常可以采取其他步骤来锁定Docker:
使用user namespaces。它们是在整个守护程序上定义的,要求您销毁所有容器,然后再次提取图像,因为uid映射会影响图像层的存储。用户名称空间抵消了docker使用的uid,因此容器内的根不是主机上的根,而在容器内,您仍然可以绑定到编号较低的端口并运行管理活动。
考虑authz plugins。我知道有两个开放策略代理和Twistlock,尽管我不知道二者是否会限制您使用docker exec
命令的用户。他们可能要求您为用户提供连接到docker的证书,而不是直接授予他们访问docker套接字的权限,因为该套接字在接收到的API请求中没有包含任何用户详细信息。
考虑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命令