從古典樸素的安全哲學談起
Aliware
網絡安全現狀
現在最常見的企業網絡安全架構便是在企業網絡邊界處做安全防護,而在企業網絡内部不做安全防範。這确實為企業的安全建設省了成本也為企業提供了一定的防護能力。但是這類比于現實情況的一個小區,這個小區裡面所有的房屋都沒有門,小區的門口站着一個保安,由他來鑒别誰能進入小區,誰不能進入小區,隻要保安放行了一個人進入小區,這個人就可以在小區裡為所欲為。那麼大家會住在這個小區嗎?我想大家都是不會的。
為什麼我們不會呢,因為這樣的小區太脆弱了,隻要有辦法繞過門口的保安,這種防護就形同虛設。例如一個小偷冒充裡面的住戶、尾随一個使用者或者勾結裡面的使用者裡應外合都能突破保安這道防線。類比于網絡環境中,一個黑客盜用員工賬号、重放連結複用、勾結企業員工都可以突破網絡邊界處的安全。
零信任的要求
零信任在這樣的背景下應運而生,零信任要求将所有的安全防護沉澱到應用級别,即每個應用都需要對請求進行身份認證和鑒權。
a. 認證就是确認你是誰。
我們依舊以剛剛的小區舉例。頒發身份就是你拿着房産證等等材料去居委會,居委會給你一個通行證,這個通行證就辨別了你是這個小區的住戶,且标明了你的身份是誰。當然這個通行證舊了,你還得拿着材料去居委會換一張新的。
在零信任的要求中,一個用戶端或者服務端需要攜帶 token 向證書頒發機構拿驗證書,這個證書就唯一标明了這個用戶端或服務端的身份,之後用戶端、服務端向其他用戶端、服務端請求時,均需要拿着這個證書以聲明自己的身份。證書在一定時間後就會過期,那麼就需要重新執行去拿去證書。
b. 鑒權就是确認你有什麼權利。
住戶拿着通行證可以獲得對應房屋的鑰匙,這把鑰匙隻能打開指定房屋的門
在零信任的要求中,每個證書身份都有對應的權利,比如你隻能通路 A 服務,不能通路 B 服務等等。每個服務會執行相應的規則,攔截不符合規則的請求,放行符合規則的請求。
零信任除了上述的基本功能外,仍需一定額外的功能,例如:
a. 認證可變化:認證和授權必須嚴格執行,并且要求動态可變。對于授權的給予,需要根據網絡情況、企業組織架構、網絡威脅、身份變換不斷地評估資源。對于授權的給予應該有動态政策驅動。
b. 可見性和監控:必須收集、分析和使用有關資産目前狀态及其通信的資訊,以改善組織的安全态勢。必須持續監控所有資産的完整性和安全性,并且必須及時緩解安全狀況的偏差。此外,這些發現應回報到客戶風險評估和身份驗證程式中,以進一步提高其品質。
c. 審計與合規性:安全資料保留和全面的合規報告是應對監管的剛需。
Istio:零信任的優秀建構者
Aliware
Istio 的零信任建構方案
服務網絡 Istio 在零信任方面建構較為完善,在服務網絡中,存在 3 種角色:
- 控制面 Istiod:每個服務網絡中存在一個 Istiod,作為控制面,統籌管理服務網絡中的所有應用。
- 使用者應用:使用者運作的應用。
- 資料面 proxy:每個運作在服務網絡中的使用者應用均擁有一個 proxy 容器,其代理了使用者應用的所有流量。所有從使用者應用出的流量和入的流量均需經過 proxy 容器。
在服務網絡中,關于零信任最核心的兩個功能,認證和鑒權的具體行為如下:
- 認證:在 proxy 啟動時,proxy 會攜帶 k8s 塞在容器裡面的 token 向 istiod拿驗證書。之後任何服務之間的調用均需雙向認證。例如 A 向 B 發起請求,A需要驗證 B 的證書,B 也需要驗證 A 的證書。
- 鑒權:控制面 istiod 會向所有 proxy 分發鑒權規則,每個 proxy 會根據規則,放行請求或者拒絕請求。
Istio 方案的一些不足
Istio 的零信任方案已經非常優秀了,如果硬要說有哪些不足,我們在可以從如下方面考慮:
a. 在認證政策方面:Istio 的信任來源于 k8s 叢集不會被人攻破,pod 中的 token 不會被人竊取。驗證 token 時以信任 apiserver 為基礎;istio 的認證政策單一。
b. 在身份辨別方面:Istio 頒發的證書中,用于辨別身份的字段 object 使用 spiff 标準。需要強依賴 K8s 的 namespace 和 serviceaccount;身份辨別不夠通用。
c. 在鑒權規則方面:Istio 的鑒權規則粒度十分細,但是有許多規則比對與 K8s 的概念強依賴,例如要求請求必須來源于某個 namespace;其次仍有部分規則的缺失,例如應用部署環境級别的鑒權等等。
Sentinel 2.0:我們期望微服務下的安全底座該是什麼樣?
Aliware
Sentinel 是什麼
Sentinel 開源伊始,注重于對應用運作态時保護,側重于流控降級,包括熱點流控、熔斷降級、自适應過載保護、并發隔離、流量控制與平滑等。
2022 年,Sentinel 宣布品牌更新,從 Sentinel 1.0 更新為 Sentinel 2.0,并與 OpenSergo 關聯,注重于應用全生命周期的保護。包括标準化、流量控制與自愈、服務容錯、服務隔離、流量路由與染色、零信任等。
Sentinel 中的零信任功能涉及零信任最核心的兩個功能,即證書管理與鑒權規則。
我們也在 Sentinel 社群提了相關的 issue[1],希望可以建設起 Sentinel2.0 的零信任安全能力。
With the development of cloud-native technologies, network boundaries are gradually disappearing, and the concept of zero trust therefore prevails. The most important functions of zero trust are certificate management and request authentication. As a generic, cloud-native traffic governance component, Sentinel 2.0 will support zero-trust capabilities for certificate management and request authentication:
- Obtain the certificate from the external data source and use it to configure https when the web service is enabled.
- Obtains authentication rules from the external data source and permits or blocks each request based on the authentication rules.
Sentinel 的零信任如何做
讓我們來詳細聊聊 Sentinel 2.0 的零信任能力如何做更适合社群的發展,能為我們的微服務生态提供安全的底座能力。
目前在 Sentinel 和 OpenSergo 的生态中:
- OpenSergo:作為規則管理與下發的中心放,定位類似于服務網絡中的控制面。
- Sentinel:作為依賴包被應用引入,定位類似于服務網絡中的一個資料面。
對于零信任的兩個核心功能認證和鑒權,Sentinel 和 OpenSergo 将會如下做:
- 認證:Sentinel 攜帶 token 向 OpenSergo 擷取相應的證書。OpenSergo 會根據相應的政策判斷 token 的合法性,頒發相應的身份證書,Sentinel 會在證書過期時自動輪轉證書。Sentinel 首先會支援與 Istio 的 k8s-apiserver 的認證政策,并在後續繼續支援 OPA、IDaas 等認證政策。
- 鑒權:使用者可以配置鑒權的 CRD 至 OpenSergo,OpenSergo 将會轉化為标準的 XDS 下發至 Sentinel,Sentinel 會儲存關于本應用的所有鑒權規則,并根據鑒權規則為應用自動放行或者拒絕請求。鑒權規則總共包含 JWT 規則、deny 規則和 allow 規則。
為了更好地讓零信任能力演進,需要統一的零信任 CRD 規則,CRD 在相容 Istio 的基礎上适當拓展。該 CRD 總共涉及 3 個方面,分别為:
a. TlsMode:認證政策,請求是否需要驗證雙方身份。
b. JWT: JWT 政策,如何驗證請求中符合 JWT 規範的 token。
c. Auth:鑒權政策,判斷何種請求會通過,何種請求會不通過。
一個 Auth 的執行個體 CRD 如下:
apiVersion: security.istio.io/v1beta1
kind: AuthorizationPolicy
metadata:
name: httpbin
namespace: default
spec:
action: DENY
rules:
- from:
- source:
# 需要比對的身份
principals: [ "principal1","principal2" ]
# 需要不比對的身份
notPrincipals: [ "notPrincipal1","notPrincipal2" ]
# 需要比對的JWT中iss+"/"+sub
requestPrincipals: [ "jwtp1","jwtp2" ]
# 需要不比對的JWT中iss+"/"+sub
notRequestPrincipals: [ "notjwtp1","notjwtp2" ]
# 需要比對的命名空間
namespaces: [ "namespace1","namespace2" ]
# 需要不比對的命名空間
notNamespaces: [ "notNamespace1","notNamespace2" ]
# 需要比對的直接來源ip
ipBlocks: [ "10.1.1.1","10.1.1.0/24" ]
# 需要不比對的直接來源ip
notIpBlocks: [ "11.1.1.1","11.1.1.0/24" ]
# 需要比對的請求最初ip,最初請求的來源ip來自于header中X-Forwarded-For的值
remoteIpBlocks: [ "12.1.1.1","12.1.1.0/24" ]
# 需要不比對的請求最初ip ,最初請求的來源ip來自于header中X-Forwarded-For的值
notRemoteIpBlocks: [ "13.1.1.1","13.1.1.0/24" ]
- source:
principals: [ "principal3" ]
to:
- operation:
# 需要比對的到達域名
hosts: [ "www.host1.com","www.host2.com" ]
# 需要不比對的到達域名
notHosts: [ "www.nothost1.com","www.nothost2.com" ]
# 需要比對的到達端口
ports: [ "8080","443" ]
# 需要不比對的到達端口
notPorts: [ "18080","1443" ]
# 需要比對的請求方法
methods: [ "GET","POST" ]
# 需要不比對的請求方法
notMethods: [ "PUT","DELETE" ]
# 需要比對的請求path
paths: [ "/info1*","/info2" ]
# 需要不比對的請求path
notPaths: [ "/notinfo1*","/info2" ]
- operation:
hosts: [ "www.host3.com" ]
我們也在 OpenSergo 社群提了相關的 issue[2],希望可以建設起規範的零信任 CRD。
We want to add a standard CRD on the zero-trust direction to OpenSergo.
The CRD will be expanded to be compatible with istio.
The CRD involves three aspects in total, namely
1. TlsMode: Authentication policy, whether to authenticate both parties.
2. JWT: JWT policy, how to verify tokens in a request that comply with the JWT specification.
3. Auth: Authentication policy that determines which requests are approved and which requests are rejected.
Sentinel 的代碼結構
在 sentinel 的代碼中關于零信任的部分,将會分為三層:
- extension:在 sentinel 的 extension 包中将會完成證書拉取、XDS 的接收、鑒權規則的轉換。
- core:在 sentinel 的 core 層定義證書、鑒權規則的實體,并存儲證書、鑒權規則。
- adapter:在 sentinel 的 adapter 層将會提供适配于 mvc、webflux、dubbo 的各種擴充卡。
Spring Cloud Alibaba、Dubbo、Spring Boot 應用可以使用擴充卡或者直接使用 core 的實體讓證書以及規則生效。
根據 3.2 中所示,Spring Cloud Alibaba、Dubbo、Spring Boot 适配 Sentinel 中存儲的證書、規則實體均需要一定改變。
SpringCloud Alibaba 适配
如何适配 TlsMode:
SpringCloud Alibaba 無法實作單端口雙協定,也就是無法實作 TlsMode 中的相容模式。是以僅支援雙模式:PERMISSIVE、DISABLE 均為明文模式,STRICT 為嚴格模式。
适配 JWT、RBAC:
SpringCloud Alibaba 是在使用者的 springcloud 上使用,是以本身就處理 http 請求,是以完全适配 JWT、RBAC。
Dubbo 适配
适配 TlsMode:
Dubbo 适配單端口雙協定,适配該模式
适配 JWT:
- Dubbo 的傳輸協定中無 header 和 params 的概念,但是存在 Attachments 的字段,
- 對于 CRD 中的 fromHeaders 映射從 Attachments 字段拿取。
- 對于 CRD 中的 fromParams 規則失效。
适配 RBAC:Dubbo 中無 paths、methods、header 的概念。
- 對于 CRD 中 header 的規則生效于 Dubbo 的 Attachments 字段。
- 對于 CRD 中的 methods 的規則無效。
- 對于 CRD 中的 paths 規則變為 /package.service/method
Dubbo 适配 CRD 的政策我們參考自 istio 對于 rpc 風格的說明:
Optional. A list of paths as specified in the HTTP request. See the Authorization Policy Normalization for details of the path normalization. For gRPC service, this will be the fully-qualified name in the form of “/package.service/method”.
If not set, any path is allowed. Must be used only with HTTP.
平滑更新:微服務零信任仍需努力的道路
Aliware
平滑更新的問題
雖然 Sentinel 中建構了拉驗證書、擷取鑒權規則、接入起效的基本架構,但是接入時,仍存在平滑相容的問題。零信任中最基礎的能力為将所有調用鍊路從明文傳輸更新為 mtls 傳輸,即雙向的身份認證。
我們以最常見的應用之間調用協定 http 協定為例,零信任的要求為所有調用鍊路均設定為 https。當然,理想情況是使用者将所有的應用停止,将所有的應用的 http 端口更新為 https 端口,之後全部重新開機。然而,這并不現實,真實的情況是,使用者将所有的應用的執行個體依次接入零信任的功能。
如圖所示,假定調用鍊路為業務網關->應用 A->應用 B->應用 C,并設定應用 A 和應用 B 有兩個執行個體,應用 C 有 1 個執行個體。
在使用者初始态時,應用之間所有的調用均使用 http 協定。
之後,進入使用者切換中間态,使用者依次更新應用并接入零信任能力,在該過程中,有如下要求:
a. 調用鍊路的前後側均接入零信任時使用 https 協定,例如,在圖中的使用者切換中間态時應用 A 執行個體 1 接入零信任功能,應用 B 執行個體 1 接入零信任功能,是以應用 A 執行個體 1->應用 B 執行個體 1 為 https 協定。
b. 如果調用鍊路前側未接入零信任功能,後側接入零信任功能,應該使用 http 協定,例如,應用 A 執行個體 2 未接入零信任功能,應用 B 執行個體 1 接入零信任功能,是以應用 A 執行個體 2->應用 B 執行個體 1 為 http 協定。
c. 如果調用鍊路前側接入零信任功能,後側未接入零信任功能,那麼應該沒有調用鍊路,例如,應用 A 執行個體 1 接入零信任功能,應用 B 執行個體 2 未接入零信任功能,是以應用 A 執行個體 2 和應用 B 執行個體 2 不存在調用鍊路。
最終,在使用者最終态時,所有應用均接入了零信任能力,所有的調用鍊路均需為 https 協定。
相容方案
從上述發現,在切換中間态時,一個應用的執行個體在接入零信任之後,必須同時擁有處理 https 和 http 的能力,在終态時,關閉處理 http 的能力,僅保留 https 的能力。
根據上述情況,并依據 istio 對于 PeerAuthentication 的定義,可以設定如下模式:
- STRICT(嚴格模式,終态):應用之間必須使用 https 通信。
- PERMISSIVE(相容模式,中間态):應用之間優先選用 https 協定通信。例如,對于調用鍊路應用 A->應用 B(如圖中的切換中間态,執行個體 1 開啟 https 端口,執行個體 2 還未開啟 https 端口),應用 A 選擇執行個體 1 通信時使用 https 端口,選擇執行個體 2 通信時使用 http 端口。
- DISABLE(明文模式,初始态):應用之間必須使用 http 通信。
那麼如果使用者選擇更新應用執行個體,使其最終從 http 變為 https,并且在過程中流量不能損失,可以根據如下步驟更新應用執行個體:
使用者重新開機應用執行個體并接入零信任功能,在啟動後預設明文模式 -> 啟用相容模式 -> 監控應用執行個體流量已經全部轉入 https -> 使用嚴格模式。
istio 對于 PeerAuthentication 的定義包含 4 個模式,分别為:
UNSET:Inherit from parent, if has one. Otherwise treated as PERMISSIVE.
DISABLE:Connection is not tunneled.
PERMISSIVE:Connection can be either plaintext or mTLS tunnel.
STRICT:Connection is an mTLS tunnel (TLS with client cert must be presented).
引文:
https://istio.io/latest/docs/reference/config/security/peer_authentication/#PeerAuthentication
那麼根據上述要求,必須做一個應用執行個體的中間态,該中間态必須保證應用執行個體能夠同時處理 http 和 https 請求,可以給出了如下兩個方案:
a. 額外開啟 https 端口的方案:該方案為新開啟一個與 http 端口不重複的https端口,并在注冊中心注明 2 個端口。例如,可以在注冊中心的 metedata 中帶入如下資訊,标明雙端口:
該方案最大的問題是相容性不好,與服務網絡、網關均無法很好适配,其次于大多數使用者,新起端口有報備要求
b. 單端口雙協定的方案:該方案最大的問題是不好實作,對于最常用的 tomcat而言,tomcat 原生不支援單端口雙協定,但是對于 tomcat 中的 nio 模式,可以通過改造源碼或者使用位元組碼增強技術實作單端口雙協定。tomcat 的 arp 模式使用 native 模式根本無法實作切面。
讓微服務應用無感、平滑更新至零信任方案,這是零信任方案是否能被大規模使用的關鍵條件之一,我們希望能夠幫助我們企業微服務做到無感的預設安全。
展望
Aliware
為了讓零信任更好、更便捷地落地,我們還有很多工作需要去完成。例如:
a. CI/CD 內建:将零信任的規則內建在 CI/CD 中,更加自動化的配置安全政策
b. 自适應調整:當一個應用外部環境改變,比如部署環境改變、應用從屬部門改變,安全政策自适應的改變。
c. 預設安全:如何保證應用釋出時無需配置,根據環境、開發者身份等等資訊,自動生成安全政策,使得應用預設時安全的。
讓微服務能夠真正實作簡單友善的零信任,仍有許多的道路要走,這或許隻是個開始。也歡迎各位志同道合的同學們一起參與建設。
作者:涯客、十眠
來源:微信公衆号:阿裡巴巴中間件
出處:https://mp.weixin.qq.com/s/PjD5EbMzBaEAiOnIRPxayg