伴魚(yú)大數(shù)據(jù)權(quán)限系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)

-? ? ?前言? ? -
伴魚(yú)早期,整個(gè)大數(shù)據(jù)倉(cāng)庫(kù)下的數(shù)據(jù)基本處于裸奔狀態(tài),沒(méi)有做任何的權(quán)限校驗(yàn)與審計(jì),用戶(hù)可以對(duì)數(shù)據(jù)為所欲為,這個(gè)階段主要考慮效率優(yōu)先。隨著業(yè)務(wù)的發(fā)展,數(shù)據(jù)安全的重要性愈發(fā)突顯,大數(shù)據(jù)權(quán)限系統(tǒng)因運(yùn)而生,本文將向大家介紹伴魚(yú)大數(shù)據(jù)權(quán)限系統(tǒng)的設(shè)計(jì)與實(shí)現(xiàn)。

-? ? ?背景? ? -
數(shù)據(jù)訪(fǎng)問(wèn)方式
在伴魚(yú),離線(xiàn)數(shù)倉(cāng)下的數(shù)據(jù)主要有以下幾種訪(fǎng)問(wèn)方式:
Hive:有兩種方式,一是 Hive CLI,一個(gè)逐漸被淘汰的工具,但目前仍然在各種腳本中被使用。Hive CLI 是一個(gè)胖客戶(hù)端,官方推薦使用 Beeline CLI(HiveServer2 JDBC Client)替代它,并建議在生產(chǎn)環(huán)境中使用其遠(yuǎn)程模式(輕客戶(hù)端模式)。另一個(gè)是 HiveServer2 JDBC API。
Presto:Presto JDBC API。
Hadoop:HDFS CLI。
Flink:HDFS Client API。
數(shù)據(jù)訪(fǎng)問(wèn)渠道
上述幾類(lèi)訪(fǎng)問(wèn)方式對(duì)應(yīng)的訪(fǎng)問(wèn)渠道主要有以下幾種:
集群節(jié)點(diǎn)上安裝的各類(lèi)客戶(hù)端工具。
Metabase(BI 平臺(tái)):Metabase 可以配置各種「數(shù)據(jù)源」,數(shù)據(jù)報(bào)表開(kāi)發(fā)時(shí)必須選擇一個(gè)對(duì)應(yīng)的「數(shù)據(jù)源」。目前我們主要使用兩類(lèi)數(shù)據(jù)源:Hive 數(shù)據(jù)源(使用 HiveServer2 JDBC API 的方式)以及 Presto 數(shù)據(jù)源(使用 Presto JDBC API 的方式)。而對(duì)于開(kāi)發(fā)之后的報(bào)表,Metabase 內(nèi)部實(shí)現(xiàn)了一套自己的授權(quán)方式。
離線(xiàn)開(kāi)發(fā)平臺(tái)(DolphinScheduler,簡(jiǎn)稱(chēng) DS):DS 同樣抽象了數(shù)據(jù)源的概念,目前主要使用的 Hive 數(shù)據(jù)源(使用 HiveServer2 JDBC API 的方式)。此外,DS 也支持 Shell 腳本類(lèi)型的工作流節(jié)點(diǎn),使用此類(lèi)方式腳本中基本是采用 CLI 的訪(fǎng)問(wèn)方式,本質(zhì)上要求 DS worker 節(jié)點(diǎn)提前安裝好各類(lèi)客戶(hù)端工具。
實(shí)時(shí)開(kāi)發(fā)平臺(tái):與具體的實(shí)時(shí)任務(wù)相關(guān),主要體現(xiàn)在與 Hive 集成的任務(wù)。
設(shè)計(jì)目標(biāo)
管控與效率兩者之間是天然對(duì)立的,我們需要做的是在這之間尋求一種平衡。就目前的形式來(lái)看,我們期望達(dá)到以下目標(biāo):
盡量收緊非數(shù)倉(cāng)團(tuán)隊(duì)的各類(lèi)權(quán)限:此為核心目標(biāo)。非數(shù)倉(cāng)團(tuán)隊(duì)訪(fǎng)問(wèn)數(shù)據(jù)主要通過(guò)是通過(guò) Metabase,目前針對(duì)不同的數(shù)據(jù)庫(kù)(如:Hive)都基本是使用同一個(gè)數(shù)據(jù)源,該數(shù)據(jù)源配置的擁有最高權(quán)限,導(dǎo)致各方都可以查看任何數(shù)據(jù)。
逐漸規(guī)范化數(shù)倉(cāng)團(tuán)隊(duì)數(shù)據(jù)訪(fǎng)問(wèn)方式:逐步替換 Hive CLI 方式至 Beeline CLI。
統(tǒng)一整合權(quán)限系統(tǒng)與各相關(guān)系統(tǒng)的權(quán)限操作:在大數(shù)據(jù)權(quán)限系統(tǒng)平臺(tái)即可完成各類(lèi)授權(quán)的操作。
調(diào)研
權(quán)限管控主要體現(xiàn)在兩個(gè)方面:用戶(hù)認(rèn)證(authentication)與權(quán)限認(rèn)證(authorization)。
用戶(hù)認(rèn)證
大數(shù)據(jù)各組件支持不同的用戶(hù)認(rèn)證方式,這里主要看下我們所關(guān)注的組件支持的認(rèn)證方式。
Hive
HiveServer2:用戶(hù)認(rèn)證支持 Kerberos、SASL、NOSASL、LDAP、PAM 和 Custom 的方式。
Presto
Presto 用戶(hù)認(rèn)證支持 Kerberos、LDAP 和 Password File 的方式。
Hadoop
Hadoop 各組件僅支持 Kerberos 的用戶(hù)認(rèn)證方式。
可見(jiàn)統(tǒng)一基于 Kerberos 的方式,可以實(shí)現(xiàn)全鏈路的用戶(hù)認(rèn)證。Kerberos 是一個(gè)集中式的用戶(hù)認(rèn)證管理框架,具備較完備的用戶(hù)認(rèn)證能力,但整體運(yùn)維成本較高,這與我們的期望(盡可能少的引入新的組件)相悖,因此決定采用 LDAP 的方式(目前已具備實(shí)操、運(yùn)維的經(jīng)驗(yàn))。也就意味著我們只是在 Hadoop 組件之上進(jìn)行用戶(hù)認(rèn)證,Hadoop 的各組件依舊保持沒(méi)有任何的用戶(hù)認(rèn)證,用戶(hù)可以在機(jī)器節(jié)點(diǎn)上偽裝任意用戶(hù)對(duì)集群中的數(shù)據(jù)進(jìn)行操控,而這類(lèi)方式對(duì)于非開(kāi)發(fā)人員具有一定的門(mén)檻,因此也符合我們的設(shè)計(jì)目標(biāo)。
權(quán)限認(rèn)證
Hive
HiveServer2:支持基于 SQL 標(biāo)準(zhǔn)的授權(quán),可用于細(xì)粒度(如:列)的訪(fǎng)問(wèn)控制。權(quán)限認(rèn)證采用了插件化的實(shí)現(xiàn)方式,目前開(kāi)源實(shí)現(xiàn)方案有 Apache Ranger 和 Apache Sentry,兩者基本類(lèi)似,我們選擇了 Apache Ranger。
Presto、Hadoop
Presto 和 Hadoop 各組件權(quán)限認(rèn)證同樣采用了插件化的實(shí)現(xiàn)方式,可以采用 Apache Ranger 方案實(shí)現(xiàn)。
系統(tǒng)設(shè)計(jì)
當(dāng)前數(shù)據(jù)鏈路各組件的關(guān)系以及權(quán)限控制如下圖所示:

