基於角色的訪問控制(RBAC):演進歷史、設計理念及簡潔實現

譯者序

本文翻譯自 2021 年的一篇英文博客:RBAC like it was meant to be。

很多系統(例如 Kubernetes、AWS)都在使用某種形式的 RBAC 做權限 / 訪問控制。

本文基於 access control 的發展歷史,從設計層面分析了 DAC -> MAC -> RBAC -> ABAC 的演進歷程及各模型的優缺點、適用場景等, 然後從實際需求出發,一步步地設計出一個實用、簡潔、真正符合 RBAC 理念的訪問控制系統。

作爲對比,如果想看看錶達能力更強(但也更復雜)的 RBAC/ABAC 系統是什麼樣子,可以研究一下 AWS 的訪問控制模型。

由於譯者水平有限,本文不免存在遺漏或錯誤之處。如有疑問,請查閱原文。

以下是譯文。

大部分人都聽說過基於角色的訪問控制(role-based access control, RBAC)以及它 的後繼演進版基於屬性的訪問控制(attribute-based access control, ABAC), 但我們經常遺忘或不懂得欣賞其中的偉大思想。

大部分如今常見的 RBAC 系統都經過了某種程度的簡化,因此比最初的設計要弱一些。而本文想要說明,只要回到 RBAC 最初的設計,我們就能構建一個 真正的 RBAC/ABAC 安全模型 ,它比你能見到的那些系統更簡單而強大,而且不管網絡規模大還是小,它都能適用。

客戶經常跟我們反饋說,他們如何震驚於如下事實:在 Tailscale 平臺上, 只用如此少的規則就能表達他們的安全策略。這並非偶然!但在解釋爲什麼之前,我們先來回顧一些歷史。

1 從 DAC 到 MAC

RBAC/ABAC 的概念和術語都源自幾十年前的美國軍方。Role-Based Access Controls (Ferraiolo and Kuhn, 1992) 是一篇很好的介紹。下面來看一下它們的一些演進過程。

1.1 DAC(自主訪問控制):各文件 owner 自主設置文件權限

最早出現的是 DAC(Discretionary Access Control),直到今天仍然很常見。

設計

如下圖所示,在 DAC 中 object owner 有權設置該 object 的訪問權限。

DAC:通過授予 individuals/groups 以 read/write/execute 權限, object (file) 的創建者能完全控制該 object 的內容和權限。

例如,

  1. 在 Unix 系統中,設置 file permission(“模式”,這也是 chmod change mode 的來歷) 就能授予別人 讀/寫/執行 這個文件的權限。

  2. 在 Google Doc 中,點擊 share 按鈕能授予權限。

使用場景:普通用戶的文件權限控制

1.2 MAC(強制訪問控制):(強制由)專門的 admin 設置文件權限

注意:不要把 MAC (mandatory access control) 與網絡術語 “MAC address” 中的 MAC (media access address) 搞混了,二者沒有任何關係,只是碰巧縮寫相同。

設計:DAC 基礎上引入專門的 admin 角色

MAC (Mandatory access control) 對 DAC 做了增強。如下圖所示, 由 administrator(管理員)或 administrative rule(管理員級別的規則) 來定義 rules。

MAC:文件 owner 只能設置一個文件 type,這個 type 包含了哪些權限是由 admin 或 policy 設置的。用戶能編輯文件內容,但無法修改文件權限。

因此在 MAC 模型中,一個人做某些事情的 能力是無法再分享給其他人的,從而避免了文件被 reshare 的問題。

例子:TCP/UDP 端口號

MAC 很難解釋,因爲在實際中很少看到它,甚至看到了之後,你都不覺得它是 “訪問控制”。

Wikipedia 給了一個很好的例子:TCP 或 UDP 端口號。當你佔用了一個 local port 之後(假設沒設置 SO_REUSEADDR), 這臺機器上的其他任何人就都無法再用這個端口號了 —— 不管他們是什麼級別的特權用戶。這裏,端口範圍不可重疊這一條件,就是強制性的(mandatory)。

適用場景:文檔 / 系統訪問控制

之前關於 file locking 的文章中,我討論了 advisory locks 和 mandatory locks 之間的區別:

可以看出,MAC 適用於對文檔或系統的訪問控制,這就不難理解爲什麼 軍方對 MAC —— 至少在理論上 —— 如此興奮了。理想場景:

在這種場景下,你自己有權限查看房間內的文檔,但無法將其分享給其他人。

這個例子給我們的一個啓示是:**數字系統中,MAC 在理論要比在實際中簡單 **(easier in theory than in practice)。

