资讯动态

Spark/Flink 的 Web UI 不能裸奔:多租户平台的鉴权反向代理设计

发布时间:2026/8/22 11:40:44 来源:尧图企业网站定制
Spark UI 和 Flink Dashboard 是排障刚需——反压、checkpoint、数据倾斜,不看原生 UI 基本查不动。但这两个 UI原生没有任何鉴权,而 K8s 上最常见的暴露方式是 per-job NodePort 或 Ingress 直通,等于把它们裸放在内网里:Flink 的 REST API 能直接提交 jar,裸暴露 远程代码执行入口,公网上被扫到就是挖矿(真实发生过的攻击面);Spark UI 的 environment 页会把配置全量吐出来,S3 的 AK/SK、数据库连接串都在里面;多租户下更致命:A 租户顺着端口能看 B 租户的作业、日志和数据路径。「我的数据空间」(datastudiohappy.cn)的做法是:引擎 UI 流量全部收进平台网关,做一个带鉴权的反向代理,与业务 API 同一套登录态、同一个信任边界,按工作空间成员关系放行。方案经过两轮对抗式安全评审,下面是评审后活下来的五个关键设计。一、五个关键设计1. 短时票据换「按作业限定作用域」的 cookie。引擎 UI 是 SPA,页面会自发加载几十个子资源,每个请求都要带上身份。做法:用户点「查看引擎 UI」→ 平台校验空间成员身份后签发一张 HMAC 短时票据 → 首个请求验票后换成HttpOnly、SameSiteStrict、Path 限定到这一个作业代理前缀的 cookie。子资源自动携带,而 A 作业的 cookie 天然到不了 B 作业的路径——跨作业越权在 cookie 作用域这层就断了。2. 鉴权判定与转发,必须是同一个 canonical 路径。先把路径做单次 percent-decode、解析掉.和..,再拿同一个归一结果去做鉴权判定和上游转发。如果判定看原始路径、转发前再解码一次,%65、点段、大小写这些花活就能做出「判定时是安全路径、到上游被重解析成敏感端点」的绕过——这是代理类系统最经典的洞。3. 路径闸分双态:活集群黑名单,历史态白名单。运行中的集群是单作业单租户的,只需挡掉全量配置 dump 这类高危端点,日志页照常放行(那是租户排障的主诉求);History Server 是共享服务,反过来默认全拒、白名单放行,且作业深链只放行本作业的 applicationId——共享面上,白名单才是正确的默认。4. 不改写响应体,但要接住重定向和根绝对链接。改写 HTML 响应体去修链接是不归路(改不全、易注错)。真正要处理的是两件事:上游 302 返回的Location是绝对内网地址,要改写回代理路径、域外一律丢弃(否则内网 IP 直接泄给浏览器);Spark UI 的页面链接是根绝对路径(/static/...),经代理访问会打到服务器根上 404——用 Spark 认的X-Forwarded-Context头让引擎自己把代理前缀拼进所有链接。顺带一个教训:这类问题curl 全程发现不了,它不加载页面里的资源链接,必须真浏览器走查。5. 脱敏兜底,不指望端点黑名单堵凭证。配置里的敏感项不可能靠枚举端点堵干净,代理层对响应做统一脱敏:高熵 secret 全量抹除、access key 就近遮蔽。纵深防御的最后一层要放在所有流量必经的位置上。二、历史 UI:存储隔离在前,路径闸退居纵深作业结束后 UI 要能回看(History Server)。这里的隔离主力其实在存储层:事件日志按租户前缀归档、每租户一把只读到自己前缀的 scoped 凭证,History Server 按需为单个租户拉起、闲置自动回收。这层做对之后,路径闸按 applicationId 的收敛就降级为纵深防御——隔离靠存储边界,不靠 UI 层的过滤。对用户来说,这一切只是作业详情页上的一个按钮:三、三句话总结引擎原生 UI 无鉴权,NodePort/Ingress 直通不是「简陋」,是 RCE 与凭证泄露级别的攻击面;代理的安全内核就三件:作用域限定的凭证载体、判定与转发同一 canonical 路径、共享面白名单;响应体不改写,Location 与根绝对链接交给标准头处理,凭证靠代理层脱敏兜底——并且一定要用真浏览器验收。这套引擎可观测能力是「我的数据空间」的一部分——一套可私有化部署的数据平台,支持 OEM 合作。产品介绍:https://datastudiohappy.cn/。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价