我們?cè)?Hive 的 HiveServer2 和 Presto 的 Coordinator 組件上進(jìn)行了用戶(hù)認(rèn)證和授權(quán),而在 HDFS 的 NameNode 組件只進(jìn)行了授權(quán)。注意到,在授權(quán)流程中 Ranger Plugin 依賴(lài)了 Hadoop Group Mapping,而它又依賴(lài)了 LDAP,關(guān)于這些關(guān)系將在下文中闡述。
用戶(hù)認(rèn)證
用戶(hù)認(rèn)證即對(duì)請(qǐng)求中的用戶(hù)名、密碼進(jìn)行校驗(yàn),邏輯相對(duì)簡(jiǎn)單。只需對(duì)相應(yīng)的組件進(jìn)行簡(jiǎn)單的配置即可,如下是 HiveServer2 組件配置示例:
hive.server2.authentication LDAP hive.server2.authentication.ldap.baseDN ou=People,dc=ipalfish,dc=com hive.server2.authentication.ldap.url ldap://*****:389 hive.server2.authentication.ldap.userDNPattern cn=%s,ou=bigdata_user,ou=People,dc=ipalfish,dc=com

-? ? ?權(quán)限認(rèn)證? ? -
用戶(hù)和用戶(hù)組
用戶(hù)和用戶(hù)組是權(quán)限認(rèn)證的基本對(duì)象,引入用戶(hù)組的目的是為了提升效率。設(shè)想這么一個(gè)場(chǎng)景:一批用戶(hù)需要同一批庫(kù)表的權(quán)限,最直接的想法是每一個(gè)用戶(hù)都申請(qǐng)一遍權(quán)限,從算法的角度看,時(shí)間復(fù)雜度是 O(N) 的。如果可以抽象出用戶(hù)組的概念,這批用戶(hù)加入同一個(gè)用戶(hù)組,同時(shí)保證組內(nèi)的成員可以繼承組的所有權(quán)限,那么就可以只為用戶(hù)組申請(qǐng)一次權(quán)限即可,時(shí)間復(fù)雜度降到了 O(1)。
Ranger 中 User 對(duì)應(yīng)用戶(hù),Group 對(duì)應(yīng)用戶(hù)組,一個(gè)用戶(hù)可以加入多個(gè)組,它實(shí)現(xiàn)了 User 繼承 Group 權(quán)限的特性。權(quán)限認(rèn)證時(shí)判定一項(xiàng)策略是否通過(guò),會(huì)判定用戶(hù)的 User 或用戶(hù)所屬的任意一個(gè) Group 是否在策略中配置,如有則通過(guò)。這里引申出一個(gè)問(wèn)題,用戶(hù)所屬的 Groups 如何獲取?
查閱代碼,不難發(fā)現(xiàn)使用 Hadoop 的 Hadoop Groups Mapping 機(jī)制。下圖為 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 相關(guān)的實(shí)現(xiàn)代碼。Hadoop Groups Mapping 支持 LDAP 的方式獲取 User 和 Group 信息,我們也采用了這種方式,因此上文中提到的用戶(hù)認(rèn)證流程和授權(quán)流程最終都將依賴(lài) LDAP。
權(quán)限等級(jí)
一個(gè)數(shù)據(jù)表的不同的列具有不同的信息價(jià)值和數(shù)據(jù)敏感度,因此需要為每一列都劃分一個(gè)權(quán)限等級(jí),用戶(hù)申請(qǐng)權(quán)限是按照列的粒度進(jìn)行申請(qǐng)。不同的權(quán)限等級(jí)對(duì)應(yīng)著不同的權(quán)限審批流程,目前我們劃分了三種權(quán)限等級(jí):P0、P1 和 P2,級(jí)別由高到低,P0 級(jí)別的列信息最敏感,因此擁有最長(zhǎng)的審批流程。
權(quán)限策略
Ranger 的策略類(lèi)型主要有兩種:Access 和 Mask。
Access:正向策略。如一個(gè)數(shù)據(jù)表有三個(gè)字段,我們可以為每一字段創(chuàng)建一條 Access 策略,將申請(qǐng)了權(quán)限的用戶(hù)或組配置進(jìn)策略即可。乍一看,這種策略即可滿(mǎn)足我們的需求,不過(guò)考慮這么一個(gè)場(chǎng)景:一個(gè)擁有 50 個(gè)字段的數(shù)據(jù)表,某一個(gè)用戶(hù)申請(qǐng)其中 40 個(gè)字段的權(quán)限(另外一些字段的權(quán)限等級(jí)可能屬于 P0 級(jí)別)。當(dāng)想要查看表數(shù)據(jù)時(shí),一般的寫(xiě)法是「SELECT * FROM Table」,這種形式的語(yǔ)句在權(quán)限認(rèn)證環(huán)節(jié)要求具備全部字段的權(quán)限,否則將會(huì)返回權(quán)限不足的錯(cuò)誤,而我們期望是對(duì)于未授權(quán)的字段可以使用特殊的脫敏標(biāo)識(shí)符打標(biāo),這就需要借助到 Ranger 提供的另一種 Mask 策略。
Mask:補(bǔ)充策略。該策略用于保護(hù)敏感數(shù)據(jù),對(duì)數(shù)據(jù)進(jìn)行脫敏。Mask 策略是建立在 Access 策略之上的,即使用 Mask 策略?xún)?yōu)先得具備列的 Access 策略。因此當(dāng)用戶(hù)申請(qǐng)權(quán)限時(shí),我們可以為用戶(hù)授予數(shù)據(jù)表全部字段的 Access 策略(只需一個(gè)策略,策略中的 column 配置成通配符 * )的權(quán)限,同時(shí)為每一個(gè)字段生成 Mask 策略,對(duì)于沒(méi)有申請(qǐng)權(quán)限的字段,將 User 或 Group 配置進(jìn)策略即可。
注:所有在 Ranger Admin 配置的策略將由 Ranger Plugin 中的線(xiàn)程定期 Pull 至組件,并在運(yùn)行時(shí)執(zhí)行權(quán)限認(rèn)證。
下圖展示了在權(quán)限系統(tǒng)申請(qǐng)庫(kù) test 表 tb 下字段名為 tid 的權(quán)限時(shí)對(duì)應(yīng)的 Ranger 策略示例:
權(quán)限申請(qǐng)工單