1.3 MAC 之雙因素登錄(two-factor login as MAC)

大家可能沒意識到,另一種 MAC 是 multi-factor authentication (MFA or 2FA):

2FA as MAC:密碼可以共享,但硬件 token 不能。密碼是 DAC,而硬件 token 是 MAC。

用 MFA 能允許特定的人登錄一臺計算機或服務,如果這個人不是管理員(admin),那他 自己能登錄,但將無法進一步將計算機共享給其他人,將密碼告訴他們也不行。

這種 login 是強制性的(mandatory,單有密碼不行,還必須有硬件 token 才能登錄)。在這個模型中,假設了第二因素(the second factor,即硬件 token)是不可分享的。

1.4 圖片分享:DAC/MAC 模型比較

另一個例子是分享圖片。

當然,如果一個人能下載這個文件,然後發送副本給別人,那結果還是泄露了這個文件 。這也是爲什麼一些人認爲 secret URL 的安全性在數學上與 MAC 是等價的,因爲現在 分享 URL 已經和分享文件一樣難了。但二者有一個區別:你可以關閉一個 URL 的共享,但無法追回一個已經發送出去的文件副本。

1.5 MAC 概念:限制太多,又好像沒什麼限制

歷史上,軍方中的 MAC 是圍繞 multi-level security 構建的,這裏的設計思想是:並非只有 admin 和 non-admin 兩種用戶,實際上有很多層的訪問。他們最初將其設想爲同心圓(“最高機密許可”、“機密許可” 等等),但最後證明 表達力太弱(too unexpressive)。

如今的訪問控制更像是獨立的 flags 或 subgroups。例如, SELinux 提供了對每個進程內的每個權限的細粒度控制,而傳統 Unix/Linux 上只有 root 和常規用戶權限的區分。但最終證明 SELinux 這套東西是噩夢般的複雜, 難以真正實用 —— 除非你在 NSA(發明 SELinux 的機構)工作,但即使 你在 NSA 也不一定會用。

最終來說,MAC 的概念證明是過於限制又過於模糊(both too restrictive and too vague)。當人們談論 MAC 時,我們很難搞清楚他們到底指的是什麼,唯一知道是:這東西 用起來非常讓人抓狂。

2 第一次嘗試:基於 RBAC/ABAC

2.1 RBAC(基於角色的訪問控制)

RBAC 是 MAC 的一個子集,它是一種特殊類型的 MAC,更加具體,因此 在討論及使用上會更加方便。

RBAC 與常見的 users/groups 模型類似。在 RBAC 中,

2.2 ABAC(基於屬性的訪問控制)

Attribute-based access control (Hu, Kuhn, Ferraiolo, 2015) 是對 RBAC 的改進,加了一些細節(屬性,Attributes)。

如果你遇到過下面這種情況 —— 登錄某個服務時彈出額外的圖片識別認證 reCAPTCHA, 而你旁邊的朋友登錄時卻不用 —— 就說明你遇到了 ABAC。

ABAC 很有用,因爲這些額外的屬性能給我們帶來很多有用信息,尤其 是對於那些連接到互聯網的、攻擊矢量特別多的系統。但在概念上,ABAC 與 RBAC 類似,只是稍微向前演進了一點。屬性的解析和認證工作是中心式的,大部分都實現 在各家的 identity provider 中。有鑑於此,接下來我們的討論重點扔將放在 RBAC。

2.3 也許你從未用過真正的 RBAC

RBAC 與前面提到的 users/groups 模型類似。接下來看一個具體的文件系統安全模型,例如 Windows。

這裏也可以拿 Unix 作爲例子,但經典 Unix 文件安全與常見的安全模型不同, 它只支持單個 owner、單個 group,以及 self/group/other 文件模式。如今 Linux 也支持 facls, 這算是 RBAC,但沒人知道怎麼用,因此這個也不算數。

Windows 文件安全模型:每個文件一個 ACL

在 Windows 中,

  1. 每個文件(或目錄)都有一個 users 和 groups 列表,以及

  2. 每個列表中的成員可以對這個文件做什麼操作。

這是一種訪問控制列表(access control list,ACL)。owner 設置 ACL,操作系 統執行 ACL。這是 MAC,對吧?

對的 —— 大部分情況下。想一下,任何有文件讀權限的人,都可以拷貝一份,然後在副本上 設置權限,因此這是某種形式的 DAC,或者說在執行上充滿漏洞的 MAC。但在真實文件上(而非 API 上)執行 MAC 非常難。我們將這個難題留給軍方,現在把關注點放在 ACL 語義上。

