伴魚大數據權限系統的設計與實現
伴魚早期,整個大數據倉庫下的數據基本處於裸奔狀態,沒有做任何的權限校驗與審計,用戶可以對數據爲所欲爲,這個階段主要考慮效率優先。隨着業務的發展,數據安全的重要性愈發突顯,大數據權限系統因運而生,本文將向大家介紹伴魚大數據權限系統的設計與實現。
背景
數據訪問方式
在伴魚,離線數倉下的數據主要有以下幾種訪問方式:
-
Hive:有兩種方式,一是 Hive CLI,一個逐漸被淘汰的工具,但目前仍然在各種腳本中被使用。Hive CLI 是一個胖客戶端,官方推薦使用 Beeline CLI(HiveServer2 JDBC Client)替代它,並建議在生產環境中使用其遠程模式(輕客戶端模式)。另一個是 HiveServer2 JDBC API。
-
Presto:Presto JDBC API。
-
Hadoop:HDFS CLI。
-
Flink:HDFS Client API。
數據訪問渠道
上述幾類訪問方式對應的訪問渠道主要有以下幾種:
-
集羣節點上安裝的各類客戶端工具。
-
Metabase(BI 平臺):Metabase 可以配置各種「數據源」,數據報表開發時必須選擇一個對應的「數據源」。目前我們主要使用兩類數據源:Hive 數據源(使用 HiveServer2 JDBC API 的方式)以及 Presto 數據源(使用 Presto JDBC API 的方式)。而對於開發之後的報表,Metabase 內部實現了一套自己的授權方式。
-
離線開發平臺(DolphinScheduler,簡稱 DS):DS 同樣抽象了數據源的概念,目前主要使用的 Hive 數據源(使用 HiveServer2 JDBC API 的方式)。此外,DS 也支持 Shell 腳本類型的工作流節點,使用此類方式腳本中基本是採用 CLI 的訪問方式,本質上要求 DS worker 節點提前安裝好各類客戶端工具。
-
實時開發平臺:與具體的實時任務相關,主要體現在與 Hive 集成的任務。
設計目標
管控與效率兩者之間是天然對立的,我們需要做的是在這之間尋求一種平衡。就目前的形式來看,我們期望達到以下目標:
-
儘量收緊非數倉團隊的各類權限:此爲核心目標。非數倉團隊訪問數據主要通過是通過 Metabase,目前針對不同的數據庫(如:Hive)都基本是使用同一個數據源,該數據源配置的擁有最高權限,導致各方都可以查看任何數據。
-
逐漸規範化數倉團隊數據訪問方式:逐步替換 Hive CLI 方式至 Beeline CLI。
-
統一整合權限系統與各相關係統的權限操作:在大數據權限系統平臺即可完成各類授權的操作。
調研
權限管控主要體現在兩個方面:用戶認證(authentication)與權限認證(authorization)。
用戶認證
大數據各組件支持不同的用戶認證方式,這裏主要看下我們所關注的組件支持的認證方式。
- Hive
HiveServer2:用戶認證支持 Kerberos、SASL、NOSASL、LDAP、PAM 和 Custom 的方式。
- Presto
Presto 用戶認證支持 Kerberos、LDAP 和 Password File 的方式。
- Hadoop
Hadoop 各組件僅支持 Kerberos 的用戶認證方式。
可見統一基於 Kerberos 的方式,可以實現全鏈路的用戶認證。Kerberos 是一個集中式的用戶認證管理框架,具備較完備的用戶認證能力,但整體運維成本較高,這與我們的期望(儘可能少的引入新的組件)相悖,因此決定採用 LDAP 的方式(目前已具備實操、運維的經驗)。也就意味着我們只是在 Hadoop 組件之上進行用戶認證,Hadoop 的各組件依舊保持沒有任何的用戶認證,用戶可以在機器節點上僞裝任意用戶對集羣中的數據進行操控,而這類方式對於非開發人員具有一定的門檻,因此也符合我們的設計目標。
權限認證
- Hive
HiveServer2:支持基於 SQL 標準的授權,可用於細粒度(如:列)的訪問控制。權限認證採用了插件化的實現方式,目前開源實現方案有 Apache Ranger 和 Apache Sentry,兩者基本類似,我們選擇了 Apache Ranger。
- Presto、Hadoop
Presto 和 Hadoop 各組件權限認證同樣採用了插件化的實現方式,可以採用 Apache Ranger 方案實現。
系統設計
當前數據鏈路各組件的關係以及權限控制如下圖所示:
我們在 Hive 的 HiveServer2 和 Presto 的 Coordinator 組件上進行了用戶認證和授權,而在 HDFS 的 NameNode 組件只進行了授權。注意到,在授權流程中 Ranger Plugin 依賴了 Hadoop Group Mapping,而它又依賴了 LDAP,關於這些關係將在下文中闡述。
用戶認證
用戶認證即對請求中的用戶名、密碼進行校驗,邏輯相對簡單。只需對相應的組件進行簡單的配置即可,如下是 HiveServer2 組件配置示例:
<property>
<name>hive.server2.authentication</name>
<value>LDAP</value>
</property>
<property>
<name>hive.server2.authentication.ldap.baseDN</name>
<value>ou=People,dc=ipalfish,dc=com</value>
</property>
<property>
<name>hive.server2.authentication.ldap.url</name>
<value>ldap://*****:389</value>
</property>
<property>
<name>hive.server2.authentication.ldap.userDNPattern</name>
<value>cn=%s,ou=bigdata_user,ou=People,dc=ipalfish,dc=com</value>
</property>
權限認證
用戶和用戶組
用戶和用戶組是權限認證的基本對象,引入用戶組的目的是爲了提升效率。設想這麼一個場景:一批用戶需要同一批庫表的權限,最直接的想法是每一個用戶都申請一遍權限,從算法的角度看,時間複雜度是 O(N) 的。如果可以抽象出用戶組的概念,這批用戶加入同一個用戶組,同時保證組內的成員可以繼承組的所有權限,那麼就可以只爲用戶組申請一次權限即可,時間複雜度降到了 O(1)。
Ranger 中 User 對應用戶,Group 對應用戶組,一個用戶可以加入多個組,它實現了 User 繼承 Group 權限的特性。權限認證時判定一項策略是否通過,會判定用戶的 User 或用戶所屬的任意一個 Group 是否在策略中配置,如有則通過。這裏引申出一個問題,用戶所屬的 Groups 如何獲取?
查閱代碼,不難發現使用 Hadoop 的 Hadoop Groups Mapping 機制。下圖爲 ranger presto plugin 部分代碼片段:
private RangerPrestoAccessRequest createAccessRequest(RangerPrestoResource resource, SystemSecurityContext context, PrestoAccessType accessType) {
String userName = null;
Set<String> userGroups = null;
if (useUgi) {
UserGroupInformation ugi = UserGroupInformation.createRemoteUser(context.getIdentity().getUser());
userName = ugi.getShortUserName();
String[] groups = ugi != null ? ugi.getGroupNames() : null;
if (groups != null && groups.length > 0) {
userGroups = new HashSet<>(Arrays.asList(groups));
}
} else {
userName = context.getIdentity().getUser();
userGroups = context.getIdentity().getGroups();
}
RangerPrestoAccessRequest request = new RangerPrestoAccessRequest(
resource,
userName,
userGroups,
accessType
);
return request;
}
可以看出,使用了 org.apache.hadoop.security 包下的 UserGroupInformation 信息,這即是 Hadoop Groups Mapping 相關的實現代碼。Hadoop Groups Mapping 支持 LDAP 的方式獲取 User 和 Group 信息,我們也採用了這種方式,因此上文中提到的用戶認證流程和授權流程最終都將依賴 LDAP。
權限等級
一個數據表的不同的列具有不同的信息價值和數據敏感度,因此需要爲每一列都劃分一個權限等級,用戶申請權限是按照列的粒度進行申請。不同的權限等級對應着不同的權限審批流程,目前我們劃分了三種權限等級:P0、P1 和 P2,級別由高到低,P0 級別的列信息最敏感,因此擁有最長的審批流程。
權限策略
Ranger 的策略類型主要有兩種:Access 和 Mask。
-
Access:正向策略。如一個數據表有三個字段,我們可以爲每一字段創建一條 Access 策略,將申請了權限的用戶或組配置進策略即可。乍一看,這種策略即可滿足我們的需求,不過考慮這麼一個場景:一個擁有 50 個字段的數據表,某一個用戶申請其中 40 個字段的權限(另外一些字段的權限等級可能屬於 P0 級別)。當想要查看錶數據時,一般的寫法是「SELECT * FROM Table」,這種形式的語句在權限認證環節要求具備全部字段的權限,否則將會返回權限不足的錯誤,而我們期望是對於未授權的字段可以使用特殊的脫敏標識符打標,這就需要藉助到 Ranger 提供的另一種 Mask 策略。
-
Mask:補充策略。該策略用於保護敏感數據,對數據進行脫敏。Mask 策略是建立在 Access 策略之上的,即使用 Mask 策略優先得具備列的 Access 策略。因此當用戶申請權限時,我們可以爲用戶授予數據表全部字段的 Access 策略(只需一個策略,策略中的 column 配置成通配符 * )的權限,同時爲每一個字段生成 Mask 策略,對於沒有申請權限的字段,將 User 或 Group 配置進策略即可。
注:所有在 Ranger Admin 配置的策略將由 Ranger Plugin 中的線程定期 Pull 至組件,並在運行時執行權限認證。
下圖展示了在權限系統申請庫 test 表 tb 下字段名爲 tid 的權限時對應的 Ranger 策略示例:
-
權限申請工單
-
Access Policy
-
Mask Policy
策略配置
以上從原理層面介紹了基於 Ranger 進行權限認證的幾個重要概念,通過修改相關組件的配置,即可使權限認證生效。本節將從平臺的角度看一下如何生成 Ranger 中的策略配置。
首先需要考慮權限策略初始化的問題。一張 Hive 表的權限策略必然是在表創建之後生成的,我們期望表創建時創建者能夠直接指定各列對應的權限等級,同時創建者作爲表的 Owner 直接擁有表所有列的全部權限。主要可以從兩個方向考慮:
- 同步創建
同步創建方案通過將建表邏輯和策略初始化邏輯包裝成一段程序,在建表成功後執行策略初始化。不幸的是,目前我們的建表渠道有多種方式,主要包括:
-
數據建模平臺:數據建模平臺約束了建表規範,同時收集了表的附加元信息,如表字段的權限等級,這些元信息將通過 API 傳遞至 Hive。可見,數據建模平臺本質上是對建表操作的封裝和約束,可以實現同步初始化策略的目的。
-
CLI:指代 Beeline。由於並未完全約束用戶在建模平臺建表,開發人員可以直接在自己腳本中通過 CLI 直接建表,這種情況下表的元信息是缺失的。
我們很難將所有渠道統一起來,即便最終建錶行爲可以收斂至建模平臺,但從系統邊界的角度考慮,建模和權限分屬兩個系統,權限策略的創建應當收斂至權限系統。
- 異步創建
異步化創建的方式需要藉助消息隊列,需要將所有的建表事件投遞至一個 Topic,權限系統後臺監聽此 Topic 消息,從而觸發策略的初始化。那麼如何捕捉全部的建表事件並投遞至一個消息隊列?這就需要藉助我們提供的「元數據中心」平臺,它統一管理了全部數據的元信息。我們的「元數據中心」平臺是在 Apache Atlas 基礎上搭建的。Apache Atlas 通過其提供的各類組件的 Atlas Hook 以此來捕捉元信息。以 Atlas Hive Hook 爲例,我們提交給 Hive 的建表信息包括附加的元信息都可以在此 Hook 中被捕捉,這些信息緊接着會被髮送至 Atlas Server 進行存儲,與此同時 Atlas Server 可以通過配置一個對外的 Topic 統一將這些消息發送至外部的監聽系統。通過這種機制,我們就達到異步初始化權限策略的目的。
值得一提的是,字段權限等級的修改有且僅能在元數據中心進行,等級的修改將影響到對應的權限策略。對於這一事件,將通過同樣的方式,被權限系統後臺監聽,並觸發相應的動作。
整個過程如下圖所示:
大數據權限系統主要劃分爲三部分:
-
Workflow State Machine:工作流狀態機,負責各級工單狀態流轉。
-
EventListener:負責監聽元信息變更事件。
-
Deployment:負責將策略部署至 Ranger。同時,由於涉及到權限整合還有和 Metabase 的交互,將在下文闡述。
權限整合
BI 系統可以說得上是一家公司使用最頻繁的一款數據產品,數據開發工程師、分析師在上面開發報表,產品、運營等業務方在上面查看報表。我們的 BI 系統是基於開源的 Metabase 搭建的,前文提到,Metabase 自身具備一套權限管控的機制,但實踐下來十分難用且由於沒有審批工單機制,往往需要人工線下確認,增加了溝通的成本。同時審批工作都由管理員完成,十分耗費個人的人力成本。基於此,我們決定在權限系統中整合 Metabase 相關的權限操作。
-
報表開發權限
任意平臺用戶都具備報表的開發權限,但開發一個報表需要選擇一個對應的「數據源」,因此開發權限體現在對於「數據源」的權限控制上。我們在權限系統提供了「同步賬戶」的操作,用戶可以執行此操作,操作中的一個步驟就是創建數據源,使用的是其對應的用戶名和密碼,用戶開發報表時選擇自己的數據源即可,會爲該對象的 Metabase 賬戶授予此數據源的權限。 -
報表查看權限
Metabase 報表權限是按照「分組」進行授權的,平臺用戶需加入某一個「分組」,然後爲此「分組」授予報表權限,用戶方可查看報表。因此「同步賬戶」時還會爲用戶或用戶組創建與之對應的「分組」,同時將其下所有成員的 Metabase 賬戶加入此「分組」。報表的權限申請提供了單獨的申請入口,用戶填入報表地址即可,工單進入不同的審批流程,審批完成則將自動爲其對應的「分組」授予權限。
Metabase 報表權限申請工單示例:
總結
本文闡述伴魚大數據權限系統的核心設計要點,目前 Presto、Hive、HDFS、Metabase 的權限都得到了收斂,工單化的申請流程極大的降低了授權申請的成本,自動化程度比較高,效果比較理想。
作者:李輝
原文:tech.ipalfish.com/blog/2021/10/07/data_access_control/
來源:伴魚技術博客
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/j_KBNn2XR0hFxS_-GBvhjw