本文发布已超过一年。较旧的文章可能包含过时的内容。请检查页面中的信息自发布以来是否已变得不正确。
在 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 和 chrooted NGINX 进程
主要挑战之一是 Ingress-NGINX 在 Ingress 控制器(有权访问 Kubernetes API 并创建 nginx.conf
文件的组件)旁边运行 Web 代理服务器(NGINX)。
因此,NGINX 确实具有对控制器文件系统的相同访问权限(以及 Kubernetes 服务帐户令牌和容器中的其他配置)。虽然拆分这些组件是我们的最终目标,但该项目需要快速响应;这使我们想到了使用 chroot()
的想法。
让我们看一下此更改之前的 Ingress-NGINX 容器的样子
如我们所见,提供 HTTP 代理的同一个容器(不是 Pod,是容器!)是监视 Ingress 对象并写入容器卷的容器
现在,了解一下新架构
这一切意味着什么?基本总结是:我们将 NGINX 服务作为容器隔离在控制器容器内。
虽然这并不完全正确,但要理解这里所做的工作,最好了解 Linux 容器(以及底层机制,如内核命名空间)是如何工作的。您可以在 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 图表部署控制器,请在 values.yaml
中更改以下设置
controller:
image:
chroot: true
Ingress 控制器通常在集群范围内设置(IngressClass API 是集群范围的)。如果您管理 Ingress-NGINX 控制器但不是整个集群的操作员,请在您在部署中启用 SYS_CHROOT
功能之前,与您的集群管理员核实您是否可以使用 SYS_CHROOT
功能。
好的,但这如何提高我的 Ingress 控制器的安全性?
请看以下配置代码段,并想象一下,由于某些原因,它被添加到您的 nginx.conf
中
location /randomthing/ {
alias /;
autoindex on;
}
如果您部署此配置,有人可以调用 http://website.example/randomthing
并获得对 Ingress 控制器整个文件系统的某些列表(和访问权限)。
现在,您能发现以下列表中 chrooted 和非 chrooted 的 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 |
左侧的没有 chrooted。因此,NGINX 具有对文件系统的完全访问权限。右侧的已 chrooted,因此创建了一个新的文件系统,其中只有使 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
运行 Ingress 控制器来禁用它。
接下来是什么?
这不是我们的最终目标。我们的最终目标是拆分控制平面和数据平面进程。事实上,这样做也将有助于我们实现 Gateway API,因为一旦我们“知道”要向数据平面提供什么,我们可能会有不同的控制器(我们需要一些帮助!!)
Kubernetes 中的其他一些项目已经采用了这种方法(如 KPNG,建议的 kube-proxy
替代品),我们计划与他们保持一致,并为 Ingress-NGINX 获得相同的体验。
延伸阅读
如果您想了解 Ingress NGINX 中如何进行 chrooting,请查看 https://github.com/kubernetes/ingress-nginx/pull/8337。包含所有更改的 v1.2.0 版本可以在 https://github.com/kubernetes/ingress-nginx/releases/tag/controller-v1.2.0 中找到