本文已超過一年。較舊的文章可能包含過時內容。請確認頁面中的資訊自發布以來是否已變得不正確。

提高 Ingress-NGINX v1.2.0 的安全標準

Ingress 可能是 Kubernetes 中最受關注的組件之一。Ingress 通常定義一個 HTTP 反向代理,暴露於網際網路,包含多個網站,並且具有對 Kubernetes API 的某些特權存取權 (例如讀取與 TLS 憑證及其私鑰相關的密鑰)。

雖然它是您架構中一個有風險的組件,但它仍然是正確公開服務最受歡迎的方式。

Ingress-NGINX 已成為安全評估的一部分,評估結果發現我們有一個大問題:我們在將配置轉換為 nginx.conf 檔案之前,並未進行所有適當的清理,這可能會導致資訊洩露風險。

雖然我們理解這種風險以及修復此問題的實際需求,但這並非易事,因此我們採取了另一種方法來降低 (但並非消除!) 目前 (v1.2.0) 版本中的這種風險。

認識 Ingress NGINX v1.2.0 和 chrooted NGINX 程序

主要挑戰之一是 Ingress-NGINX 與 Ingress 控制器 (可存取 Kubernetes API 並建立 nginx.conf 檔案的組件) 並行執行網頁代理伺服器 (NGINX)。

因此,NGINX 確實具有與控制器相同的檔案系統存取權 (以及 Kubernetes 服務帳戶令牌,以及來自容器的其他配置)。雖然分離這些組件是我們的最終目標,但專案需要快速回應;這引導我們產生了使用 chroot() 的想法。

讓我們看看此變更之前的 Ingress-NGINX 容器外觀

Ingress NGINX pre chroot

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

現在,認識新的架構

Ingress NGINX post chroot

這一切意味著什麼?基本摘要是:我們正在將 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。編輯 Manifest 檔案後,您會看到類似以下的程式碼片段
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 控制器整個檔案系統的某些列表 (和存取權)。

現在,您能發現 chrooted 和非 chrooted 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

左側的那個不是 chrooted。因此 NGINX 可以完全存取檔案系統。右側的那個是 chrooted,因此建立了一個新的檔案系統,其中僅包含使 NGINX 運作所需的檔案。

此版本中還有哪些其他安全改進?

我們知道新的 chroot() 機制有助於解決部分風險,但仍然有人可以嘗試注入命令來讀取,例如 nginx.conf 檔案並提取敏感資訊。

因此,此版本中的另一個變更 (這是選擇退出!) 是深度檢查器。我們知道某些指令或正規表示式可能對 NGINX 構成危險,因此深度檢查器會檢查 Ingress 物件中的所有欄位 (在其協調期間,以及使用驗證 Admission Webhook) 以驗證是否有任何欄位包含這些危險指令。

Ingress 控制器已針對註解執行此操作,我們的目標是將此現有驗證移至深度檢查內部,作為未來版本的一部分。

您可以查看 https://github.com/kubernetes/ingress-nginx/blob/main/internal/ingress/inspector/rules.go 中的現有規則。

由於檢查和比對相關 Ingress 物件內所有字串的性質,此新功能可能會消耗更多 CPU。您可以透過使用命令列參數 --deep-inspect=false 執行 Ingress 控制器來停用它。

下一步是什麼?

這不是我們的最終目標。我們的最終目標是分離控制平面和資料平面程序。事實上,這樣做也將幫助我們實現 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 中找到