利用Spark提供的屬性來(lái)提升Spark Web UI的安全性

本文基于Spark 2.1.0版本蹄葱、Hadoop 2.7.3版本

如無(wú)特殊說(shuō)明滥壕,本文的Spark Web UI,特指: [Driver Web UI](默認(rèn)是http://運(yùn)行Driver程序的主機(jī)IP:4040)

Spark提供了幾個(gè)可配置的屬性,允許用戶控制Web UI使用的安全性:

  • ACL機(jī)制狂打,允許指定的用戶查看Web UI的內(nèi)容书斜、終止JOB诬辈、Stage的運(yùn)行
  • Filter機(jī)制,允許用戶使用自定義的過(guò)濾器來(lái)控制Web UI的使用權(quán)限(本文重點(diǎn))

1荐吉,ACL機(jī)制:

相關(guān)屬性:

Property Name Default Meaning
spark.acls.enable false Whether Spark acls should be enabled. If enabled, this checks to see if the user has access permissions to view or modify the job. Note this requires the user to be known, so if the user comes across as null no checks are done.
spark.ui.view.acls Empty Comma separated list of users that have view access to the Spark web ui. By default only the user that started the Spark job has view access. Putting a "*" in the list means any user can have view access to this Spark job.
spark.modify.acls Empty Comma separated list of users that have modify access to the Spark job. By default only the user that started the Spark job has access to modify it (kill it for example). Putting a "*" in the list means any user can have access to modify it.
spark.admin.acls Empty Comma separated list of users/administrators that have view and modify access to all Spark jobs. This can be used if you run on a shared cluster and have a set of administrators or devs who help debug when things do not work. Putting a "*" in the list means any user can have the privilege of admin.

這個(gè)機(jī)制很簡(jiǎn)單焙糟,大家看明白每個(gè)屬性的意思,就可以很快上手了样屠,我簡(jiǎn)單舉幾例子說(shuō)明一下穿撮。

首先,hadoop用戶下痪欲,使用YARN的方式啟動(dòng)spark shell應(yīng)用程序:
[hadoop@wl1 ~]$ spark-shell --master yarn

Hadoop YARN Web UI

觀察上圖中兩個(gè)橢圓擴(kuò)起來(lái)的地方:

  • 使用YARN時(shí)悦穿,默認(rèn)的登陸用戶是dr.who(可以在Hadoop的core-site.xml中使用hadoop.http.staticuser.user屬性來(lái)指定登陸用戶)
  • 而spark-shell的應(yīng)用程序,是用hadoop用戶啟動(dòng)的

由于沒(méi)有使能ACL機(jī)制业踢,此時(shí)點(diǎn)擊Tracking UI: ApplicationMaster栗柒,是可以進(jìn)入該Spark應(yīng)用程序的Driver Web UI的(此處圖省略)。

使用如下命令重新提交該Spark應(yīng)用程序:
[hadoop@wl1 ~]$ spark-shell --master yarn --conf spark.acls.enable=true

點(diǎn)擊YARN Web UI界面的Tracking UI: ApplicationMaster知举,發(fā)現(xiàn)訪問(wèn)失敗

訪問(wèn) Spark應(yīng)用程序的Driver Web UI失敗
終端也打出了錯(cuò)誤信息

說(shuō)明spark.acls.enable屬性為true時(shí)瞬沦,開(kāi)啟了ACL機(jī)制。當(dāng)訪問(wèn)Spark應(yīng)用程序 Web UI的用戶不是啟動(dòng)該應(yīng)用程序的用戶時(shí)雇锡,會(huì)被拒絕訪問(wèn)(本例的訪問(wèn)者是dr.who)逛钻。

使用如下命令重新提交該Spark應(yīng)用程序:
[hadoop@wl1 ~]$ spark-shell --master yarn --conf spark.acls.enable=true --conf spark.ui.view.acls=dr.who

點(diǎn)擊YARN Web UI界面的Tracking UI: ApplicationMaster,發(fā)現(xiàn)可以正常訪問(wèn)Spark應(yīng)用程序的Driver Web UI了

Spark應(yīng)用程序的Driver Web UI

但是點(diǎn)擊Job kill(圖中橢圓框位置)時(shí)锰提,并沒(méi)有終止該Job(Stage同理)曙痘,在終端有錯(cuò)誤信息的輸出


終端錯(cuò)誤信息

說(shuō)明通過(guò)spark.ui.view.acls屬性加入ACL的用戶,只有view的權(quán)限欲账,沒(méi)有modify的權(quán)限屡江。

使用如下命令重新提交該Spark應(yīng)用程序:
[hadoop@wl1 ~]$ spark-shell --master yarn --conf spark.acls.enable=true --conf spark.ui.view.acls=dr.who --conf spark.modify.acls=dr.who

點(diǎn)擊YARN Web UI界面的Tracking UI: ApplicationMaster,發(fā)現(xiàn)可以正常訪問(wèn)Spark應(yīng)用程序的Driver Web UI

Spark應(yīng)用程序的Driver Web UI

同時(shí)也可以通過(guò)點(diǎn)擊Job kill來(lái)終止該Job(Stage同理)


Job被kill
終端顯示Job被cancel

要注意一點(diǎn):spark.modify.acls屬性需要和spark.ui.view.acls屬性配合使用赛不。

使用如下命令重新提交該Spark應(yīng)用程序:
[hadoop@wl1 ~]$ spark-shell --master yarn --conf spark.acls.enable=true --conf spark.admin.acls=dr.who

(此處圖省略)點(diǎn)擊YARN Web UI界面的Tracking UI: ApplicationMaster惩嘉,發(fā)現(xiàn)可以正常訪問(wèn)Spark應(yīng)用程序的Driver Web UI,同時(shí)也可以通過(guò)點(diǎn)擊Job kill(圖中橢圓框位置)來(lái)終止該Job(Stage同理)踢故。
說(shuō)明通過(guò)spark.admin.acls屬性加入ACL的用戶文黎,具有Admin的權(quán)限惹苗,可以通過(guò)Spark Driver Web UI 來(lái)view和modify Spark的應(yīng)用程序。

2耸峭,F(xiàn)ilter機(jī)制:

相關(guān)屬性:

Property Name Default Meaning
spark.ui.filters None Comma separated list of filter class names to apply to the Spark web UI. The filter should be a standard javax servlet Filter. Parameters to each filter can also be specified by setting a java system property of: spark.<class name of filter>.params='param1=value1,param2=value2'

用戶可以通過(guò)自定義的Filter過(guò)濾器桩蓉,來(lái)控制Spark Driver Web UI的訪問(wèn)規(guī)則。

首先劳闹,實(shí)現(xiàn)一個(gè)符合標(biāo)準(zhǔn)javax servlet Filter的類院究,源碼如下:
這是一個(gè)對(duì)用戶名和密碼進(jìn)行校驗(yàn)的過(guò)濾器,也是HTTP訪問(wèn)時(shí)常用的權(quán)限核實(shí)方式

/**
 * Created by wangliang on 2017/4/29.
 */
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.util.StringTokenizer;

public class BasicAuthFilter implements Filter {

    /** Logger */
    private static final Logger LOG = LoggerFactory.getLogger(BasicAuthFilter.class);

    private String username = "";

    private String password = "";

    private String realm = "Protected";

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        username = filterConfig.getInitParameter("username");
        password = filterConfig.getInitParameter("password");
        String paramRealm = filterConfig.getInitParameter("realm");
        if (StringUtils.isNotBlank(paramRealm)) {
            realm = paramRealm;
        }
    }

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
            throws IOException, ServletException {

        HttpServletRequest request = (HttpServletRequest) servletRequest;
        HttpServletResponse response = (HttpServletResponse) servletResponse;

        String authHeader = request.getHeader("Authorization");
        if (authHeader != null) {

            StringTokenizer st = new StringTokenizer(authHeader);
            if (st.hasMoreTokens()) {

                String basic = st.nextToken();

                if (basic.equalsIgnoreCase("Basic")) {

                    try {
                        String credentials = new String(Base64.decodeBase64(st.nextToken()), "UTF-8");
                        LOG.debug("Credentials: " + credentials);

                        int p = credentials.indexOf(":");
                        if (p != -1) {
                            String _username = credentials.substring(0, p).trim();
                            String _password = credentials.substring(p + 1).trim();


                            if (!username.equals(_username) || !password.equals(_password)) {
                                unauthorized(response, "Bad credentials");
                            }

                            filterChain.doFilter(servletRequest, servletResponse);
                        } else {
                            unauthorized(response, "Invalid authentication token");
                        }
                    } catch (UnsupportedEncodingException e) {
                        throw new Error("Couldn't retrieve authentication", e);
                    }
                }
            }
        } else {
            unauthorized(response);
        }
    }

    @Override
    public void destroy() {
    }

    private void unauthorized(HttpServletResponse response, String message) throws IOException {
        response.setHeader("WWW-Authenticate", "Basic realm=\"" + realm + "\"");
        response.sendError(401, message);
    }

    private void unauthorized(HttpServletResponse response) throws IOException {
        unauthorized(response, "Unauthorized");
    }

}

