Amazon ECS 任务和容器安全性最佳实践 - Amazon Elastic Container Service

Amazon ECS 任务和容器安全性最佳实践

您应该将容器映像视为抵御“攻击”的第一道防线。不安全、构造不佳的映像可能允许攻击者逃离容器的边界并获得对主机的访问权限。您应该采取以下措施来缓解发生这种情况的风险。

在设置任务任务和容器时,建议执行以下操作。

创建最小的映像或使用 distroless 映像

首先从容器映像中移除所有多余的二进制文件。如果您使用的是来自 Amazon ECR Public Gallery 的不熟悉映像,请检查该映像以参考每个容器层的内容。您可以使用诸如 Dive 之类的应用程序来执行此操作。

或者,您可以使用仅包含您的应用程序及其运行时系统依赖项的 distroless 映像。它们不包含包管理器或 shell。Distroless 映像改善了“扫描仪的信噪比,减轻了根据需要确定来源的负担”。有关更多信息,请参阅有关 distroless 的 GitHub 文档。

Docker 有一种机制,可以从预留的、最小的镜像(称为 scratch)创建映像。有关更多信息,请参阅 Docker 文档中的使用 scratch 创建简单的父映像。使用像 Go 这样的语言,您可以创建一个静态链接的二进制文件,然后在 Dockerfile 中引用它。以下示例说明了如何完成此操作。

############################ # STEP 1 build executable binary ############################ FROM golang:alpine AS builder # Install git. # Git is required for fetching the dependencies. RUN apk update && apk add --no-cache git WORKDIR $GOPATH/src/mypackage/myapp/ COPY . . # Fetch dependencies. # Using go get. RUN go get -d -v # Build the binary. RUN go build -o /go/bin/hello ############################ # STEP 2 build a small image ############################ FROM scratch # Copy our static executable. COPY --from=builder /go/bin/hello /go/bin/hello # Run the hello binary. ENTRYPOINT ["/go/bin/hello"] This creates a container image that consists of your application and nothing else, making it extremely secure.

上一个示例也是多阶段构建示例。从安全角度来看,这些类型的构建很有吸引力,因为您可以使用它们来最大限度地减少推送到容器注册表的最终映像的大小。缺乏构建工具和其他无关二进制文件的容器映像通过减少映像的攻击面来改善您的安全状况。有关多阶段构建的更多信息,请参阅 Docker 文档中的 Multi-stage builds

扫描您的映像中是否存在漏洞

与虚拟机映像类似,容器映像可能包含有漏洞的二进制文件和应用程序库,或者随着时间的推移而出现漏洞。防范漏洞的最佳方法是定期使用图像扫描仪扫描图像。

存储在 Amazon ECR 中的映像可以在推送时或需要时扫描(每 24 小时一次)。Amazon ECR 基本扫描使用一种开源图像扫描解决方案 Clair。Amazon ECR 增强扫描使用 Amazon Inspector。扫描图像后,结果将记录到 Amazon EventBridge 中的 Amazon ECR 事件流中。您还可以从 Amazon ECR 控制台中或通过调用 DescribeImageScanFindings API 来查看扫描结果。应删除或重建带有 HIGHCRITICAL 漏洞的映像。如果已部署的映像出现漏洞,则应尽快将其更换。

Docker Desktop Edge 版本 2.3.6.0 或更高版本可以扫描本地映像。扫描由应用程序安全服务 Snyk 提供支持。当发现漏洞时,Snyk 会识别 Dockerfile 中存在漏洞的层次和依赖项。它还推荐了安全的替代方案,例如使用漏洞更少的更精简的基础映像,或者将特定的软件包升级到较新的版本。通过使用 Docker 扫描,开发人员可以在将映像推送到注册表之前解决潜在的安全问题。

移除映像的特殊权限

访问权限标志 setuidsetgid 允许以可执行文件所有者或组的权限运行可执行文件。从您的映像中移除具有这些访问权限的所有二进制文件,因为这些二进制文件可用于升级权限。考虑移除所有可能用于恶意目的 nccurl 之类的 shell 和实用程序。您可以使用以下命令查找具有 setuidsetgid 访问权限的文件。

find / -perm /6000 -type f -exec ls -ld {} \;

要从这些文件中移除这些特殊权限,请在您的容器映像中添加以下指令。

RUN find / -xdev -perm /6000 -type f -exec chmod a-s {} \; || true

创建一组精选映像

与其允许开发人员创建自己的映像,不如为组织中的不同应用程序堆栈创建一组经过审查的映像。通过这样做,开发人员可以放弃学习如何编写 Dockerfiles,而专注于编写代码。当更改合并到您的代码库中时,CI/CD 管道可以自动编译资产,然后将其存储在构件存储库中。最后,在将构件推送到 Docker 注册表(例如 Amazon ECR)之前,将其复制到相应的映像中。您至少应该创建一组基础映像,开发人员可以从中创建自己的 Dockerfiles。您应避免从 Docker Hub 中提取映像。您并不总是知道映像中有什么,在前 1000 个映像中,大约有五分之一存在漏洞。这些映像及其漏洞的列表可以在 https://vulnerablecontainers.org/ 中找到。

扫描应用程序包和库中是否存在漏洞

现在,开源库已普遍使用。与操作系统和操作系统包一样,这些库可能存在漏洞。作为开发生命周期的一部分,当发现严重漏洞时,应对这些库进行扫描和更新。