在一個 Windows filesystem ACL 中,有如下概念:

  1. User:在這個文件上執行操作的用戶。在經典 RBAC 術語中,稱爲 subject。

  2. Group 或 Role:由管理員定義的一組 user。

  3. File:需要做訪問控制的資源(resource)。也稱爲 object。subject 對 object 進行操作。

  4. Permission 或 Entitlement:一條 subject-action-object(用戶 - 動作 - 目標文件)規則。有時會說某個 subject 有一條 entitlement,或者說某個 object 允許某個 permission,這兩種表達方式本質上是一樣的,只是從不同的角度描述。

  5. ACL:一個 entitlements 列表。

控制誰能訪問哪個文件

每個文件都有一個 ACL(permission 列表)。

如果想控制誰能訪問這些文件,可通過以下任一種方式:

  1. 找到 ACL 對應的 groups/roles,在其中添加或刪除 user(稱爲修改 group/role 的 membership);或者,

  2. 直接修改 ACL,添加或刪除 permissions。

如果想一次修改一組文件的 ACL,可以

  1. 修改 group/role membership(簡單),或者

  2. 找到所有相關文件,逐個修改對應的 ACL(慢且易出錯)。

文件多了之後,逐個修改 ACL 就不切實際了。

2.4 存在的問題:ACL 太多,到處重複,批量修改麻煩

最後一點,也是訪問控制開始出現漏洞的地方。

3 第二次嘗試:每個 ACL 對應一個用戶組

被以上問題折磨多次之後,你可能會嘗試一些新東西:

3.1 仍以 Windows 文件系統爲例

仍然以 Windows 文件系統爲例,如下圖所示,你可能會創建兩個 group report-readers 和 report-writers

將盡量多的東西從 ACL 中移出,將盡量多的東西移入 groups 中。

效果是:所有 reports 文件能被 report-readers 組內的用戶讀,能被 report-writers 組內的用戶寫。

經驗不足的人在這裏會犯的一個錯誤是:只創建一個名爲 report 的 group,然後給 予這個 group read/write 權限。通常來說,需要文件讀權限的用戶,要比需要 寫權限的用戶更多。甚至在某些情況下,writer 和 reader 用戶之間都 沒有重疊(例如審計日誌場景)。

這種 per-file-type group(每種文件訪問類型一個單獨的 user group)結構是 Don't Repeat Yourself (DRY) 原則在實際應用中的一個例子:上一節 RBAC/ABAC 模型中,根源問題是每個文件都有自己的 ACL, 這些 ACL 到處重複,因此這裏提取出了重複部分放到了一個公共的地方。

3.2 存在的問題

這個改進比較合理,尤其是在有很多 objects 的大公司中工作良好,但也有幾個問題:

  1. 現在需要有某種形式的 IAM admin 訪問控制,也就是對 用戶組的增刪查改做控制。

    上一節的 RBAC/ABAC 模型中無需這種功能,因爲它直接修改文件的 ACL。IAM admin 管控帶來的一個新問題是:

  1. End users 仍然能四處遊蕩,在需要時能修改每個 report 文件的 ACL (“Alice 真的真的需要查看這個文件”),破壞了你精心設計的系統 —— 而你自己都 無法察覺。

  2. 現在需要爲每個 ACL 組合創建一個 user group。

    最後會發現,公司的每個工程師都屬於 975 個 group,每個 group 都需要定義 read/write 兩種類型。你必須 review 每個 group 的 membership。這種方式雖然比 老的 ad-hoc 文件權限方式審計性要好,但也好不了太多。

4 第三次嘗試:重拾被忽視的概念:object tags

至此,我們決定放棄文件系統的 ACL,原因是:文件系統已經設計成這樣了, 基於文件系統的 ACL 我們只能做到目前這樣。你大概率無法解決現有的文件系統和操作系統中這些問題。

但接下來的好消息是: 如今的服務都運行在無狀態容器內, 大部分 VM 都無需密碼就能執行 sudo, 因此我們不用再對文件系統進行控制,而是對 web 應用和 NoSQL 的 API 做控制。這也許不是巧合,因爲對細粒度分佈式安全(fine-grained distributed security) 的需求一直在增長,而文件系統還停留在 1980s 年代。

那麼,接下來就開始設計我們想要的 permission 系統!

4.1 根據 user type 而非 file type 創建 user group