上述代碼生成spark_filter.jar本涕,放置在Spark集群中业汰,使用如下命令提交Spark應(yīng)用程序:(spark.ui.filters通過(guò)driver java屬性來(lái)設(shè)置)

[hadoop@wl1 ~]$ spark-shell --master spark://wl1:7077 --driver-class-path /home/hadoop/testjar/spark_filter.jar --driver-java-options "-Dspark.ui.filters=BasicAuthFilter -Dspark.BasicAuthFilter.params='username=admin,password=admin,realm=20170429'"

這次使用Standalone的Client方式提交的應(yīng)用程序,所以通過(guò)Spark Master的Web UI來(lái)訪問(wèn)Driver Web UI(下圖橢圓框處)

Spark Master的Web UI

神奇的一幕出現(xiàn)了菩颖,彈出了認(rèn)證對(duì)話框样漆,這個(gè)就是上面自定義的BasicAuthFilter實(shí)現(xiàn)的,輸入正確的用戶名和密碼
(就是提交應(yīng)用程序時(shí)-Dspark.BasicAuthFilter.params指定的)

認(rèn)證對(duì)話框

就可以訪問(wèn)Spark Driver Web UI了

Spark Driver Web UI

需要注意的地方:
如果使用YARN的方式來(lái)提交應(yīng)用程序晦闰,Spark默認(rèn)會(huì)加載Hadoop的org.apache.hadoop.yarn.server.webproxy.amfilter.AmIpFilter過(guò)濾器放祟,當(dāng)用戶使用YARN的Web UI來(lái)訪問(wèn)Spark應(yīng)用程序的Web UI時(shí),使用的地址是過(guò)濾器生成的8088端口的代理地址呻右,導(dǎo)致如果同時(shí)使用上面的
BasicAuthFilter過(guò)濾器時(shí)跪妥,用戶認(rèn)證總是失敗,因?yàn)樵撜J(rèn)證需要和Spark 4040端口的Web Server交互才行窿冯。

