本文包含可帮助您安全使用Docker的技巧。 如果您是Docker的新手,建议您先阅读我以前有关Docker概念,Docker生态系统,Dockerfile,精简映像,常用命令和Docker中的数据的文章。
您需要如何关注Docker的安全性? 这取决于Docker是否内置了明智的安全性功能。如果您使用的是官方Docker映像并且未与其他计算机通信,则无需担心。
但是,如果您使用的是非官方的镜像,提供文件或在生产环境中运行应用程序,那么情况就不同了。 在这种情况下,您需要对Docker安全性有更多的了解。
您的主要安全目标是防止恶意用户获取有价值的信息或造成严重破坏。 为此,我将在几个关键领域分享Docker安全最佳实践。 到本文结尾,您将看到20多个Docker安全提示!
在第一部分中,我们将重点关注三个领域:
访问管理
镜像安全
机密管理
请考虑缩写AIM,以帮助您记住它们。
首先,让我们看看限制容器的访问权限。
访问管理-限制权限
启动容器时,Docker将创建一组命名空间。 命名空间可防止容器中的进程看到或影响主机(包括其他容器)中的进程。 命名空间是Docker封锁一个容器与另一个容器的主要方式。
Docker也提供私有容器网络。 这样可以防止容器获得对同一主机上其他容器的网络接口的特权访问。
因此,Docker环境在某种程度上是孤立的,但对于您的用例而言,它可能不够孤立。
> Does not look safe
良好的安全性意味着遵循最小特权原则。 您的容器应具有执行所需功能的能力,但没有其他能力。 棘手的事情是,一旦您开始限制可以在容器中运行的进程,则容器可能无法执行其合法需要执行的操作。
有几种方法可以调整容器的权限。 首先,避免以root身份运行(如果必须以root身份运行,则应重新映射)。 其次,使用–cap-drop和–cap-add调整功能。
多数人需要做的是避免root和调整功能,以限制特权。 更高级的用户可能想要调整默认的AppArmor和seccomp配置文件。 我将在即将出版的有关Docker的书中讨论这些内容,但此处已将它们排除在外,以防止本文如期膨胀。
避免以root身份运行
Docker的默认设置是使映像中的用户以root用户身份运行。 许多人没有意识到这是多么危险。 这意味着攻击者更容易访问敏感信息和您的内核。
一般最佳做法是,不要让容器以root用户身份运行。
> Roots
"防止来自容器内部特权升级攻击的最佳方法是将容器的应用程序配置为以非特权用户身份运行。" — Docker文档。
您可以在构建时指定root以外的用户名,如下所示:
docker run -u 1000 my_image
-user或-u标志可以指定用户名或用户ID。 如果userid不存在,那就很好。
在上面的示例中,1000是任意的非特权用户标识。 在Linux中,通常保留0到499之间的用户ID。 选择一个超过500的用户ID,以避免以默认系统用户身份运行。
最好从镜像的root用户更改用户,而不是从命令行设置用户。 这样,人们就不必记住在构建时进行更改。 仅在需要root附带功能的Dockerfile指令之后,在映像中包括USER Dockerfile指令。
换句话说,首先安装所需的软件包,然后切换用户。 例如:
FROM alpine:latest RUN apk update && apk add --no-cache git USER 1000 …
如果必须以超级用户身份在容器中运行进程,请将该超级用户重新映射到Docker主机上的特权较低的用户。 请参阅Docker文档。
您可以通过更改功能来授予用户所需的特权。
能力
功能是允许的流程包。
使用–cap-drop和–cap-add通过命令行调整功能。 最好的策略是使用–cap-drop all删除容器的所有特权,并使用–cap-add重新添加所需的特权。
> Stop or go
您可以在运行时调整容器的功能。 例如,要放弃使用kill来停止容器的功能,可以删除该默认功能,如下所示:
docker run --cap-drop=Kill my_image
避免为进程赋予SYS_ADMIN和SETUID特权,因为它们具有广泛的权力。 向用户添加此功能类似于授予root权限(避免这种结果是不使用root的全部目的)。
禁止容器使用1到1023之间的端口号是更安全的做法,因为大多数网络服务都在此范围内运行。 未经授权的用户可以侦听诸如登录之类的内容并运行未经授权的服务器应用程序。 这些编号较低的端口需要以root用户身份运行或被明确赋予CAP_NET_BIND_SERVICE功能。
要查找诸如容器是否具有特权端口访问权限之类的信息,可以使用inspect。 使用docker container inspect my_container_name将为您显示有关容器分配的资源和安全配置文件的许多详细信息。
这是Docker参考,更多关于特权的信息。
与Docker中的大多数事情一样,最好在自动的自文档文件中配置容器。 使用Docker Compose,您可以在服务配置中指定功能,如下所示:
cap_drop: ALL
或者,您可以按照此处的讨论在Kubernetes文件中对其进行调整。
Linux功能的完整列表在这里。
如果要对容器特权进行更细粒度的控制,请在我即将出版的书中查看我对AppArmor和seccomp的讨论。 订阅我的电子邮件通讯,以便在可用时得到通知。
> Closed road
访问管理-限制资源
最好限制容器对内存和CPU等系统资源的访问。 没有资源限制,容器可以用尽所有可用内存。 如果发生这种情况,Linux主机内核将抛出"内存不足"异常并杀死内核进程。 这可能会导致整个系统崩溃。 您可以想象攻击者如何利用这些知识来尝试关闭应用程序。
如果您在同一台计算机上运行多个容器,则可以明智地限制任何一个容器可以使用的内存和CPU。 如果您的容器内存不足,则会关闭。 关闭容器可能会导致应用崩溃,这很不好玩。 但是,这种隔离可以防止主机内存不足,并且可以防止主机上的所有容器崩溃。 那是一件好事。
> Wind resource
适用于Mac v2.1.0的Docker Desktop CE具有默认资源限制。 您可以在Docker图标->首选项下访问它们。 然后单击"资源"选项卡。 您可以使用滑块来调整资源限制。
> Resource settings on Mac
另外,您可以通过指定–memory标志或-m的缩写来限制命令行中的资源,后跟一个数字和一个度量单位。
4m表示4兆字节,是最小的容器内存分配。 兆字节(MiB)略大于兆字节(1 MiB = 1.048576 MB)。 该文档目前不正确,但希望维护人员在您阅读本文时已接受我的PR进行更改。
要查看您的容器正在使用哪些资源,请在新的终端窗口中输入命令docker stats。 您会看到定期刷新运行中的容器统计信息。
> Stats
在后台,Docker正在使用Linux控制组(cgroup)来实现资源限制。 该技术已经过实战测试。
在此处了解有关Docker上资源限制的更多信息。
镜像安全
从Docker Hub抓取镜像就像邀请某人进入您的家一样。 您可能想要对此有所了解。
> Someone's home
使用值得信赖的镜像
镜像安全的规则之一是仅使用您信任的镜像。 您如何知道哪些镜像是可信赖的?
可以肯定,流行的官方镜像相对安全。 此类镜像包括alpine,ubuntu,python,golang,redis,busybox和node。 每个都有超过1000万的下载量,并且很多人关注它们。
Docker解释:
Docker赞助了一个专门的团队,负责审查和发布正式映像中的所有内容。 该团队与上游软件维护者,安全专家以及更广泛的Docker社区合作,以确保这些映像的安全性。 |
减少攻击面
与使用正式基础镜像有关,您可以使用最小基础镜像。
由于内部代码较少,因此安全漏洞的可能性较小。 较小,较不复杂的基本图像更加透明。
与您的朋友的镜像(依赖于朋友的镜像,该镜像依赖于另一基本镜像)相比,查看Alpine镜像中发生的事情要容易得多。 短线更容易解开。
> Tangled
同样,仅安装您实际需要的软件包。 这样可以减少攻击面,并加快镜像下载和镜像构建速度。
需要签名的图像镜像
您可以使用Docker内容信任来确保对镜像进行签名。
Docker内容信任阻止用户使用带标签的镜像,除非它们包含签名。 可信来源包括来自Docker Hub的Official Docker Images和来自用户可信来源的签名镜像。
> Signed
默认情况下禁用内容信任。 要启用它,请将DOCKER_CONTENT_TRUST环境变量设置为1。在命令行中,运行以下命令:
export DOCKER_CONTENT_TRUST=1
现在,当我尝试从Docker Hub下拉我自己的未签名映像时,它已被阻止。
Error: remote trust data does not exist for docker.io/discdiver/frames: notary.docker.io does not have trust data for docker.io/discdiver/frames
内容信任是防止riff窃的一种方法。 在此处了解有关内容信任的更多信息。
Docker通过其内容的加密校验和存储和访问图像。 这样可以防止攻击者创建图像冲突。 这是很酷的内置安全功能。
管理密码
您的访问受到限制,镜像安全,现在该管理您的密码了。"
管理敏感信息的规则1:请勿将其添加到您的镜像中。 在代码存储库,日志和其他地方找到未加密的敏感信息并不难。
规则2:也不要将环境变量用于敏感信息。 任何可以在容器中运行docker inspect或exec的人都可以找到您的密码。 以root身份运行的任何人都可以。 希望我们已经进行了一些配置,以便用户不会以root用户身份运行,但是冗余是良好安全性的一部分。 通常,日志也会转储环境变量值。 您不希望您的敏感信息只泄露给任何人。
Docker卷更好。 建议使用它们在Docker文档中访问您的敏感信息。 您可以将卷用作保存在内存中的临时文件系统。 卷消除了docker inspect和日志记录风险。 但是,root用户仍然可以看到秘密,任何可以执行到容器中的人都可以看到秘密。 总体而言,卷是一个很好的解决方案。
比卷更好,请使用Docker Secret。 Secret已加密。
> Secrets
一些Docker文档指出您只能在Docker Swarm中使用机密。 不过,您可以在没有Swarm的情况下在Docker中使用机密。
如果您只需要映像中的秘密,则可以使用BuildKit。 BuildKit是比当前用于构建Docker映像的构建工具更好的后端。 它大大缩短了构建时间,并具有其他不错的功能,包括对构建时机密的支持。
BuildKit相对较新-Docker Engine 18.09是BuildKit支持附带的第一个版本。 有三种方法可以指定BuildKit后端,因此您可以立即使用其功能。 将来,它将是默认的后端。
使用export DOCKER_BUILDKIT = 1将其设置为环境变量。
使用DOCKER_BUILDKIT = 1启动构建或运行命令。
默认情况下启用BuildKit。 使用以下命令将/etc/docker/daemon.json中的配置设置为true:{" features":{" buildkit":true}}。 然后重启Docker。
然后,您可以在构建时使用–secret标志使用机密,如下所示:
docker build –secret my_key = my_value,src = path / to / my_secret_file。
文件将您的Secret指定为键值对的位置。
这些Secret不会存储在最终映像中。 它们也从映像构建缓存中排除。 安全第一!
如果您需要运行容器中的Secret,而不仅仅是在构建映像时,请使用Docker Compose或Kubernetes。
使用Docker Compose,将secrets键值对添加到服务中并指定secret文件。 改写以下示例的有关Docker Compose秘密的Stack Exchange答案的技巧。
带有Secret的示例docker-compose.yml:
version: "3.7"services: my_service: image: centos:7 entrypoint: "cat /run/secrets/my_secret" secrets: - my_secretsecrets: my_secret: file: ./my_secret_file.txt
然后像往常一样使用docker-compose up –build my_service启动Compose。
如果您使用的是Kubernetes,它支持秘密。 Helm-Secrets可以帮助简化K8中的秘密管理。 此外,K8和Docker Enterprise一样,都具有基于角色的访问控制(RBAC)。 RBAC使团队的访问秘密管理更易于管理和更安全。
Secret的最佳做法是使用机密管理服务,例如Vault。 Vault是HashiCorp的一项服务,用于管理对机密的访问。 它还限制了时间的Secret。 您可以在此处找到有关Vault的Docker映像的更多信息。
AWS Secrets Manager和其他云提供商的类似产品也可以帮助您管理云中的机密。
> Keys
请记住,管理机密的关键是保持。 绝对不要将它们添加到您的镜像中或将它们变成环境变量。
更新
与任何代码一样,使镜像中的语言和库保持最新,以从最新的安全修复程序中受益。
> Hopefully your security is more up to date than this lock
如果您在镜像中引用基础镜像的特定版本,请确保也保持最新。
相关地,您应该使Docker版本保持最新,以进行错误修复和增强,以允许您实施新的安全功能。
最后,保持主机服务器软件为最新。 如果您使用的是托管服务,则应该为您完成此操作。
更好的安全性意味着保持更新。
考虑Docker Enterprise
如果您的组织拥有一堆人和一堆Docker容器,那么您可以从Docker Enterprise中受益。 管理员可以为所有用户设置策略限制。 所提供的RBAC,监视和日志记录功能可能会使您的团队更轻松地进行安全管理。
借助Enterprise,您还可以在Docker Trusted Registry中私有地托管自己的映像。 Docker提供了内置的安全扫描功能,以确保您的映像中没有已知的漏洞。
Kubernetes免费提供了其中一些功能,但是Docker Enterprise对容器和映像具有附加的安全功能。 最好的是,Docker Enterprise 3.0于2019年7月发布。它包括具有"明智的安全默认设置"的Docker Kubernetes服务。
其他提示
永远不要以特权方式运行容器,除非您有特殊需要,例如需要在Docker容器中运行Docker,而且您知道自己在做什么。
在Dockerfile中,建议使用COPY而不是ADD。 ADD会自动提取压缩文件,并可以从URL复制文件。 COPY没有这些功能。 尽可能避免使用ADD,这样您就不会受到来自远程URL和Zip文件的攻击。
如果您在同一服务器上运行任何其他进程,请在Docker容器中运行它们。
如果您使用网络服务器和API创建容器,请仔细检查参数,以免创建您不想要的新容器。
如果公开REST API,请使用HTTPS或SSH保护API端点。
考虑使用Docker Bench for Security进行检查,以了解您的容器遵循其安全准则的程度。
仅将敏感数据存储在卷中,而不能存储在容器中。
如果将单主机应用程序与网络一起使用,请不要使用默认的桥接网络。 它具有技术缺陷,不建议用于生产。 如果发布端口,则可以访问桥接网络上的所有容器。
将Lets Encrypt用于HTTPS证书进行服务。 在此处查看有关NGINX的示例。
仅在需要读取卷时,才将卷挂载为只读。 请参阅此处的几种方法。
摘要
您已经了解了许多使Docker容器更安全的方法。 安全不是一成不变的。 它需要保持警惕,以确保镜像和容器的安全。
> Keys
考虑安全性时,请记住AIM:
(1) 访问管理
避免以超级用户身份运行。 如果必须使用root,则重新映射。
删除所有功能,然后重新添加所需的功能。
如果您需要细粒度的权限调整,请进入AppArmor。
限制资源。
(2) 镜像安全
使用官方的,流行的,最小的基本镜像。
不要安装不需要的东西。
要求对镜像进行签名。
保持Docker,Docker映像和其他与Docker相关的软件的更新。
(3) 机密Secret管理
使用Secret或卷。
考虑一个机密管理器,例如vault。
> Bullseye!
保持Docker容器安全意味着实现安全的目标。
不要忘了让Docker,您的语言和库,您的图像以及您的主机软件保持更新。 最后,如果您作为团队的一部分运行Docker,请考虑使用Docker Enterprise。
希望本文对Docker安全性有所帮助。 如果您这样做了,请在您喜欢的论坛或社交媒体频道上与其他人分享它,以便您的朋友也可以找到它!