Access Policy

Mask Policy


-? ? ?策略成本? ? -
以上從原理層面介紹了基于 Ranger 進(jìn)行權(quán)限認(rèn)證的幾個(gè)重要概念,通過(guò)修改相關(guān)組件的配置,即可使權(quán)限認(rèn)證生效。本節(jié)將從平臺(tái)的角度看一下如何生成 Ranger 中的策略配置。
首先需要考慮權(quán)限策略初始化的問(wèn)題。一張 Hive 表的權(quán)限策略必然是在表創(chuàng)建之后生成的,我們期望表創(chuàng)建時(shí)創(chuàng)建者能夠直接指定各列對(duì)應(yīng)的權(quán)限等級(jí),同時(shí)創(chuàng)建者作為表的 Owner 直接擁有表所有列的全部權(quán)限。主要可以從兩個(gè)方向考慮:
同步創(chuàng)建
同步創(chuàng)建方案通過(guò)將建表邏輯和策略初始化邏輯包裝成一段程序,在建表成功后執(zhí)行策略初始化。不幸的是,目前我們的建表渠道有多種方式,主要包括:
數(shù)據(jù)建模平臺(tái):數(shù)據(jù)建模平臺(tái)約束了建表規(guī)范,同時(shí)收集了表的附加元信息,如表字段的權(quán)限等級(jí),這些元信息將通過(guò) API 傳遞至 Hive。可見(jiàn),數(shù)據(jù)建模平臺(tái)本質(zhì)上是對(duì)建表操作的封裝和約束,可以實(shí)現(xiàn)同步初始化策略的目的。
CLI:指代 Beeline。由于并未完全約束用戶(hù)在建模平臺(tái)建表,開(kāi)發(fā)人員可以直接在自己腳本中通過(guò) CLI 直接建表,這種情況下表的元信息是缺失的。
我們很難將所有渠道統(tǒng)一起來(lái),即便最終建表行為可以收斂至建模平臺(tái),但從系統(tǒng)邊界的角度考慮,建模和權(quán)限分屬兩個(gè)系統(tǒng),權(quán)限策略的創(chuàng)建應(yīng)當(dāng)收斂至權(quán)限系統(tǒng)。
異步創(chuàng)建
異步化創(chuàng)建的方式需要借助消息隊(duì)列,需要將所有的建表事件投遞至一個(gè) Topic,權(quán)限系統(tǒng)后臺(tái)監(jiān)聽(tīng)此 Topic 消息,從而觸發(fā)策略的初始化。那么如何捕捉全部的建表事件并投遞至一個(gè)消息隊(duì)列?這就需要借助我們提供的「元數(shù)據(jù)中心」平臺(tái),它統(tǒng)一管理了全部數(shù)據(jù)的元信息。我們的「元數(shù)據(jù)中心」平臺(tái)是在 Apache Atlas 基礎(chǔ)上搭建的。Apache Atlas 通過(guò)其提供的各類(lèi)組件的 Atlas Hook 以此來(lái)捕捉元信息。以 Atlas Hive Hook 為例,我們提交給 Hive 的建表信息包括附加的元信息都可以在此 Hook 中被捕捉,這些信息緊接著會(huì)被發(fā)送至 Atlas Server 進(jìn)行存儲(chǔ),與此同時(shí) Atlas Server 可以通過(guò)配置一個(gè)對(duì)外的 Topic 統(tǒng)一將這些消息發(fā)送至外部的監(jiān)聽(tīng)系統(tǒng)。通過(guò)這種機(jī)制,我們就達(dá)到異步初始化權(quán)限策略的目的。
值得一提的是,字段權(quán)限等級(jí)的修改有且僅能在元數(shù)據(jù)中心進(jìn)行,等級(jí)的修改將影響到對(duì)應(yīng)的權(quán)限策略。對(duì)于這一事件,將通過(guò)同樣的方式,被權(quán)限系統(tǒng)后臺(tái)監(jiān)聽(tīng),并觸發(fā)相應(yīng)的動(dòng)作。
整個(gè)過(guò)程如下圖所示:

