本文已超過一年。較舊的文章可能包含過時內容。請確認頁面中的資訊自發布以來是否已變得不正確。
提高 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 容器外觀
如我們所見,提供 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
。編輯 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() |
---|---|
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 物件中的所有欄位 (在其協調期間,以及使用驗證 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 中的其他一些專案已經採用了這種方法 (例如 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 中找到