翻譯自Edge Authentication and Token-Agnostic Identity Propagation。經過本文能夠了解到Netflix是如何經過將認證轉移到邊緣設備來下降系統內容內部的認證流程,以及如何使用統一的認證結構支持系統對身份信息的需求。java
正如大多數開發人員認爲的那樣,對安全協議和身份令牌,以及用戶和設備身份驗證的處理可能會充滿挑戰。假設有不少協議,令牌,200M+的用戶,以及上千個設備,問題可能隨時會在範圍內爆發。幾年前,咱們決定經過發起一個新的計劃,組建一個新的團隊來解決這種複雜性,將用戶和設備身份驗證以及各類安全協議和令牌的複雜處理移至(由一組集中式服務和一個團隊管理的)邊緣網絡上。在這個過程當中,咱們更改了身份在服務之間的傳播方式,轉而使用支持加密驗證且令牌無關的身份對象。後端
經過本文能夠了解到:api
Netflix最初是一個容許會員管理其DVD隊列的網站。該網站後來提供了流內容,流設備稍晚一些,可是這些初始設備的功能受到了限制。隨着時間的推移,流設備的功能愈來愈強大,曾經只能經過網站訪問的功能也拓展到了流設備上。Netflix服務的擴展很是快速,目前已經支持多達2000種設備類型。安全
支持這些功能的服務識別多種令牌以及安全協議(用於驗證用戶和設備,並受權訪問這些功能)的負擔也愈來愈重。整個系統變得至關複雜,開發也變得脆弱。加上邊緣層的架構已經演化到PaaS模型,咱們須要肯定如何,以及在哪裏處理身份令牌。服務器
爲了展現流的複雜度,下面描述了在架構修改前,用戶是如何登陸的:cookie
從最高層面看,此流程(大大簡化)涉及的步驟以下:網絡
該模型有一些問題,如:數據結構
本例展現了處理一個協議(HTTP/S)以及一個令牌類型(Cookies)的流程。在Netflix的流產品中使用了一些協議和令牌,歸納以下:架構
Netflix 的流生態系統會消費(有可能會更改)這些令牌,如:併發
更復雜的是,能夠經過多種方法在系統之間傳輸這些令牌或令牌中包含的數據。在某些狀況下會不斷打開令牌,從中抽取身份數據元素,做爲API調用使用的簡單基元或字符串,或經過請求上下文首部或URL參數在系統間傳遞。整個過程當中並不會檢查令牌或令牌中包含的數據的完整性。
同時,Netflix 的規模在以指數增加。如今,Netflix 已經有200M+的訂閱,以及每個月上百萬個活動的設備。咱們每秒要服務超過2.5百萬個請求,至關大一部分用於某種格式的認證。在老的架構中,每個請求都會觸發一個API調用,用來驗證請求中聲明的內容,以下所示:
後續業務的變更使得狀況變得更復雜,邊緣工程團隊正在將老的API服務架構遷移到一個新的基於PaaS的方式。在咱們遷移到EdgePaaS的同時,先後端服務也從基於Java的API遷移到了BFF(backend for frontend),即NodeQuark:
該模型能夠在不依賴核心API框架的前提下讓先後端工程擁有和操做各自的服務。但這也引入了另外一層複雜性,即這些NodeQuark服務如何處理身份令牌?NodeQuark服務是用JavaScript編寫的,廢除了像MSL這樣複雜又浪費的協議,這些協議會複製全部令牌管理的邏輯。
作個總結,在大規模場景下,發現咱們使用了一個複雜且低效的方案來處理認證和身份令牌。咱們有多種身份令牌類型和資源,每種身份令牌又須要不一樣的處理,各個處理邏輯被複制到了多個系統中。關鍵身份數據以不一致的方式在整個服務器生態系統中傳播。
咱們意識到,爲了解決這個問題,須要一個統一的身份模型,在上游進一步處理身份驗證令牌(和協議)。咱們經過將認證和協議終結轉移到邊緣網絡,而後建立一個新的完整性保護的且令牌無關的對象,使該對象在整個服務器生態系統中傳播。
注意,咱們的目標是提高安全性,並下降複雜度,進而提供更好的用戶體驗,咱們就如何將設備身份驗證操做以及用戶標識和身份驗證令牌管理集中到服務邊緣制定了相應的策略。
從上層看,Zuul(雲網關)做爲令牌檢查和載荷加密/解密的終結點。這種狀況下,Zuul能夠處理這些操做(一小部分),例如,若是沒有出現令牌,則須要更新,不然視爲無效。Zuul會將這些操做委派給一組新的邊緣身份驗證服務,用來處理加密密鑰交換以及令牌的建立或更新。
邊緣認證服務(EAS)是一個架構理念,包含將設備和用戶的認證和身份驗證從棧轉移到雲邊緣,以及用於處理令牌類型而開發的服務套件。
EAS是運行在Zuul中的一系列過濾器,可能會調用外部服務來支持域(domain),如調用一個服務來處理MSL 令牌或Cookies的其餘令牌。EAS涵蓋了爲只讀令牌建立"Passport"(稍後會涉及到)。
EAS處理請求的基本模式以下:
對於每一個進入Netflix 服務的請求,Zuul中的EAS入站過濾器會檢查設備客戶端提供的令牌,而後將請求轉發到"Passport"檢查過濾器(Passport Injection Filter),或某個認證服務進行處理。Passport Injection Filter會生成一個令牌無關的身份,而後使用該身份在剩餘的服務生態系統中傳播。在響應路徑上,在邊緣認證服務的協助下,EAS出站過濾器會生成須要發送到客戶端設備的令牌。
如今系統架構的格式以下:
注意令牌永遠不會越過邊緣網關/EAS邊界。MSL安全協議會在邊緣網關上終結,且全部的令牌會在網關上打開,而後以一種令牌無關的方式在服務生態系統中傳播身份數據。
在新的處理路徑上,Zuul可以處理大量有效且未過時的令牌,邊緣認證服務處理剩餘的請求。
EAS服務具備容錯性,例如在Zuul標識Cookies有效但已過時,且對EAS的續約調用失敗或某些潛在的錯誤狀況下:
這種失敗場景下,Zuul中的EAS過濾器將會容忍這種錯誤,並容許解析後的身份繼續傳播,並在下一次請求時從新調度續約調用。
使用簡單的可變身份結構是遠遠不夠的,由於這樣會致使服務到服務間傳遞的身份缺乏足夠的信任。此時須要令牌無關的身份結構。
咱們引入了一個稱爲"Passport"的身份結構,它容許以統一的方式傳播用戶和設備身份信息。Passport也是一種令牌,但相比使用外部令牌,使用內部結構能帶來不少好處。然而,下游系統仍然須要訪問用戶和設備身份。
Passport 是一種由邊緣網關爲每一個請求建立的短生命的身份結構,即它的生存時間取決於請求的生命週期,且僅在Netflix生態系統內部有效。Passport由Zuul經過一組身份過濾器生成。一個Passport包含用戶&設備身份,格式爲protobuf,其完整性由HMAC保證。
如上所述,Passport 模型爲一個Protocol Buffer。從高層看,Passport 的定義以下:
message Passport { Header header = 1; UserInfo user_info = 2; DeviceInfo device_info = 3; Integrity user_integrity = 4; Integrity device_integrity = 5; }
Header元素傳達了建立Passport的服務的名稱。更有意義的是傳播的與用戶和設備有關的內容。
UserInfo 元素包含識別發起請求的用戶所需的全部信息,DeviceInfo 元素包含用戶訪問Netflix的設備所需的全部信息:
message UserInfo { Source source = 1; int64 created = 2; int64 expires = 3; Int64Wrapper customer_id = 4; … (some internal stuff) … PassportAuthenticationLevel authentication_level = 11; repeated UserAction actions = 12; } message DeviceInfo { Source source = 1; int64 created = 2; int64 expires = 3; StringValue esn = 4; Int32Value device_type = 5; repeated DeviceAction actions = 7; PassportAuthenticationLevel authentication_level = 8; … (some more internal stuff) … }
UserInfo
和DeviceInfo
包含了請求的Source
和PassportAuthenticationLevel
。Source
是一個聲明類型列表,爲使用的協議以及用於驗證聲明的服務。PassportAuthenticationLevel
爲放到認證聲明中的信任的級別。
enum Source { NONE = 0; COOKIE = 1; COOKIE_INSECURE = 2; MSL = 3; PARTNER_TOKEN = 4; … } enum PassportAuthenticationLevel { LOW = 1; // untrusted transport HIGH = 2; // secure tokens over TLS HIGHEST = 3; // MSL or user credentials }
下游應用可使用這些值來進行受權或決定用戶體驗。
Passport 的完整性由HMAC保證(基於哈希的消息認證碼),HMAC是一種特定類型的MAC,涉及密碼哈希函數和密鑰,能夠同時用於校驗數據完整性和消息的真實性。
用戶和設備的完整性定義以下:
message Integrity { int32 version = 1; string key_name = 2; bytes hmac = 3; }
當Integrity的version爲1表示爲HMAC使用SHA-256,編碼爲ByteArray。將來Integrity的version可能使用一個不一樣的哈希函數或編碼。在version爲1時,HMAC字段包含MacSpec.SHA_256中的256位。
完整性防禦保證Passport 字段在Passport建立以後不會改變。客戶端應用能夠在使用其中包含的任何值以前,經過Passport Introspector檢查Passport的完整性。
Passport對象自己是不透明的。客戶端可使用Passport Introspector從首部抽取Passport,並檢索其中的內容。Passport Introspector是Passport二進制數據的包裝器。客戶端能夠經過一個工廠建立一個Introspector,而後就訪問基本的訪問器方法:
public interface PassportIntrospector { Long getCustomerId(); Long getAccountOwnerId(); String getEsn(); Integer getDeviceTypeId(); String getPassportAsString(); … }
下面定義了Passport 協議緩衝,以及Passport Actions 的定義:
message UserInfo { repeated UserAction actions = 12; … } message DeviceInfo { repeated DeviceAction actions = 7; … }
當對用戶或設備身份進行更新時,下游服務會顯示地發送一個Passport Actions。EAS 會使用該信號來建立或更新對應類型的令牌。
讓咱們總結一下全部這些解決方案一塊兒工做的例子。
在將認證和協議終結轉移到邊緣,並引入Passports做爲身份以後,前面所述的登陸流程演變爲了如下內容:
存在外部令牌流入下游系統的緣由是,受權決策常常會依賴令牌中的認證聲明,且信任與各類令牌類型相關聯。在咱們的Passport結構中爲信任分配了不一樣的級別,意味着,須要受權決策的系統能夠圍繞Passport編寫合理的規則,而無需在不少服務的代碼中重複信任規則。
具備規範身份的結構很是有用。傳遞身份原始數據的方式比較脆弱且難以調試。若是在一個調用聲明中,用戶的身份從服務A切換到了服務D,那麼誰會發生改變?一旦身份結構經過全部關鍵系統,一種相對簡單的方式是添加一個新的外部令牌類型,新的信任級別,以及新的方式來表示該身份。
擁有一個像Passport的結構,能夠容許定義一個使用Passport定義的服務,而且能夠被其餘服務校驗。當傳播Passport且在日誌中看到該Passport時,咱們能夠打開、校驗、瞭解其身分內容。也能夠了解到Passport的來歷,並跟蹤到它是如何進入系統的。這使得調試異常身份問題變得更加容易。
傳遞一個統一的結構到下游系統,意味着這些系統可使用內省庫查看設備和用戶身份(因爲使用了相同的結構,所以無需單獨處理各個類型的外部令牌)
經過將令牌處理從這些系統卸載到中央邊緣認證服務上,下游系統在CPU、請求延遲、垃圾回收指標當方面得到了可觀的收益,全部這些均可以幫助下降集羣佔用空間以及雲支出。下面例子中的受益都來源於主要的API服務。
在前面的實現中,每一個請求必須承擔兩次解密/終止開銷,由於咱們須要在邊緣具備路由的能力,且須要在下游服務中具備豐富的終止請求的能力。某些性能的提升歸因於這些功能的合併-如今僅須要處理一次MSL請求。
卸載令牌的處理使得每一個請求的CPU開銷下降了30%,並下降了40%的平均負載。下圖展現了CPU的RPS比率,越低越好:
API服務的響應時間有了很大提高,下降了30%的平均延遲,並使99%的延遲下降20%:
顯著下降了API服務的垃圾回收的壓力,以及GC等待值時間,下圖展現了垃圾回收的STW指標:
將微服務開發人員和身份驗證和身份相關的問題剝離開來,意味着他們能夠專一於其核心領域。如今僅在一組專門的服務中完成一次對身份認證的更改便可,而無需將變動散佈到多個服務中。
咱們目前正在擴展邊緣認證服務來經過一個新的服務"Resistor"支持多因子認證。基於機器學習模型選擇性地爲可疑的鏈接引入第二個因素。隨着加入了新的流程,咱們引入了新的因素,例如使用一次性密碼(OTP)來發送郵件或電話,給移動設備推送通知,以及使用第三方認證應用等。
咱們還可能爲但願在其賬戶上增長安全性的用戶引入可選擇的多重身份驗證。
如今咱們已經有一個系統層面的身份驗證流,在受權決策中咱們可使用該身份驗證流做爲一個信號。去年,咱們開始探索一個新的產品訪問策列(PACS),如今正在將其引入Netflix流產品中。PACS最近爲Streamfest( a weekend of free Netflix in India)的體驗訪問控制提供了支持。