前言
2016年,Hadoop迎來了自己十周歲生日。過去的十年,hadoop雄霸武林盟主之位,號令天下,引領大數據技術生態不斷發展壯大,一時間百家爭鳴,百花齊放。然而,兄弟多了不好管,為了搶占企業級市場,各家都迭代出自己的一套訪問控制體系,不管是老牌系統(比如HDFS、Hbase),還是生態新貴(比如Kafka、Alluxio),ACL(Access Control List)支持都是Roadmap里被關注最高的issue之一。
歷史證明跳出混沌狀態的最好方式就是——出臺標準。于是,Hadoop兩大廠Cloudera和Hortonworks先后發起標準化運動,分別開源了Sentry和Ranger,在centralized訪問控制領域展開新一輪的角逐。
Ranger在0.4版本的時候被Hortonworks加入到其Hadoop發行版HDP里,目前作為Apache incubator項目,最新版本是0.6。它主要提供如下特性:
基于策略(Policy-based)的訪問權限模型
通用的策略同步與決策邏輯,方便控制插件的擴展接入
內置常見系統(如HDFS、YARN、hbase)的控制插件,且可擴展
內置基于LDAP、文件的用戶同步機制,且可擴展
統一的管理界面,包括策略管理、審計查看、插件管理等
本文將從權限模型、總體架構、系統插件三個角度來展開,剖析Ranger如何實現centralized訪問控制。
權限模型
訪問權限無非是定義了”用戶-資源-權限“這三者間的關系,Ranger基于策略來抽象這種關系,進而延伸出自己的權限模型。為了簡化模型,便于理解,我用以下表達式來描述它:
Policy = Service + List<Resource> + AllowACL + DenyACL
AllowACL = List<AccessItem> allow + List<AccssItem> allowException
DenyACL = List<AccessItem> deny + List<AccssItem> denyException
AccessItem = List<User/Group> + List<AccessType>
接下來從”用戶-資源-權限”的角度來詳解上述表達:
用戶:由User或Group來表達;User代表訪問資源的用戶,Group代表用戶所屬的用戶組。
資源:由(Service, Resource)二元組來表達;一條Policy唯一對應一個Service,但可以對應多個Resource。
權限:由(AllowACL, DenyACL)二元組來表達,兩者都包含兩組AccessItem。而AccessItem則描述一組用戶與一組訪問之間的關系——在AllowACL中表示允許執行,而DenyACL中表示拒絕執行。
下表列出了幾種常見系統的模型實體枚舉值:
關于權限這個部分,還有一點沒有解釋清楚:為什么AllowACL
和DenyACL
需要分別對應兩組AccessItem?這是由具體使用場景引出的設計:
以AllowACL為例,假定我們要將資源授權給一個用戶組G1,但是用戶組里某個用戶U1除外,這時只要增加一條包含G1的AccessItem到AllowACL_allow,同時增加一條包含U1的AccessItem到AllowACL_allowException即可。類似的原因可反推到DenyACL。
既然現在一條Policy有(allow, allowException, deny, denyException)這么四組AccessItem,那么判斷用戶最終權限的決策過程是怎樣的?總體來說,這四組AccessItem的作用優先級由高到低依次是:
denyException > deny > allowException > allow
訪問決策樹可以用以下流程圖來描述:
這里要對決策下放做一個解釋:如果沒有policy能決策訪問,Ranger可以選擇將決策下放給系統自身的訪問控制層,比如HDFS的ACL。
總體架構
Ranger的總體架構如下圖所示,主要由以下三個組件構成:
AdminServer: 以RESTFUL形式提供策略的增刪改查接口,同時內置一個Web管理頁面。
AgentPlugin: 嵌入到各系統執行流程中,定期從AdminServer拉取策略,根據策略執行訪問決策樹,并且定期記錄訪問審計。插件的實現原理將在后文詳細介紹。
UserSync: 定期從LDAP/File中加載用戶,上報給AdminServer。
系統插件
前文已經提到,系統插件主要負責三件事:
定期從AdminServer拉取策略
根據策略執行訪問決策樹
定期記錄訪問審計
以上執行邏輯是通用的,可由所有系統插件引用,因此剩下的問題是如何把這些邏輯嵌入到各個系統的訪問決策流程中去。目前Ranger里有兩種做法:
- 實現可擴展接口:多數的系統在實現時都有考慮功能擴展性的問題,一般會為核心的模塊暴露出可擴展的接口,訪問控制模塊也不例外。Ranger通過實現訪問控制接口,將自己的邏輯嵌入各個系統。下表列出了Ranger插件對幾個常見系統的擴展接口:
- 代碼注入:不排除有少數系統沒有將訪問控制模塊暴露出擴展點,這個時候Ranger依賴Java代碼注入機制(java.lang.instrument)來實現邏輯嵌入。以HDFS插件為例,Ranger利用ClassFileTransformer,直接修改HDFS訪問控制類FSPermissionChecker的ClassFile,將checkPermission方法替換成Ranger的自定義實現。
運行過程
整個Ranger的工作過程大概有以下幾部分:
User/Group同步
同步模塊從Unix系統或是LDAP文件系統同步users/groups信息,admin server會存儲這些信息供后續定義policy使用Rest/Web
用戶、管理員等使用Rest接口或是web界面創建/更新policies,保存到policy數據庫。同時,admin server還會收安裝到不同組件中插件收集來的訪問信息,進行統計。插件
輕量java程序,嵌入到hadoop各個組件中。會以一定間隔從admin server拉取policies信息存儲到本地文件中。當用戶通過組件請求數據時,插件會攔截請求,結合本地policy信息進行鑒權。同時會啟一個獨立的線程將此次請求的信息收集起來發送admin server.
總結
隨著Hadoop生態圈進軍企業級市場,數據安全逐漸成為關注焦點。Ranger作為標準化的訪問控制層,引入統一的權限模型與管理界面,極大地簡化了數據權限的管理。不過,Ranger目前處于孵化項目,在功能性與穩定性上仍然有較大的提升空間,其能否覆蓋更多的系統,一統江湖成為標準,讓我們拭目以待。