微服務中的授權模式 - osohq

banq發表於2021-12-24

在過去的五個月中,我與 50 多家公司討論了他們的授權系統。他們中的一半以上正在以某種形式使用微服務,我對它們帶來的授權挑戰著迷。似乎沒有人就面向服務的後端授權的最佳實踐達成一致:我與將使用者角色附加到身份驗證令牌的團隊、將所有內容儲存在特定於授權的圖形資料庫中的團隊以及在 Kubernetes 中自動執行授權檢查的團隊進行了交談。這些解決方案已經進行了數月或數年的工程工作,每個團隊都發明瞭自己的輪子。為什麼?

當你有一個單體時,你通常只需要與一個資料庫交談來決定是否允許使用者做某事。單體應用中的授權策略不需要過多關注在哪裡可以找到資料(例如使用者角色)——你可以假設所有資料都可用,如果需要載入更多資料,它可以很容易從單體的資料庫中提取出來。

但是分散式架構的問題變得更加困難。也許您正在將單體應用拆分為微服務,或者您正在開發一個新的計算密集型服務,該服務需要在執行作業之前檢查使用者許可權。現在,決定誰可以做什麼的資料可能並不那麼容易獲得。您需要新的 API,以便您的服務可以相互討論許可權:“誰是該組織的管理員?誰可以編輯此文件?他們可以編輯哪些文件?” 為了在服務 A 中做出決策,我們需要來自服務 B 的資料。服務 A 的開發人員如何要求這些資料?服務 B 的開發人員如何提供這些資料?

這些問題有很多答案,所以我試圖將它們組織成幾個廣泛的模式。這些模式不一定能捕捉到解決方案世界的全部複雜性,但我發現它們可以幫助我與不同的人談論他們構建的內容。當我與新團隊交談時,它們使我更容易對解決方案進行分類。

在構建微服務時,我看到了處理授權資料的三種主要模式。我將在這篇文章中討論所有三個:

  1. 將資料留在原處,讓服務直接請求它。
  2. 使用閘道器將資料附加到所有請求,因此它隨處可用。
  3. 將授權資料集中到一個地方,並將所有決策轉移到那個地方。

  

為什麼微服務的授權更難?

我們以授權場景為例,一個用於編輯文件的應用程式。這是微不足道的,但希望能說明問題:

  • 有使用者、組織和文件。
  • 使用者可以在組織內擁有角色,member或者admin。
  • 檔案屬於組織。
  • 如果使用者member在組織中具有角色,則她可以閱讀文件。
  • 如果使用者admin在組織中具有角色,則她可以閱讀或編輯文件。

在單體應用中,以乾淨的方式表達該邏輯並不太難。當您需要檢查使用者是否可以閱讀文件時,您可以檢查該文件屬於哪個組織,為該組織載入使用者的角色,然後檢查該角色是否為member或 之一admin。這些檢查可能需要額外的一兩行 SQL,但資料都在那裡。

當您將應用程式拆分為不同的服務時會發生什麼?也許您已經剝離了一個新的“文件服務”——現在,檢查對特定文件的讀取許可權需要檢查位於該服務資料庫之外的使用者角色。文件服務如何訪問它需要的角色資料?

 

模式 1:將資料保留在原處

通常,最簡單的解決方案是將資料保留在原處,並讓服務在需要時請求他們需要的資料。鑑於上述問題,您可能會認為這是最明顯的解決方案。

您拆分資料模型和邏輯,以便文件服務控制由哪個角色授予哪些與文件相關的許可權(管理員可以編輯,成員可以閱讀等),然後使用者服務公開一個 API 來獲取使用者的角色一個組織。有了這個 API,許可權檢查可以像這樣發生:

微服務中的授權模式 - osohq

有一個合理的論點認為最簡單的解決方案是最好的解決方案,這通常適用於這裡。根據我的經驗,這通常是當團隊開始轉向微服務並且只想讓某些東西工作時的著陸點。它可以完成工作,並且不需要任何額外的基礎設施。

當服務或團隊數量增加、授權邏輯變得更加複雜或面臨更嚴格的效能要求時,這種模式開始出現裂縫。為了實現這一目標,任何新服務的開發人員都需要知道如何從使用者服務中獲取角色資料,而使用者服務本身必須進行擴充套件以滿足該需求。隨著服務依賴性的激增,該模式可能會增加不可預測的延遲和重複請求。也許引入單獨的“資料夾”服務會使許可權檢查成為服務之間的聊天網路:

微服務中的授權模式 - osohq

儘管它有變得有點混亂的風險,但這種模式可以讓你走得很遠。不必為授權部署和維護額外的基礎設施可能是一個巨大的優勢,如果帶有資料的服務可以處理來自需要資料的服務的負載,那麼將它們串在一起是一個很好的解決方案。

我已經與一些遵循這種一般模式的團隊進行了交談,但他們覺得他們應該用某種專門的授權服務來替換所有的管道。我總是確保問他們真正的問題是什麼。如果是延遲,也許在正確的位置新增快取可以解決它。如果授權邏輯在服務本身中變得雜亂無章,那麼也許您需要強加標準的策略格式。(Oso 是一種解決方案;還有其他解決方案。)

但是,如果問題是您的資料模型變得過於複雜,或者您重複地重新實現相同的 API,或者許可權檢查需要與太多不同的服務進行互動,那麼也許是時候重新考慮架構了。

 

模式 2:請求閘道器

