使用雙向 TLS 和 Istio 保護應用程式通訊
深入了解如何保護應用程式通訊、mTLS 和 Istio,以在應用程式之間實現端對端 mTLS。
使用者採用服務網格的最大原因之一是使用基於密碼學可驗證身分的雙向 TLS (mTLS) 來實現應用程式之間的安全通訊。在這篇部落格中,我們將討論應用程式之間安全通訊的需求、mTLS 如何實現並滿足所有這些需求,以及使用 Istio 在應用程式之間啟用 mTLS 的簡單步驟。
您需要什麼來保護應用程式之間的通訊?
現代雲原生應用程式經常分佈在多個 Kubernetes 集群或虛擬機器上。新版本會頻繁地被分階段推出,並且它們可以根據使用者請求快速擴展或縮減。由於現代應用程式不再依賴於共置來提高資源利用效率,因此必須能夠對這些分散式應用程式之間的通訊應用存取策略並加以保護,因為多個進入點的增加會導致更大的攻擊面。忽視這一點會導致資料遺失、資料竊取、偽造資料或簡單的處理不當而造成巨大的業務風險。
以下是應用程式之間安全通訊的常見關鍵需求
身分
身分是任何安全架構的基本組成部分。在您的應用程式可以安全地傳送資料之前,必須為應用程式建立身分。這個建立身分的過程稱為身分驗證 - 它涉及一些眾所周知、受信任的授權機構對應用程式工作負載執行一或多個檢查,以確定其是否與聲稱的身分相符。一旦授權機構感到滿意,它就會授予工作負載一個身分。
想想取得護照的行為 - 您會向某個授權機構請求護照,該授權機構可能會要求您提供多種不同的身分驗證,以證明您是您所說的那個人 - 出生證明、目前地址、醫療紀錄等等。一旦您滿足了所有身分驗證,您將(希望)獲得身分證明文件。您可以將該身分證明文件提供給其他人,以證明您已滿足發證機構的所有身分驗證要求,如果他們信任發證機構(以及身分證明文件本身),他們可以信任它關於您的說法(或者他們可以聯絡受信任的授權機構並驗證該文件)。
身分可以採取任何形式,但是,與任何形式的身分證明文件一樣,身分驗證越弱,偽造就越容易,並且該身分證明文件對任何使用它來做出決策的人來說就越沒有用。這就是為什麼在運算中,密碼學可驗證的身分如此重要 - 它們由可驗證的授權機構簽署,類似於您的護照和駕照。基於任何其他形式的身分是一種相對容易利用的安全弱點。
您的系統可能具有源自網路屬性(例如 IP 位址)的身分,以及追蹤身分與這些網路屬性之間對應關係的分散式身分快取。這些身分沒有像密碼學可驗證身分那樣強的保證,因為 IP 位址可以重新分配給不同的工作負載,並且身分快取可能不會始終更新到最新狀態。
為您的應用程式使用密碼學可驗證身分是理想的,因為在連線建立期間交換應用程式的密碼學可驗證身分,在可靠性和安全性方面都優於依賴將 IP 位址對應到身分的系統。這些系統依賴於具有最終一致性和陳舊問題的分散式身分快取,這可能會在 Kubernetes 中造成結構性弱點,而 Kubernetes 中自動化 pod 輪換的高速率是常態。
機密性
加密應用程式之間傳輸的資料至關重要 - 因為在入侵普遍、代價高昂且實際上微不足道的世界中,完全依賴安全內部環境或其他安全邊界早已不再足夠。為了防止中間人攻擊,您需要一個來源-目的地對的唯一加密通道,因為您需要強大的身分唯一性保證來避免混淆代理問題。換句話說,僅僅加密通道是不夠的 - 它必須使用直接從唯一來源和目的地身分衍生的唯一金鑰進行加密,以便只有來源和目的地才能解密資料。此外,您可能需要根據安全團隊的要求自訂加密,例如選擇特定的密碼。
完整性
從來源透過網路傳送到目的地的加密資料,在傳送後不能被來源和目的地以外的任何身分修改。換句話說,接收到的資料與傳送的資料相同。如果您沒有資料完整性,則中間的某人可能會在來源和目的地之間的通訊期間修改一些位元或資料的整個內容。
存取策略執行
應用程式擁有者需要對其應用程式應用存取策略,並使其得到正確、一致且明確的執行。為了對通訊通道的兩端應用策略,我們需要每一端的應用程式身分。一旦我們有了具有明確出處鏈的密碼學可驗證身分,我們就可以開始應用關於誰可以與什麼通訊的策略。標準 TLS 是一種廣泛使用的加密協定,用於保護用戶端(例如,網路瀏覽器)和伺服器(例如,網路伺服器)之間的通訊,它實際上只驗證並強制執行一方(伺服器)的身分。但是,對於全面的端對端策略執行,至關重要的是,雙方(用戶端和伺服器)都具有可靠、可驗證、明確的身分。這是內部應用程式的常見要求 - 例如,想像一下這樣一個場景,只有 frontend
應用程式應該呼叫後端 checkout
應用程式的 GET 方法,但不應允許呼叫 POST
或 DELETE
方法。或者,只有具有特定 JWT 發行者發出的 JWT 權杖的應用程式才能呼叫 checkout
應用程式的 GET
方法。透過利用兩端的加密身分,我們可以確保正確、安全和可靠地執行強大的存取策略,並具有可驗證的稽核追蹤。
FIPS 合規性
聯邦資訊處理標準 (FIPS) 是由國家標準技術研究院 (NIST) 開發的聯邦電腦系統標準和指南。並非所有人都要 FIPS 合規性,但 FIPS 合規性意味著滿足美國政府為保護敏感資訊而建立的所有必要安全要求。與聯邦政府合作時,這是必須的。為了遵循美國政府制定的與網路安全相關的指南,許多私營部門自願使用這些 FIPS 標準。
為了說明上述安全應用程式需求(身分、機密性和完整性),讓我們以 frontend
應用程式呼叫 checkout
應用程式的範例來說明。請記住,您可以將圖表中的 ID 視為任何類型的身分證明文件,例如政府發行的護照、照片識別證
mTLS 如何滿足上述需求?
TLS 1.3(撰寫本文時的最新 TLS 版本)規範的主要目標是在兩個通訊對等方之間提供安全通道。TLS 安全通道具有以下屬性
- 驗證:通道的伺服器端始終經過驗證,用戶端是可選驗證。當用戶端也經過驗證時,安全通道將成為雙向 TLS 通道。
- 機密性:資料已加密,並且只有用戶端和伺服器可見。資料必須使用明確地與來源和目的地身分證明文件進行密碼學綁定的金鑰進行加密,以便可靠地保護應用程式層流量。
- 完整性:透過通道傳送的資料不能在未被偵測到的情況下修改。這保證了只有來源和目的地才擁有金鑰來加密和解密給定會話的資料。
mTLS 內部
我們已經確定密碼學可驗證身分是保護通道和支援存取策略執行的關鍵,並且我們已經確定 mTLS 是一種經過實戰考驗的協定,它對於在通道的兩端使用密碼學可驗證身分強制執行一些極其重要的保證 - 讓我們深入了解 mTLS 協定在底層的實際運作方式。
交握協定
這個握手協定會驗證通訊的雙方、協商加密模式和參數,並建立共享的金鑰材料。換句話說,握手的作用是驗證通訊雙方的身分並協商一個會話金鑰,以便後續的連線可以基於該會話金鑰進行加密。當您的應用程式建立 mTLS 連線時,伺服器和用戶端會協商一個密碼套件,該套件會決定您的應用程式在連線的其餘部分將使用的加密演算法,並且您的應用程式也會協商要使用的加密會話金鑰。整個握手過程的設計目的是為了抵抗篡改 - 任何不具備與來源和/或目的地相同的、可透過加密驗證的身分證明文件的實體的干擾都將被拒絕。因此,在任何通訊方繼續處理應用程式資料之前,檢查整個握手過程並驗證其完整性非常重要。
根據 TLS 1.3 規格中的握手協定概述,握手可以被認為有三個階段 - 再次,讓我們使用一個 frontend
應用程式呼叫後端 checkout
應用程式的例子
- 階段 1:
frontend
和checkout
協商可以用於保護握手過程其餘部分和流量資料的加密參數和加密金鑰。 - 階段 2: 此階段和之後的所有內容都已加密。在此階段,
frontend
和checkout
會建立其他握手參數,以及是否也驗證了客戶端 - 也就是 mTLS。 - 階段 3:
frontend
透過其可透過加密驗證的身分來驗證checkout
(在 mTLS 中,checkout
也以相同方式驗證frontend
)。
自 TLS 1.2 以來,關於握手有一些主要差異,請參閱 TLS 1.3 規格以了解更多詳細資訊
- 所有握手訊息 (階段 2 和 3) 都使用在階段 1 中協商的加密金鑰進行加密。
- 已修剪掉舊有的對稱加密演算法。
- 新增了零往返時間 (0-RTT) 模式,在連線設定時節省了一次往返時間。
記錄協定
在握手階段協商好 TLS 協定版本、會話金鑰和 HMAC 之後,雙方現在可以安全地交換由記錄協定分塊的加密資料。必須 (並且是規範的一部分) 使用握手中完全相同的協商參數來加密流量,以確保流量的機密性和完整性。
將 TLS 1.3 規格中的兩個協定放在一起,並使用 frontend
和 checkout
應用程式來說明流程如下
誰為 frontend
和 checkout
頒發身分憑證?它們通常由憑證授權單位 (CA)頒發,該授權單位本身具有根憑證或使用其根 CA 的中繼憑證。根憑證基本上是一個公鑰憑證,用於識別根 CA,您可能已經在您的組織中擁有該憑證。除了自己的根簽署的身分憑證之外,根憑證也會分發給 frontend
(或 checkout
)。這就是每天基本的公鑰基礎結構 (PKI) 的運作方式 - CA 負責驗證實體的身份證明文件,然後以憑證的形式授予其不可偽造的身份證明文件。
您可以依賴您的 CA 和中繼 CA 作為身分真實性的來源,以一種結構化的方式維持高可用性,以及穩定、可持續驗證的身分保證,這是大量分散式 IP 和身分映射快取所無法做到的。當 frontend
和 checkout
的身分憑證由同一個根憑證頒發時,frontend
和 checkout
可以一致且可靠地驗證其同儕身分,無論它們在哪個叢集、節點或規模上運行。
您了解了 mTLS 如何提供加密身分、機密性和完整性,那麼當您擴展到多個叢集中的數千個或更多應用程式時,可擴展性如何?如果您在多個叢集之間建立單一根憑證,只要該連線受到根憑證的信任,系統就不需要在意您的應用程式何時收到來自其他叢集的連線請求 - 系統知道連線上的身分是經過加密驗證的。當您的應用程式 Pod 變更 IP 或重新部署到不同的叢集或網路時,您的應用程式 (或代表它執行的元件) 只需使用 CA 頒發的受信任憑證向目的地發起流量。它可以是 500 多個網路躍點,也可以是直接的;無論拓撲如何,您的應用程式的存取策略都以相同的方式強制執行,而無需追蹤身分快取並計算哪個 IP 位址對應到哪個應用程式 Pod。
FIPS 合規性如何?根據 TLS 1.3 規格,符合 TLS 標準的應用程式必須實作 TLS_AES_128_GCM_SHA256
密碼套件,並建議實作 TLS_AES_256_GCM_SHA384
,這兩種密碼套件也都在 NIST 的 TLS 指南中。TLS 1.3 規格和 NIST 的 TLS 指南也建議使用 RSA 或 ECDSA 伺服器憑證。只要您將 mTLS 和符合 FIPS 140-2 或 140-3 標準的加密模組用於您的 mTLS 連線,您將走在 FIPS 140-2 或 140-3 驗證的正確道路上。
可能會出什麼問題
完全按照 TLS 1.3 規格的要求實作 mTLS 至關重要。如果沒有按照 TLS 規格使用正確的 mTLS,以下是一些可能在未被偵測到的情況下發生的錯誤
如果連線中有人靜默地捕獲了加密資料怎麼辦?
如果連線沒有完全按照 TLS 規格中概述的握手和記錄協定,例如,連線遵循握手協定,但在記錄協定中未使用握手協商的會話金鑰和參數,您的連線的握手可能與記錄協定無關,而握手和記錄協定之間的身份可能不同。TLS 要求握手和記錄協定共享相同的連線,因為將它們分開會增加中間人攻擊的攻擊面。
mTLS 連線從握手開始到結束都具有一致的端到端安全性。加密資料使用憑證中公鑰協商的會話金鑰進行加密。只有來源和目的地可以使用私鑰解密資料。換句話說,只有擁有私鑰的憑證所有者才能解密資料。除非駭客控制了憑證的私鑰,否則他或她無法使用 mTLS 連線來成功執行中間人攻擊。
如果來源或目的地的身分沒有以加密方式保護怎麼辦?
如果身分基於網路屬性 (例如 IP 位址),而這些網路屬性可能會重新分配給其他 Pod,則無法使用加密技術驗證身分。由於這種身分類型不是基於加密身分,您的系統可能會有一個身分快取來追蹤身分、Pod 的網路標籤、對應的 IP 位址以及 Pod 部署所在的 Kubernetes 節點資訊之間的映射。使用身分快取時,您可能會遇到 Pod IP 位址被重複使用,並且在身分快取短時間內不同步時,會錯誤地識別身分,導致無法正確強制執行策略。例如,如果您在同儕之間的連線上沒有加密身分,您的系統將必須從身分快取中取得身分,而該快取可能已過期或不完整。
這些將身分映射到工作負載 IP 的身分快取並非 ACID (原子性、一致性、隔離性和持久性),並且您希望您的安全性系統應用於具有強大保證的事物。請考慮以下屬性以及您可能想要問自己的問題
- 陳舊性:同儕如何驗證快取中的項目是最新的?
- 不完整性:如果出現快取未命中且系統未能關閉連線,那麼當只有快取同步器發生故障時,網路是否會變得不穩定?
- 如果某個東西根本沒有 IP 位址怎麼辦?例如,AWS Lambda 服務預設沒有公用 IP。
- 非交易性:如果您讀取身分兩次,您會看到相同的值嗎?如果您在存取策略或稽核實作中不小心,這可能會造成實際問題。
- 誰來保護守衛自己?是否有像 CA 那樣保護快取的既定做法?您有什麼證據表明快取沒有被竄改?您是否被迫推理 (並稽核) 某些不是您的 CA 的複雜基礎結構的安全性?
以上有些比其他的更糟。您可以應用失敗關閉原則,但這並不能解決以上所有問題。
身分也用於強制執行存取策略,例如授權策略,而這些存取策略位於請求路徑中,您的系統必須快速做出決策才能允許或拒絕存取。每當身分被錯誤識別時,存取策略可能會在未被偵測或稽核的情況下被繞過。例如,您的身分快取可能將您的 checkout
Pod 先前分配的 IP 位址與其中一個 checkout
身分相關聯。如果 checkout
Pod 被回收,並且相同的 IP 位址剛好分配給其中一個 frontend
Pod,則該 frontend
Pod 在快取更新之前可能會具有 checkout
的身分,這可能會導致強制執行錯誤的存取策略。
讓我們說明假設以下大規模多叢集部署的身分快取陳舊性問題
- 100 個叢集,每個叢集有 100 個節點,每個節點有 20 個 Pod。Pod 的總數為 200,000 個。
- 始終有 0.25% 的 Pod 在更換 (推出、重新啟動、復原、節點更換,…),每次更換的時間為 10 秒。
- 每 10 秒,有 500 個正在更換的 Pod 分配給 10,000 個節點 (快取)
- 如果快取同步器停頓,5 分鐘後系統有多少百分比的陳舊 - 可能高達 7.5%!
以上假設快取同步器處於穩定狀態。如果快取同步器發生斷電,將會影響其健康檢查,進而增加流失率,導致連鎖不穩定。
憑證授權機構(CA)也可能被攻擊者入侵,攻擊者聲稱代表其他人,並欺騙 CA 發出憑證。然後,攻擊者可以使用該憑證與其他對等方通訊。這就是憑證撤銷可以透過撤銷憑證來補救情況的地方,使其不再有效。否則,攻擊者可以利用被入侵的憑證直到過期。將根憑證的私鑰保存在離線的 HSM 中,並使用中繼憑證來簽署工作負載憑證至關重要。在 CA 斷電或停頓 5 分鐘的情況下,您將無法取得新的或續訂的工作負載憑證,但先前發行且有效的憑證會繼續為您的工作負載提供強大的身分保證。為了提高發行的可靠性,您可以將中繼 CA 部署到不同的區域和地區。
Istio 中的 mTLS
啟用 mTLS
在 Istio 中為網格內部應用程式啟用 mTLS 非常簡單。您只需要將應用程式新增至網格中,這可以透過標記您的命名空間以進行 sidecar 注入或環境注入來完成。在 sidecar 的情況下,需要進行一次滾動重新啟動,才能將 sidecar 注入到您的應用程式 pod 中。
加密身分
在 Kubernetes 環境中,Istio 會根據應用程式的服務帳戶建立其身分。在您將應用程式新增至網格後,會向網格中的每個應用程式 pod 提供身分憑證。
預設情況下,您的 pod 的身分憑證會在 24 小時後過期,並且 Istio 每 12 小時輪換一次 pod 身分憑證,以便在發生入侵事件(例如,CA 被入侵或 pod 的私鑰被盜)時,被入侵的憑證只能在非常有限的時間內運作,直到憑證過期,從而限制它可能造成的損害。
強制執行嚴格的 mTLS
預設的 mTLS 行為是盡可能使用 mTLS,但並非嚴格執行。若要嚴格強制您的應用程式僅接受 mTLS 流量,您可以使用 Istio 的 PeerAuthentication 原則,可以是網格範圍、每個命名空間或每個工作負載。此外,您也可以應用 Istio 的 AuthorizationPolicy 來控制您的工作負載的存取權限。
TLS 版本
TLS 版本 1.3 是 Istio 中網格內部應用程式通訊的預設版本,使用 Envoy 的預設密碼套件(例如,Istio 1.19.0 的 TLS_AES_256_GCM_SHA384
)。如果需要舊版的 TLS,您可以為您的工作負載設定不同的網格範圍最低 TLS 協定版本。
總結
網際網路工程任務組(IETF)建立的 TLS 協定是現有經過最廣泛審閱、專家認可、實戰檢驗的資料安全協定之一。TLS 也廣泛應用於全球各地 - 每當您造訪任何受保護的網站時,您都能安心購物,部分原因在於鎖頭圖示,表示您透過 TLS 安全地連線到受信任的網站。TLS 1.3 協定在設計上具有端到端驗證、機密性和完整性,以確保您的應用程式的身分和通訊不會受到入侵,並防止中間人攻擊。為了實現這一點(並被視為符合標準的 TLS),不僅正確驗證通訊對等方非常重要,而且使用握手建立的金鑰加密流量也至關重要。現在您知道 mTLS 在滿足您的安全應用程式通訊需求(加密身分、機密性、完整性和存取原則強制執行)方面表現出色,您可以簡單地使用 Istio 來開箱即用地使用 mTLS 升級您的網格內部應用程式通訊,而且只需極少的組態!
非常感謝 Louis Ryan、Ben Leggett、John Howard、Christian Posta、Justin Pettit 在審閱和提出部落格更新方面投入了大量時間!