首先,注意到,前面兩節的文件系統 ACL 方案其實並不是真正意義上基於角色的(role-based)訪問控制。爲什麼呢?它把 user groups 作爲 roles —— 這沒有問題 —— 但如果你有 975 個像 report-readers 和 report-writers 一樣的 group,那這些就不算不上是真正的 human-relevant roles。HR 並不知道 你的新員工是否應該是 report-reader,這個決策太底層了(low-level)。

因此我們得到的第一個啓示就是:應該根據用戶類型(user types)而非 文件類型(file types)來創建 user groups。如下圖所示:

4.2 Roles 去扁平化,增強表達力:將 ACL 定義爲一組策略規則

以上 group-per-user-type 格式還是過於扁平了(too flat):它已經丟失了 “爲什麼某人會在某 group” 的語義含義(semantic meaning)。如果 Bob 離職了,我們必須修改所有可能包含 Bob 的 groups。這雖然已經比跟蹤每個 report 類型的文件 然後 double check 它的 permissions 是否還正確要好,但仍然很容易出錯 。

我們假設有如下角色(roles):Accounting(審計人員)、DevOps(研發運維人員)、Engineering(工程師)、Executive(高管)。

然後我們就可以將 ACL 定義爲一組策略規則(a set of policy rules):

這種模型與最初的 flat 模型表達的東西是一樣的,但通過增加一個間接層(indirection), 它表達了我們一直想表達(而沒有表達出來)的東西。有了這個模型, 接下來就可以討論:

4.3 關於策略規則的進一步解釋

我們正在設計一個新的權限系統。

現在,先將剛纔設計的能轉換成的 roles 的 policy rules 進一步表示爲:

有了這樣一種格式的描述之後,當我們需要滿足 SOC2 合規性要求時,只需將 database 的 readers 改爲,例如 [DevOps, Prod],這將會立即鎖定所有數據庫相關的對象。

4.4 其他特性

最後,我們來加兩個其他特性:

首先,與文件只有一種 type(讀或寫)不同,一個對象可以有零或多個 tags。因此,與數據庫相關的源文件可以打上 database 和 sourcefile 兩個 tag,對應地, 它獲得的是兩種 permission set 的交集。

第二,只有 tag 的 owner 有權限增加或刪除任何對象上的該 tag。例如在下圖中,只有 Engineering 可以在某個對象打 sourcefile tag。這能夠避免意外將對象分享給應該完全隔離的人,或在不期望的地方錯誤地應用已有策略。

4.5 MAC 歸來


至此,我們看到了 MAC 迴歸的身影。但是,現在它,

  1. 不需要一個針對 security policy 的 global admin access control。

  2. 每個 tag owner 能直接對他們的 objects 進行授權,但他們能授予哪些訪問權限,是 由整體上的安全策略(the overall security policy,即 roles)控制的。

4.6 例子:API 訪問控制

在類似 Tailscale 的網絡系統中,我們其實並不會用 readers 和 writers 這樣的文件系統術語。我們定義 node 和 port,以及允許誰連接到這些 node 和 port。例如可能會如下規則:

有了以上規則,

  1. Engineering 中的任何人都可以啓動一個dev-api-server node,

  2. 該 node 能接受從任何 dev-api-client node 來的非加密連接(TLS 太難了!開發環境就放行非加密連接吧),但反之並不亦然。

  3. 只有 Ops 中的人能啓動 prod-api-server 和 prod-api-client nodes,它們只處理 https 流量,拒絕非加密 http。

下面是效果:

這裏注意:我們遞歸地用一些 tag names 來定義 permissions for other tags。Ops 中的某個人可以啓動一個 node 並打上 prod-api-server tag, 這個 node 就會獲得與 prod-api-server 而不是 Ops 相關聯的 permissions 和 entitlements( 這很重要,因爲prod-api-server instance 無法像 Ops 一樣啓動更多 instance)。

真實的 Tailscale ACLs 和 tags 與此很像,但更加具體。

5 職責分離

5.1 根據 policy rules 和 user groups 自動生成訪問權限

如果試圖將這個模型反向適配到 legacy-style filesystem permissions, 我們就會發現 roles 和 tag definitions 其實是相同類型的對象(都是 lists of users), 二者之間通過一個(“安全策略”)算法進行單向轉換:

將 roles 擴展成 tags,然後適配到傳統文件系統的權限控制模型。

你可以類似地寫一些腳本,將給定的 roles 和 group membership rules 自動生成你的 /etc/group 內容,我知道有些公司就是這樣做的。這不是標準方式,維護很痛苦,而且通常用定時任務來批量執行,這意味着當修改 一個 tag 或 group membership 之後,必須要等上一段時間才能生效。但本質上來說,這 種方式是能工作的,而且比典型的操作系統默認值要好多了。

