我应该以非root用户身份在Docker容器中运行东西以提高安全性吗?

38

我已经不需要使用sudo,可以运行docker builddocker run。但是,当我在docker容器内部启动进程时,进程会在主机上以root身份显示(而不是在容器内部)。

尽管由于docker的命名空间和cgroups而不能访问主机文件系统,但它是否比作为普通用户运行还更危险?

如果是这样,那么在docker中以非root方式运行东西的正确方法是什么?

我应该只需要在Dockerfile的末尾添加USER nonroot吗?

更新:

构建某些内容需要root权限。我应该将USER放在Dockerfile的最顶端,然后安装sudo和其他依赖项,然后仅在构建过程中需要时使用sudo吗?

谁能给出一个简单的Dockerfile示例,在开头使用USER,然后安装和使用sudo


1
是的,这通常是一个好的实践。请注意,在没有使用sudo的情况下运行docker build比在镜像内部发生的任何事情都要危险得多。 - David Maze
是的,我支持@DavidMaze的评论。但需要注意的是,某些服务(例如sshd)必须以root身份运行,对于这种情况,您可以使用用户命名空间隔离容器(例如,在容器内将root映射到主机上不存在的非特权用户/UID)。 - masseyb
4个回答

27

root身份运行容器会带来许多风险。虽然容器内的root与主机上的root不同(有关详细信息请参见此处),在容器启动期间可以拒绝许多能力,但仍建议避免成为root

通常,在安装一些通用软件包/库之后,在Dockerfile中使用USER指令是个好主意。换句话说——在需要root权限的操作之后。在生产服务镜像中安装sudo是错误的,除非你有一个真正好的理由。在大多数情况下,你不需要它,而且这更是一个安全问题。如果您需要访问镜像中的某些特定文件或目录的权限,请确保您在Dockerfile中指定的用户确实可以访问它们(根据您部署容器的位置设置适当的uidgid和其他选项)。通常情况下,您不需要事先创建用户,但如果需要自定义,则可以随时执行此操作。

以下是一个Java应用程序的示例Dockerfile,该应用程序在用户my-service下运行:

FROM alpine:latest
RUN apk add openjdk8-jre
COPY  ./some.jar /app/
ENV SERVICE_NAME="my-service"

RUN addgroup --gid 1001 -S $SERVICE_NAME && \
    adduser -G $SERVICE_NAME --shell /bin/false --disabled-password -H --uid 1001 $SERVICE_NAME && \
    mkdir -p /var/log/$SERVICE_NAME && \
    chown $SERVICE_NAME:$SERVICE_NAME /var/log/$SERVICE_NAME

EXPOSE 8080
USER $SERVICE_NAME
CMD ["java", "-jar", "/app/some.jar"]

正如您所看到的,我事先创建了用户并设置了它的gid,禁用了它的 shell 和密码登录,因为它将成为一个“服务”用户。该用户还成为/var/log/$SERVICE_NAME的所有者,假设它将在那里写入一些文件。现在我们有了更小的攻击面。


如果Dockerfile从源代码构建库, 然后必须将lib安装到特权文件夹中怎么办?我不想在root权限下进行构建,所以是不是先安装sudo再不使用sudo构建并使用sudo将lib安装到如/opt这样的位置会更合适? - Guerlando OCs
1
如果您将用户放在开头并以此方式构建应用程序,则该用户将拥有在以下层创建的所有文件。您可能不总是希望如此。这就像在库上有写入权限-如果有人能够闯入容器并覆盖文件,他们将能够使用与运行应用程序的同一用户相同的用户来执行此操作。但是,如果它们由root拥有,则不会那么容易。因此,请将root保留为所有者,确保您的用户至少可以读取所需的文件,并在Dockerfile末尾切换到该用户。 - theUndying
1
选项 s 不明确(shell,system)。你是说要添加组 --gid 1001 -system 吗? - ChrisDanger
1
我刚刚使用了这个:# 避免以root身份运行容器可以降低风险 ENV SERVICE_NAME="my-service" RUN adduser --system --group $SERVICE_NAME USER $SERVICE_NAME - ChrisDanger
显示剩余6条评论

7

为什么不应该以root用户身份运行

虽然其他人已指出,不应该将镜像以root用户身份运行,但这里或文档中并没有太多信息说明原因。

尽管在容器内获得root权限和在主机上获得root权限之间存在差异,但在容器内获得root权限仍然非常强大。

以下是一篇深入探讨两者区别及该问题的好文:

https://www.redhat.com/en/blog/understanding-root-inside-and-outside-container

总体观点是,如果您的容器中存在恶意进程,则它可以在容器中执行任何操作,例如安装软件包、上传数据、劫持资源等等。

这也使得进程更容易突破容器并获得主机权限,因为容器本身没有任何保障。

何时以及如何以非root用户身份运行

您需要做的是使用root用户身份运行所有安装和文件下载/复制步骤(许多东西需要以root身份安装,通常以我下面概述的原因而言,这只是一个更好的做法)。然后,显式创建用户并授予该用户运行应用程序所需的最低访问级别。这通过使用chmodchown命令完成。

在您的ENTRYPOINTCMD指令之前,然后添加一个USER指令以切换到新创建的用户。这将确保您的应用程序以非root用户身份运行,并且该用户只能访问您在之前步骤中明确授予它访问权限的内容。

总体思路是,运行容器的用户应具有绝对最小的权限(大多数情况下,用户不需要文件的读、写和执行权限)。这样,如果容器中存在恶意进程,则其行为将受到尽可能多的限制。这意味着您应避免作为该用户创建或复制任何文件或安装任何软件包,因为默认情况下,它们将完全控制任何它们创建的资源。我曾看过一些评论提出不同的建议,请忽略它们。如果您想符合安全最佳实践,那么您还必须返回并撤销用户的多余权限,这将非常糟糕和容易出错。


6
"这也使得一个进程更容易打破容器并在主机上获得权限,因为容器本身没有任何保障。" - 你能举例说明吗? - RamPrakash

4

我应该将USER放在Dockerfile开头还是结尾?我应该安装sudo并仅在需要时使用它吗? - Guerlando OCs
最后的结果应该很好。 - iceveda06

-1
在非 root 用户下运行容器可以为您提供额外的安全层。默认情况下,Docker 容器是以 root 用户身份运行的,但这允许容器进行不受限制的活动。

2
我们所讨论的安全是什么类型的?容器已经与主机隔离开了!! - RamPrakash
2
@RamPrakash 在网上快速查看可能会让您感到惊讶,例如 https://blog.aquasec.com/container-isolation - “容器并不是一个强大的安全边界。它们在主机上提供了一些对共享资源的限制,但并不一定防止恶意攻击者规避这些限制。” - Dan Parsonson

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接