Docker Desktop 使用 Snyk 执行本地扫描。它还可用于查找开源库中的漏洞和潜在的许可问题。可以直接将其集成到开发人员工作流程中,从而降低开源库带来的风险。有关更多信息,请参阅以下主题:

执行静态代码分析

在构建容器映像之前,您应该执行静态代码分析。它是针对您的源代码执行的,用于识别代码错误和可能被恶意行为者利用的代码,例如错误注入。您可以使用 Amazon Inspector。有关更多信息,请参阅《Amazon Inspector User Guide》中的 Scanning Amazon ECR container images with Amazon Inspector

以非根用户身份运行容器

您应该以非根用户身份运行容器。默认情况下,除非 USER 指令包含在您的 Dockerfile 中,否则容器将以 root 用户身份运行。Docker 分配的默认 Linux 功能限制了可以作为 root 身份运行的操作,但只能稍作限制。例如,以 root 身份运行的容器仍不允许访问设备。

作为 CI/CD 管道的一部分,您应该使用 lint Dockerfiles 来查找 USER 指令,如果缺少该指令,则构建失败。有关更多信息,请参阅以下主题:

  • Dockerfile-lint 是 RedHat 推出的开源工具,可用于检查文件是否符合最佳实践。

  • Hadolint 是另一种用于构建符合最佳实践的 Docker 映像的工具。

使用只读的根文件系统

您应该使用只读的根文件系统。默认情况下,容器的根文件系统是可编写的。当您为容器配置一个 RO(只读)根文件系统时,它会强制您明确定义数据的保存位置。这可以减少攻击面,因为除非特别授予权限,否则无法写入容器的文件系统。

注意

拥有只读的根文件系统可能会导致某些期望能够写入文件系统的操作系统包出现问题。如果您打算使用只读的根文件系统,请事先进行全面测试。

使用 CPU 和内存限制配置任务(Amazon EC2)

您应该为任务配置 CPU 和内存限制,以最大限度地降低以下风险。针对任务中所有容器可以预留的 CPU 和内存量,任务的资源限制设定了上限。如果未设置限制,则任务可以访问主机的 CPU 和内存。这可能会导致在共享主机上部署的任务使其他任务耗尽系统资源的问题。

注意

AWS Fargate 任务上的 Amazon ECS 要求您指定 CPU 和内存限制,因为它会将这些值用于计费。对于 Amazon ECS Fargate 来说,一项占用所有系统资源的任务不是问题,因为每个任务都是在自己的专用实例上运行的。如果您未指定内存限制,Amazon ECS 会为每个容器分配至少 4MB 的存储空间。同样,如果没有为任务设置 CPU 限制,Amazon ECS 容器代理会为其分配至少 2 个 CPU。

在 Amazon ECR 中使用不可变标签

借助 Amazon ECR,您可以而且应该使用具有不可变标签的配置映像。这样可以防止将修改或更新的映像版本推送到带有相同标签的映像存储库。这样可以防止攻击者在带有相同标签的映像上推送受损版本的映像。通过使用不可变标签,您可以有效地强迫自己为每次更改推送一个带有不同标签的新映像。

避免以特权身份运行容器(Amazon EC2)

您应该避免以特权身份运行容器。对于后台,以 privileged 身份运行的容器在主机上以扩展权限运行。这意味着容器会继承分配给主机上的 root 的所有 Linux 功能。应严格限制或禁止其使用。建议将 Amazon ECS 容器代理环境变量 ECS_DISABLE_PRIVILEGED 设置为 true,以防止容器在不需要 privileged 时在特定主机以 privileged 身份运行。或者,您可以使用 AWS Lambda 扫描任务定义以了解 privileged 参数的使用情况。

注意

AWS Fargate 上的 Amazon ECS 不支持容器以 privileged 身份运行。

从容器中移除不必要的 Linux 功能

以下是分配给 Docker 容器的默认 Linux 功能的列表。有关每项功能的更多信息,请参阅 Linux 功能概述

CAP_CHOWN, CAP_DAC_OVERRIDE, CAP_FOWNER, CAP_FSETID, CAP_KILL, CAP_SETGID, CAP_SETUID, CAP_SETPCAP, CAP_NET_BIND_SERVICE, CAP_NET_RAW, CAP_SYS_CHROOT, CAP_MKNOD, CAP_AUDIT_WRITE, CAP_SETFCAP

如果容器不需要上面列出的所有 Docker 内核功能,请考虑将其从容器中删除。有关 Docker 内核每项功能的更多信息,请参阅 KernelCapabilities。您可以通过执行以下操作查找哪些功能在使用中:

  • 安装操作系统包 libcap-ng 并运行 pscap 实用程序以列出每个进程正在使用的功能。

  • 您还可以使用 capsh 来解密进程正在使用哪些功能。

使用客户自主管理型密钥(CMK)加密推送到 Amazon ECR 的映像

您应该使用客户自主管理型密钥(CMK)加密推送到 Amazon ECR 的映像。推送到 Amazon ECR 的映像会使用 AWS Key Management Service(AWS KMS)托管密钥自动进行静态加密。如果您更愿意使用自己的密钥,Amazon ECR 现在支持使用客户自主管理型密钥(CMK)进行 AWS KMS 加密。在使用 CMK 启用服务器端加密之前,请查看静态加密文档中列出的注意事项。