大數(shù)據(jù)權(quán)限系統(tǒng)主要?jiǎng)澐譃槿糠郑?/span>
Workflow State Machine:工作流狀態(tài)機(jī),負(fù)責(zé)各級(jí)工單狀態(tài)流轉(zhuǎn)。
EventListener:負(fù)責(zé)監(jiān)聽(tīng)元信息變更事件。
Deployment:負(fù)責(zé)將策略部署至 Ranger。同時(shí),由于涉及到權(quán)限整合還有和 Metabase 的交互,將在下文闡述。
權(quán)限整合
BI 系統(tǒng)可以說(shuō)得上是一家公司使用最頻繁的一款數(shù)據(jù)產(chǎn)品,數(shù)據(jù)開(kāi)發(fā)工程師、分析師在上面開(kāi)發(fā)報(bào)表,產(chǎn)品、運(yùn)營(yíng)等業(yè)務(wù)方在上面查看報(bào)表。我們的 BI 系統(tǒng)是基于開(kāi)源的 Metabase 搭建的,前文提到,Metabase 自身具備一套權(quán)限管控的機(jī)制,但實(shí)踐下來(lái)十分難用且由于沒(méi)有審批工單機(jī)制,往往需要人工線(xiàn)下確認(rèn),增加了溝通的成本。同時(shí)審批工作都由管理員完成,十分耗費(fèi)個(gè)人的人力成本。基于此,我們決定在權(quán)限系統(tǒng)中整合 Metabase 相關(guān)的權(quán)限操作。
報(bào)表開(kāi)發(fā)權(quán)限
任意平臺(tái)用戶(hù)都具備報(bào)表的開(kāi)發(fā)權(quán)限,但開(kāi)發(fā)一個(gè)報(bào)表需要選擇一個(gè)對(duì)應(yīng)的「數(shù)據(jù)源」,因此開(kāi)發(fā)權(quán)限體現(xiàn)在對(duì)于「數(shù)據(jù)源」的權(quán)限控制上。我們?cè)跈?quán)限系統(tǒng)提供了「同步賬戶(hù)」的操作,用戶(hù)可以執(zhí)行此操作,操作中的一個(gè)步驟就是創(chuàng)建數(shù)據(jù)源,使用的是其對(duì)應(yīng)的用戶(hù)名和密碼,用戶(hù)開(kāi)發(fā)報(bào)表時(shí)選擇自己的數(shù)據(jù)源即可,會(huì)為該對(duì)象的 Metabase 賬戶(hù)授予此數(shù)據(jù)源的權(quán)限。報(bào)表查看權(quán)限
Metabase 報(bào)表權(quán)限是按照「分組」進(jìn)行授權(quán)的,平臺(tái)用戶(hù)需加入某一個(gè)「分組」,然后為此「分組」授予報(bào)表權(quán)限,用戶(hù)方可查看報(bào)表。因此「同步賬戶(hù)」時(shí)還會(huì)為用戶(hù)或用戶(hù)組創(chuàng)建與之對(duì)應(yīng)的「分組」,同時(shí)將其下所有成員的 Metabase 賬戶(hù)加入此「分組」。報(bào)表的權(quán)限申請(qǐng)?zhí)峁┝藛为?dú)的申請(qǐng)入口,用戶(hù)填入報(bào)表地址即可,工單進(jìn)入不同的審批流程,審批完成則將自動(dòng)為其對(duì)應(yīng)的「分組」授予權(quán)限。
Metabase 報(bào)表權(quán)限申請(qǐng)工單示例:


-? ? ?總結(jié)? ? -
本文闡述伴魚(yú)大數(shù)據(jù)權(quán)限系統(tǒng)的核心設(shè)計(jì)要點(diǎn),目前 Presto、Hive、HDFS、Metabase的權(quán)限都得到了收斂,工單化的申請(qǐng)流程極大的降低了授權(quán)申請(qǐng)的成本,自動(dòng)化程度比較高,效果比較理想。
作者:李輝
來(lái)源:tech.ipalfish.com/blog/2021/10/07/data_access_control/