所以骗奖,如果想基于YARN來(lái)控制Spark應(yīng)用程序的Web UI,可以用Hadoop提供的Filter或者HTTP Kerberos的方式來(lái)實(shí)現(xiàn)醒串。

相關(guān)鏈接:
[Spark 2.1.0 configuration] (http://spark.apache.org/docs/latest/configuration.html)
[javax servlet Filter] (http://docs.oracle.com/javaee/6/api/javax/servlet/Filter.html)
[Spark 2.1.0 security]
(http://spark.apache.org/docs/latest/security.html)

喜歡這篇文章执桌,就點(diǎn)一下??吧??

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市芜赌,隨后出現(xiàn)的幾起案子仰挣,更是在濱河造成了極大的恐慌,老刑警劉巖缠沈,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件膘壶,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡洲愤,警方通過(guò)查閱死者的電腦和手機(jī)颓芭,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)柬赐,“玉大人亡问,你說(shuō)我怎么就攤上這事。” “怎么了州藕?”我有些...
    開(kāi)封第一講書人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵束世,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我床玻,道長(zhǎng)毁涉,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任锈死,我火速辦了婚禮贫堰,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘待牵。我一直安慰自己严嗜,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布洲敢。 她就那樣靜靜地躺著,像睡著了一般茄蚯。 火紅的嫁衣襯著肌膚如雪压彭。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書人閱讀 49,185評(píng)論 1 284
  • 那天渗常,我揣著相機(jī)與錄音壮不,去河邊找鬼。 笑死皱碘,一個(gè)胖子當(dāng)著我的面吹牛询一,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播癌椿,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼健蕊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了踢俄?” 一聲冷哼從身側(cè)響起缩功,我...
    開(kāi)封第一講書人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎都办,沒(méi)想到半個(gè)月后嫡锌,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡琳钉,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年势木,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片歌懒。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡啦桌,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出歼培,到底是詐尸還是另有隱情震蒋,我是刑警寧澤茸塞,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布,位于F島的核電站查剖,受9級(jí)特大地震影響钾虐,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜笋庄,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一效扫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧直砂,春花似錦菌仁、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至洽蛀,卻和暖如春摹迷,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背郊供。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工峡碉, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人驮审。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓鲫寄,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親疯淫。 傳聞我的和親對(duì)象是個(gè)殘疾皇子地来,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

推薦閱讀更多精彩內(nèi)容