5.2 Tags 和 roles 各自的適用場景

前面說 tags(用於 ACL 目的)和 roles(用於 user management 目的) 都是 “用戶列表”(lists of users),其實這種說法有誤導性。二者用於不同場景。最重要的是, 不同的人負責系統的不同部分:

  1. Roles 描述的是 identity system (authentication) 中的人。Roles 變化很少,通常在入職、晉升或轉崗時由 HR 部門設置。

  2. Object types (tags) 由 object owner 在這個 object 創建時設置。

  3. Entitlements 用 (Role, Tag) 描述,由簡單的程序(安全策略)來定義,由安全團隊設置。

在這個架構中,這三種類型的人只有很少時候才需要交互:

  1. Accounting 部門中的財報 writer 並不關心誰是 Executive,也不關心 Executive 是否 有權查看或編輯財報。他們只需知道要給 report 文件打上 financial-report tag。

  2. 安全團隊並不關心哪個文件打了 financial-report(討論一般情況下),也不關心誰是 Executive。他們需要的是

  1. HR 團隊不知道也不關心文件或安全策略,他們只關心這周招了一個 Accounting role 的人。

5.3 小結

回到 network permissions 場景:在大公司中,正確地圍繞這些概念設計你的模型,就能避免大量摩擦。

我們在實際工作中可能會遇到如下類似的例子:工程師創建了一個新的開發(dev)集羣后, 還要去提個工單,讓安全團隊給他開防火牆端口。爲什麼會這樣?因爲在這些公司中,安全團隊維護的策略並不規範,沒有收斂到以上模型:

  1. 允許 Engineers 運行 dev API servers,接受來自本機或 dev API clients 的 incoming 連接 —— 這個沒問題;

  2. 通常不允許創建 outgoing connections —— 這個也沒問題;

  3. 噢對了,Carol 的 dev API server 需要主動訪問數據庫服務器,只能開單獨策略了 —— 問題來了。

如果安全團隊能將這些安全規則固化成代碼片段,結果將會更好,能確保它們在整張 網絡上得到一致執行。

6 結束語

以上提到的所有東西,users、roles、object types、policies 都不是新概念, 它們都來自 1992 提出 RBAC 模型的那篇論文,只是術語稍有不同。

如今,幾乎每個人都在使用 users、groups、ACLs 了。一些人認爲,我們實現的東西已經 是 RBAC,但事實告訴我們:並不是。還沒有誰實現過完整的 RBAC 模型:

  1. 每個人都是一個 User (subject)。

  2. 每個 user 都有一個或多個 Roles。

  3. 每個 object 都有一個或多個 Tags。

  4. 一條 “security policy” 定義一個將 (Role, Tag) 轉換成 Entitlements 的 公式。

  5. 一個執行層(enforcement layer)負責 enforce security policy,併爲每個 object 生成有效 entitlements 列表(ACL)。

但另一方面,實現這樣一個模型比實現常見的 users+groups 模型並沒有複雜多少 —— 只要從一開始就將其放到系統的核心。

最後回到文初,這就是爲什麼 Tailscale RBAC、ABAC 和 security policy 不同尋常的地方。Tailscale objects 都是設備和端口(devices and ports),而非文件,但所有概念在使用上與在文件系統中是一樣的。最終的產品在理念設計上很簡潔:

  1. Device 或 container 的 owner 可以設置 tag;

  2. 安全團隊決定誰 own 哪些 tag、每個 tag 關聯了哪些 permissions、tags 會授權給哪些 roles;

  3. Identity/HR 團隊決定哪些 users 應該屬於哪些 roles。

附錄(譯者注):Tailscale 的安全策略模型

ACL rules 格式:

{
  "action": "accept",  "users": [ list-of-sources... ],      # 廣義的訪問來源,相當於 RBAC 模型中的 users/subjects
  "ports": [ list-of-destinations... ], # 廣義的訪問目標,相當於 RBAC 模型中的 objects/resources}

以上 json 中的 users 和 ports 都是爲了兼容公司的歷史 API,它們實際上包含的 範圍要比字面意思大的多,具體見 官方文檔(https://tailscale.com/kb/1018/acls/)

作者:arthurchiao

來源:https://arthurchiao.art/blog/rbac-as-it-meant-to-be-zh/

原文:https://tailscale.com/blog/rbac-like-it-was-meant-to-be/

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/DGcd3KeG-xnWV_ytclrK5A