授權資料問題的一種乾淨的解決方案是將使用者的角色包含在對所有可能需要做出決定的服務的任何請求中。如果文件服務在請求中獲取有關使用者角色的資訊,則它可以基於此做出自己的授權決策。

微服務中的授權模式 - osohq

在這種模式中,“閘道器”位於 API 與其終端使用者之間。閘道器可以訪問使用者資訊和角色資訊,它可以在將請求傳遞給 API 本身之前將這些資訊附加到請求中。當 API 收到請求時,它可以使用請求中的角色資料(即在其標頭中)來檢查使用者的操作是否被允許。

閘道器通常負責身份驗證和授權。例如,閘道器可能使用Authorization標頭對特定使用者進行身份驗證,然後另外獲取該使用者的角色資訊。然後閘道器將帶有使用者 ID 和角色資訊的請求代理到下游服務(上例中的文件服務)。

微服務中的授權模式 - osohq

閘道器模式的主要好處是其架構簡單。它允許下游服務(如文件服務)的開發人員不必關心角色資料來自何處。授權資料始終在請求中可用——可以立即執行許可權檢查,無需任何額外的往返。

請注意,在這裡使用裸頭確實開闢了新的攻擊途徑——您需要確保惡意客戶端無法注入他們自己的頭。作為替代方案,使用者的角色或其他訪問控制資料可以包含在他們的身份驗證令牌本身中,通常表示為JWT

如果您的授權資料包含少量角色(例如,每個使用者在一個組織中只能擁有一個角色),則閘道器最有效。當許可權開始不僅僅取決於使用者在組織中的角色時,請求的規模可能會激增。也許使用者可以根據他們嘗試訪問的資源型別(特定事件的組織者或特定資料夾的編輯者)具有不同的角色。有時,這些資料太大而無法合理地放入標題中,而有時急切地獲取所有這些資料的效率很低。如果是這種情況,將所有相關的授權資料填充到令牌或標頭中並不能完全削減它。

 

模式 3:集中所有授權資料

另一種解決方案是將所有授權資料和邏輯放在一個地方,與所有需要強制執行授權的服務分開。實現這種模式最常見的方法是構建一個專門的“授權服務”。然後,當你的其他服務需要進行許可權檢查時,他們會轉身詢問授權服務:

微服務中的授權模式 - osohq

在這個模型中,文件服務根本不關心使用者的角色:它只需要詢問授權服務使用者是否可以編輯文件,或者使用者是否可以檢視文件。授權服務本身包含做出該決定所需的一切(包括角色資料)。

這可能非常有吸引力:您現在擁有一個負責授權的系統,這符合微服務的理念。以這種方式分離關注點有一些優點:你團隊中的其他開發人員不需要關心授權是如何工作的。因為它是獨立的,所以您對授權服務所做的任何優化都有助於加快整個系統的其餘部分。

當然,這種關注點分離是有代價的。現在所有授權資料都必須存放在一個地方。決策中可能使用的所有內容——使用者在組織中的成員身份、文件與其組織的關係——都必須存在於集中式服務中。要麼授權服務成為該資料的唯一真實來源,要麼您必須將資料從應用程式複製和同步到該中心位置(更有可能)。授權系統必須瞭解作為任何許可權基礎的整個資料模型:組、共享、資料夾、來賓、專案。如果這些模型經常變化,系統就會成為新開發的瓶頸。任何微服務的任何更改都可能需要更新授權服務,

還有其他因素使授權服務變得棘手:部署負責保護每個請求的服務意味著您負責實現高可用性和低延遲。如果系統出現故障,每個請求都會被拒絕。如果系統對查詢響應緩慢,則每個請求都很慢。

Google 的 Zanzibar 論文概述了這種模式的一種實現,但它也帶來了自己的挑戰。您必須將所有資料作為“元組”插入 Zanzibar(Alice 擁有此文件,此資料夾包含此其他資料夾等)。並且因為它限制了它可以儲存的資料,所以有些規則實際上無法單獨用 Zanzibar 來表達:與時間、請求上下文或依賴於某種計算有關的規則。有些人稱這些為“基於屬性”的規則。例如,使用者每週只能建立 10 個文件,或者管理員可以將某些資料夾設定為“只讀”,以防止對其子文件進行編輯。在這些情況下,開發人員必須在 Zanzibar 之外編寫自己的策略邏輯。

將您的授權集中到一個地方的挑戰傳統上阻止了大多數團隊採用這種模式。那些確實傾向於擁有大量服務和足夠複雜的資料模型——對他們來說吸收授權服務本身增加的複雜性是有意義的。例如,Airbnb構建了一個名為 Himeji 的授權服務,以支援他們從單體應用轉向微服務的模型。它有一個專門的工程師團隊為它工作兩年,並且可能會無限期地工作。

但是,如果您可以削減其中的一些開銷,對於許多使用微服務構建的團隊來說,集中式授權服務可能是一個有吸引力的選擇。我的團隊正在努力構建授權服務,同時避免集中所有授權資料的挑戰。

 

你應該使用哪一個?

在與工程團隊交談時,我的指導始終是“圍繞應用程式構建授權,而不是相反”。對於維護大量額外基礎設施成本高昂的簡單系統,最好將資料保留在原處,並將您的服務與專門構建的 API 結合在一起。某些應用程式可以增長到大規模,只需要適合 JWT 的基本使用者角色——在這種情況下,也許授權閘道器是最佳的。一些擁有多種產品、授權模式和使用者型別的公司可能更願意努力將他們的資料集中到一個專門的授權服務中。

 

相關文章