当前位置: 首页 > news >正文

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

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、SameSite=Strict、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/。

http://www.cnnetsun.cn/news/4155763.html

相关文章:

  • 2026开题必备|OKBIYE开题报告功能深度实测,解决90%开题难题✅
  • Magpie 窗口放大教程:3 类场景选对缩放算法,老游戏画面立刻变清晰
  • RoPE旋转位置编码:统一绝对与相对位置,提升Transformer长文本建模能力
  • Boss Key 老板键:一键隐藏所有窗口的免费隐私助手
  • LLM Agent记忆安全:ADAM攻击原理与防御实践
  • 提升编程能力:机试代码训练与算法优化技巧
  • CodeBERT 实战指南:从读懂陌生代码库到跨语言维护的完整路径
  • 梯度流与扩散映射驱动的新型卡尔曼滤波器
  • 宝塔面板Docker商店一键部署DeepSeek智能Agent框架指南
  • 设备故障诊断与预测:多模态数据如何提前发现退化
  • 动态智能体拓扑:生成式演化与固定模块集重排序两种范式
  • 完整指南 Epub.js Reader:浏览器里直接读 EPUB 的开源阅读器
  • Linux系统故障排查实战:从日志审计到性能瓶颈定位
  • 《逃离塔科夫》网络连接优化:从系统底层到网络层的实战指南
  • 网页视频下载三步搞定:猫抓资源嗅探扩展与M3U8解析完整指南
  • 从零训练微型大语言模型:Horus-runtime框架实战与Transformer原理详解
  • 算法修炼入门:从数据结构到经典算法的“练气八层”核心指南
  • android-笔记-OpenCV-2 问题
  • 2026年乌鲁木齐PLC培训选哪家
  • HoRain云--Swagger 文档实例
  • GetQzonehistory:把 QQ 空间历史说说批量备份为 Excel 与 HTML 的本地开源工具
  • C语言链接库
  • C++左值与右值深度解析:从内存模型到移动语义实战
  • ESGUI V2.0.0:Python脚本快速打包成独立GUI应用与分发指南
  • 免费装好 Plus Jakarta Sans 开源字体:4 步走完最短上手路径
  • C++模板编程:从泛型思想到实战应用全解析
  • GitHub开源工具箱:从选型到实战,打造高效开发运维利器
  • OpenRouter集成Stripe支付:一站式LLM API聚合平台实战指南
  • C++可变参数模板:从语法到实战,实现类型安全的泛型编程
  • 技术解析|音频变调为什么会不真实?音高、共振峰与时长的三个耦合层面