本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。

在 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 容器是什麼樣子

Ingress NGINX pre chroot

正如我們所看到的,提供 HTTP 代理的容器(不是 Pod,而是容器!)是監視 Ingress 物件並寫入容器卷的容器

現在,認識一下新架構

Ingress NGINX post chroot

這一切意味著什麼?一個基本的總結是:我們將 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()
binbin
devdev
etcetc
home
liblib
media
mnt
optopt
procproc
root
runrun
sbin
srv
sys
tmptmp
usrusr
varvar
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 中的其他一些專案已經採取了這種方法(例如 KPNGkube-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 找到。