Amazon ECS 任务和容器安全性最佳实践
您应该将容器映像视为抵御“攻击”的第一道防线。不安全、构造不佳的映像可能允许攻击者逃离容器的边界并获得对主机的访问权限。您应该采取以下措施来缓解发生这种情况的风险。
在设置任务任务和容器时,建议执行以下操作。
创建最小的映像或使用 distroless 映像
首先从容器映像中移除所有多余的二进制文件。如果您使用的是来自 Amazon ECR Public Gallery 的不熟悉映像,请检查该映像以参考每个容器层的内容。您可以使用诸如 Dive
或者,您可以使用仅包含您的应用程序及其运行时系统依赖项的 distroless 映像。它们不包含包管理器或 shell。Distroless 映像改善了“扫描仪的信噪比,减轻了根据需要确定来源的负担”。有关更多信息,请参阅有关 distroless
Docker 有一种机制,可以从预留的、最小的镜像(称为 scratch)创建映像。有关更多信息,请参阅 Docker 文档中的使用 scratch 创建简单的父映像
############################ # 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 基本扫描使用一种开源图像扫描解决方案 ClairHIGH
或 CRITICAL
漏洞的映像。如果已部署的映像出现漏洞,则应尽快将其更换。
Docker Desktop Edge 版本 2.3.6.0
-
使用 Amazon ECR 和 AWS Security Hub 自动实现映像合规性
说明如何显示来自 AWS Security Hub 中的 Amazon ECR 的漏洞信息,以及如何通过阻止访问易受攻击的图像来自动修复。
移除映像的特殊权限
访问权限标志 setuid
和 setgid
允许以可执行文件所有者或组的权限运行可执行文件。从您的映像中移除具有这些访问权限的所有二进制文件,因为这些二进制文件可用于升级权限。考虑移除所有可能用于恶意目的 nc
和 curl
之类的 shell 和实用程序。您可以使用以下命令查找具有 setuid
和 setgid
访问权限的文件。
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。您可以通过执行以下操作查找哪些功能在使用中:
使用客户自主管理型密钥(CMK)加密推送到 Amazon ECR 的映像
您应该使用客户自主管理型密钥(CMK)加密推送到 Amazon ECR 的映像。推送到 Amazon ECR 的映像会使用 AWS Key Management Service(AWS KMS)托管密钥自动进行静态加密。如果您更愿意使用自己的密钥,Amazon ECR 现在支持使用客户自主管理型密钥(CMK)进行 AWS KMS 加密。在使用 CMK 启用服务器端加密之前,请查看静态加密文档中列出的注意事项。