如何防止根访问我的 docker 容器
How do I prevent root access to my docker container
我正在努力强化我们的 docker 图像,我对它的理解已经有点薄弱。话虽如此,我正在进行的当前步骤是阻止用户 运行 将容器设置为 root。对我来说,就是 "when a user runs 'docker exec -it my-container bash', he shall be an unprivileged user"(如果我错了请纠正我)。
当我通过 docker-compose 启动我的容器时,运行 的启动脚本需要作为根目录,因为它处理导入证书和挂载文件(在外部创建并通过查看)卷安装)。完成后,我希望用户成为 'appuser' 以供将来访问。这个问题似乎很符合我要找的东西,但我使用的是 docker-compose,而不是 docker 运行: How to disable the root access of a docker container?
这似乎是相关的,因为启动命令不同于 tomcat。我们正在 运行ning 一个 Spring 引导应用程序,我们用一个简单的 'java -jar jarFile' 启动它,图像是使用 maven 的 dockerfile-maven-plugin 构建的。话虽如此,我应该在运行之前还是之后将用户更改为非特权用户?
我相信在 Dockerfile 中更改用户而不是启动脚本会执行此操作...但是它不会 运行 以 root 身份启动脚本,从而在需要 root 的调用上爆炸。我也搞砸了使用 ENTRYPOINT,但可能在那里做错了。同样,在 yml 文件中使用 "user:" 似乎使 start.sh 脚本 运行 成为该用户而不是 root,所以这不起作用。
Docker文件:
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 用户身份 运行 您的容器的最佳做法是在 Docker 文件中使用 USER
指令或 运行ning入口点脚本中的 gosu 之类的东西,就像您显示的那样。但是,面对有足够兴趣获得它的特权用户,您不能阻止 root 访问。
正如 David 提到的那样,一旦有人可以访问 docker 套接字(通过 API 或使用 docker
CLI),这通常意味着他们可以访问您的主机.使用对 运行 特权容器的访问是微不足道的,该容器具有主机名称空间和卷安装,让攻击者可以做任何事情。
当您需要使用 运行 作为 root 的步骤初始化容器时,我建议使用 而不是 su
之类的东西,因为 su
不是为容器设计的并将留下一个进程 运行ning 作为根 pid。确保你 exec
调用 gosu
并且这将消除任何 运行ning 作为 root。但是,您启动容器的用户与用于 docker exec
的用户相同,并且由于您需要以 root 身份启动,因此您的 exec 将 运行 作为 root 用户,除非您用 [=] 覆盖它16=]旗帜。
一般情况下,您可以采取其他步骤来锁定 docker:
使用user namespaces。这些是在整个守护进程上定义的,需要销毁所有容器,然后重新拉取镜像,因为 uid 映射会影响镜像层的存储。用户命名空间偏移了 docker 使用的 uid,因此容器内的 root 不是主机上的 root,而在容器内您仍然可以绑定到低编号端口和 运行 管理活动。
考虑 authz plugins。 Open policy agent 和 Twistlock 是我所知道的两个,但我不知道它们是否允许您限制 docker exec
命令的用户。他们可能要求您为用户提供连接到 docker 的证书,而不是让他们直接访问 docker 套接字,因为该套接字在 API 请求中不包含任何用户详细信息收到。
考虑 rootless docker。这仍然是实验性的,但由于 docker 不是 运行 root 用户,它无法返回主机执行 root 活动,从而缓解了容器 运行 时出现的许多问题作为根。
当 docker 通常来自一台主机时 运行,您可以执行一些步骤。
通过在从接受的主机安装的目录中查找秘密,确保它不是来自另一台主机的 运行。
更改主机上用户的 .bashrc,以便他们在登录后立即开始 运行ning 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。在调用 startserver 后将 exit
添加到 .bash_rc
.
不确定这是否有效,但您可以试试。允许对 user/group 使用有限执行命令的 sudo 访问。 Sudo 配置只允许执行docker-cli。创建一个名为 docker-cli
的 shell 脚本,内容为 运行s 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 命令
我正在努力强化我们的 docker 图像,我对它的理解已经有点薄弱。话虽如此,我正在进行的当前步骤是阻止用户 运行 将容器设置为 root。对我来说,就是 "when a user runs 'docker exec -it my-container bash', he shall be an unprivileged user"(如果我错了请纠正我)。
当我通过 docker-compose 启动我的容器时,运行 的启动脚本需要作为根目录,因为它处理导入证书和挂载文件(在外部创建并通过查看)卷安装)。完成后,我希望用户成为 'appuser' 以供将来访问。这个问题似乎很符合我要找的东西,但我使用的是 docker-compose,而不是 docker 运行: How to disable the root access of a docker container?
这似乎是相关的,因为启动命令不同于 tomcat。我们正在 运行ning 一个 Spring 引导应用程序,我们用一个简单的 'java -jar jarFile' 启动它,图像是使用 maven 的 dockerfile-maven-plugin 构建的。话虽如此,我应该在运行之前还是之后将用户更改为非特权用户?
我相信在 Dockerfile 中更改用户而不是启动脚本会执行此操作...但是它不会 运行 以 root 身份启动脚本,从而在需要 root 的调用上爆炸。我也搞砸了使用 ENTRYPOINT,但可能在那里做错了。同样,在 yml 文件中使用 "user:" 似乎使 start.sh 脚本 运行 成为该用户而不是 root,所以这不起作用。
Docker文件:
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 用户身份 运行 您的容器的最佳做法是在 Docker 文件中使用 USER
指令或 运行ning入口点脚本中的 gosu 之类的东西,就像您显示的那样。但是,面对有足够兴趣获得它的特权用户,您不能阻止 root 访问。
正如 David 提到的那样,一旦有人可以访问 docker 套接字(通过 API 或使用 docker
CLI),这通常意味着他们可以访问您的主机.使用对 运行 特权容器的访问是微不足道的,该容器具有主机名称空间和卷安装,让攻击者可以做任何事情。
当您需要使用 运行 作为 root 的步骤初始化容器时,我建议使用 su
之类的东西,因为 su
不是为容器设计的并将留下一个进程 运行ning 作为根 pid。确保你 exec
调用 gosu
并且这将消除任何 运行ning 作为 root。但是,您启动容器的用户与用于 docker exec
的用户相同,并且由于您需要以 root 身份启动,因此您的 exec 将 运行 作为 root 用户,除非您用 [=] 覆盖它16=]旗帜。
一般情况下,您可以采取其他步骤来锁定 docker:
使用user namespaces。这些是在整个守护进程上定义的,需要销毁所有容器,然后重新拉取镜像,因为 uid 映射会影响镜像层的存储。用户命名空间偏移了 docker 使用的 uid,因此容器内的 root 不是主机上的 root,而在容器内您仍然可以绑定到低编号端口和 运行 管理活动。
考虑 authz plugins。 Open policy agent 和 Twistlock 是我所知道的两个,但我不知道它们是否允许您限制
docker exec
命令的用户。他们可能要求您为用户提供连接到 docker 的证书,而不是让他们直接访问 docker 套接字,因为该套接字在 API 请求中不包含任何用户详细信息收到。考虑 rootless docker。这仍然是实验性的,但由于 docker 不是 运行 root 用户,它无法返回主机执行 root 活动,从而缓解了容器 运行 时出现的许多问题作为根。
当 docker 通常来自一台主机时 运行,您可以执行一些步骤。
通过在从接受的主机安装的目录中查找秘密,确保它不是来自另一台主机的 运行。
更改主机上用户的 .bashrc,以便他们在登录后立即开始 运行ning 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。在调用 startserver 后将 exit
添加到 .bash_rc
.
不确定这是否有效,但您可以试试。允许对 user/group 使用有限执行命令的 sudo 访问。 Sudo 配置只允许执行docker-cli。创建一个名为 docker-cli
的 shell 脚本,内容为 运行s 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 命令