本文发表于一年多前。旧文章可能包含过时内容。请检查页面中的信息自发布以来是否已变得不正确。
在 Ingress-NGINX v1.2.0 中提高安全标准
Ingress 可能是 Kubernetes 中最常被攻击的组件之一。Ingress 通常定义了一个暴露给互联网的 HTTP 反向代理,其中包含多个网站,并拥有对 Kubernetes API 的一些特权访问(例如读取与 TLS 证书及其私钥相关的 Secret)。
虽然它在您的架构中是一个有风险的组件,但它仍然是正确暴露服务的最流行方式。
Ingress-NGINX 经过安全评估后发现一个大问题:在将配置转换为 nginx.conf
文件之前,我们没有进行所有适当的清理,这可能导致信息泄露风险。
尽管我们理解这种风险以及修复它的真正需求,但这不是一个简单的过程,因此我们采取了另一种方法来降低(但不能消除!)当前(v1.2.0)版本中的这种风险。
隆重推出 Ingress NGINX v1.2.0 和 chroot NGINX 进程
主要的挑战之一是 Ingress-NGINX 将 Web 代理服务器(NGINX)与 Ingress 控制器(具有 Kubernetes API 访问权限并创建 nginx.conf
文件的组件)一起运行。
因此,NGINX 确实拥有与控制器相同的文件系统访问权限(以及 Kubernetes 服务帐户令牌以及容器中的其他配置)。虽然将这些组件分离是我们的最终目标,但项目需要快速响应;这促使我们考虑使用 chroot()
。
让我们看看在这次更改之前 Ingress-NGINX 容器是什么样子
正如我们所看到的,提供 HTTP 代理的容器(不是 Pod,而是容器!)是监视 Ingress 对象并写入容器卷的容器
现在,认识一下新架构
这一切意味着什么?一个基本的总结是:我们将 NGINX 服务隔离为控制器容器内的容器。
虽然这并非完全准确,但要理解这里所做的工作,最好了解 Linux 容器(以及 cgroup 等底层机制和内核命名空间)的工作原理。您可以在 Kubernetes 词汇表中阅读有关 cgroup 的内容:cgroup
,并在 NGINX 项目文章 命名空间和 cgroup 是什么,它们如何工作? 中了解 cgroup 如何与命名空间交互。(在您阅读时,请记住 Linux 内核命名空间与 Kubernetes 命名空间是不同的概念)。
跳过理论,我需要什么才能使用这种新方法?
虽然这会提高安全性,但我们在本次发布中将此功能设置为可选,以便您有时间在环境中进行正确的调整。此新功能仅适用于 Ingress-NGINX 控制器 v1.2.0 及更高版本。
要使用此功能,您的部署需要进行两项更改
- 在容器镜像名称后附加 "-chroot" 后缀。例如:
gcr.io/k8s-staging-ingress-nginx/controller-chroot:v1.2.0
- 在您的 Ingress 控制器的 Pod 模板中,找到添加能力
NET_BIND_SERVICE
的位置,并添加能力SYS_CHROOT
。编辑清单后,您将看到类似以下的代码片段
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
- SYS_CHROOT
如果您使用官方 Helm chart 部署控制器,则更改 values.yaml
中的以下设置
controller:
image:
chroot: true
Ingress 控制器通常是集群范围的(IngressClass API 是集群范围的)。如果您管理 Ingress-NGINX 控制器但不是整个集群的运营者,则在您的部署中启用 SYS_CHROOT
功能**之前**,请咨询您的集群管理员是否可以使用该功能。
好的,但这如何提高我的 Ingress 控制器的安全性?
考虑以下配置片段,并想象出于某种原因它被添加到了您的 nginx.conf
中
location /randomthing/ {
alias /;
autoindex on;
}
如果您部署此配置,则有人可以通过调用 http://website.example/randomthing
获取 Ingress 控制器整个文件系统的列表(和访问权限)。
现在,您能识别出下方列表中 chroot 和非 chroot Nginx 之间的区别吗?
无额外的 chroot() | 有额外的 chroot() |
---|---|
bin | bin |
dev | dev |
etc | etc |
home | |
lib | lib |
media | |
mnt | |
opt | opt |
proc | proc |
root | |
run | run |
sbin | |
srv | |
sys | |
tmp | tmp |
usr | usr |
var | var |
dbg | |
nginx-ingress-controller | |
wait-shutdown |
左侧的没有 chroot。因此 NGINX 对文件系统拥有完全访问权限。右侧的进行了 chroot,因此创建了一个只包含使 NGINX 工作所需文件的新文件系统。
此版本中还有哪些其他安全改进?
我们知道新的 chroot()
机制有助于解决部分风险,但是,仍然有人可以尝试注入命令来读取,例如,nginx.conf
文件并提取敏感信息。
因此,此版本中的另一项更改(这是可选退出!)是“深度检查器”。我们知道某些指令或正则表达式可能对 NGINX 危险,因此深度检查器会检查 Ingress 对象的所有字段(在其协调期间,以及通过验证准入 Webhook),以验证是否有任何字段包含这些危险指令。
Ingress 控制器已经对注解执行此操作,我们的目标是在未来版本中将此现有验证移到深度检查中。
您可以在 https://github.com/kubernetes/ingress-nginx/blob/main/internal/ingress/inspector/rules.go 中查看现有规则。
由于需要检查和匹配相关 Ingress 对象中的所有字符串,此新功能可能会消耗更多 CPU。您可以通过在命令行参数中运行 --deep-inspect=false
来禁用它。
接下来是什么?
这并非我们的最终目标。我们的最终目标是将控制平面和数据平面进程分离。事实上,这样做也将有助于我们实现 Gateway API 实现,因为一旦它“知道”要向数据平面提供什么,我们可能会有不同的控制器(这里需要一些帮助!!)
Kubernetes 中的其他一些项目已经采取了这种方法(例如 KPNG,kube-proxy
的拟议替代品),我们计划与它们保持一致,并在 Ingress-NGINX 中获得相同的体验。
进一步阅读
如果您想了解 Ingress NGINX 中如何实现 chroot,请查看 https://github.com/kubernetes/ingress-nginx/pull/8337。包含所有更改的 v1.2.0 版本可在 https://github.com/kubernetes/ingress-nginx/releases/tag/controller-v1.2.0 找到。