Ambari Kerberos下Trino Web UI接入Knox双认证实践
2026/9/12 4:58:30 网站建设 项目流程

团队把 Ambari 集群的 Kerberos 开关打开之后,老 HDP 栈常见的那套问题一个接一个冒出来。其中最让我头疼的不是 HDFS,也不是 Hive,反而是看起来最不起眼的 Trino Web UI。Trino 的 CLI 可以通过 Kerberos 正常连接,但浏览器访问 Web UI 要么一直 401,要么干脆空白。后来把 Knox 加进来做统一入口,才算把这条链路理顺。这篇文章就是把当时踩过的坑、试过的方案、最后落地的配置完整记录下来,给同样在 Ambari 开启 Kerberos 之后需要把 Trino Web UI 交给 Knox 的团队一个可复现的参照。

1. 先说清楚:Trino Web UI 在 Kerberos 集群里到底卡在哪

1.1 Trino 的 HTTP 服务认证逻辑

Trino 的 Web UI 本质上不是独立应用,而是 Trino HTTP Server 上的一组静态资源加 REST API。默认监听 8080 端口,/ui/路径返回前端页面,/v1/statement/v1/info这些路径则提供服务状态和查询接口。

集群没有开 Kerberos 的时候,这个 HTTP Server 默认不认证,任何人只要能访问 8080 端口就能打开查询页面。Ambari 开启 Kerberos 之后,Trino 如果配置了http-server.authentication.type=KERBEROS,那么 HTTP Server 会启用 SPNEGO 认证。服务端以自己的 HTTP principal 作为身份,通常是HTTP/trino-host.example.com@EXAMPLE.COM,所有浏览器请求必须携带协商好的 Kerberos 票据,否则返回401 Unauthorized

这个机制本身没有问题,但对使用者极不友好。浏览器需要额外配置auth_negotiate白名单,主机名必须和 principal 完全匹配,静态资源请求也会触发 SPNEGO,经常一个页面加载出一堆 401 记录。Trino CLI 和 JDBC 客户端走的是标准 Kerberos 认证流程,配置好 keytab 和 krb5.conf 之后通常一次成功,但 Web UI 的用户往往不是愿意折腾浏览器底层配置的人。

1.2 为什么"You have to have a ticket"这条路走不通

我在现场排障时遇到过最典型的场景:DBA 把 Kerberos 票据申请好后,用浏览器打开http://trino-host:8080/ui/,Chrome 直接弹一个登录框,输入域账号密码之后还是 401。原因往往不是密码错误,而是浏览器根本不认识 SPNEGO 协商流程。

Trino 的 Kerberos 认证走的是 HTTP Negotiate 协议。服务端返回WWW-Authenticate: Negotiate,浏览器需要用本地的 Kerberos ticket 构造 SPNEGO token 回传。这个过程中,如果浏览器所在机器没有加入域,或者没有配置intranet站点的协商白名单,或者访问的地址和 Trino 的 service principal 中注册的 hostname 不一致,就会失败。对于只在内网用网页查询数据的人,这个门槛太高。

1.3 Knox 在中间扮演的角色

Knox 解决的核心问题是统一入口。用户不需要直接面对 Trino 的 8080,也不需要在浏览器上配 Kerberos,只需要访问https://knox-host:8443/gateway/default/trino-ui/ui/,Knox 替用户完成认证,再向后端 Trino 发起请求。这里的难点在于 Knox 不是透明代理,它有自己的认证、rewrite、header 处理逻辑,需要明确告诉它后端是什么,路径怎么映射,认证用什么方式。这也是很多人配完之后一脸懵的原因。

2. 方案取舍:三种接入方式的对比与选择

2.1 直连 Trino + 浏览器 SPNEGO

最朴素的方式,用户直接访问 Trino 8080 端口,浏览器走 Kerberos 协商。优点是少一层网关,不需要 Knox。缺点是整个浏览器访问链路的体验非常差,而且如果 Trino 被部署在边缘节点,8080 端口直接暴露在办公网有安全风险。在 Kerberos 开启的集群里,直连还要求每个访问用户的浏览器环境都正确配置,运维谈判成本极高。

2.2 Knox + Trino 纯 Kerberos 认证

理论上最"正统"的方案:用户访问 Knox,Knox 认证通过后,以 Kerberos 客户端身份向 Trino 发起 SPNEGO 协商。但这个方案在实操层面最麻烦。Knox 虽然支持 Kerberos 相关的认证 provider,但要让它自动为每个后端连接维护 SPNEGO token、处理协商循环,配置复杂度很高,且不同版本的 Knox 支持情况差异很大。我曾经试着在 Knox 的 topology 里加 SPNEGO 客户端配置,最后因为 Knox 自带的服务定义里没有一个能干净地处理 Negotiate 过程而放弃了。

2.3 Knox + Trino 双认证(KERBEROS + PASSWORD)

最终我采用的是这个方案。Trino 端开启KERBEROS,PASSWORD双认证,CLI、JDBC 这些服务间调用继续走 Kerberos,Web UI 的 HTTP 请求则通过 Knox 转发时携带 Basic Auth 凭据,使用 Trino 的 Password Authenticator 完成认证。

这个方案的优点在于:

  • 不破坏已有 Kerberos 安全链路。
  • 用户只感知 Knox 的统一认证入口。
  • Knox 到 Trino 之间的认证机制简单可控,排障难度低。

安全上我做了限制:Trino 的 8080 端口只对 Knox 节点和运维网段开放,办公网用户只能访问 Knox 的 8443。如果你们安全要求很高,还可以在这个基础上做 IP 白名单,或者给 Knox 单独分配一个服务账号,不让它代替用户传递密码。

三种方式对比如下:

方案用户操作复杂度配置复杂度后端暴露风险推荐程度
直连 Trino + SPNEGO高,依赖浏览器配置不推荐
Knox + 纯 Kerberos很高,依赖版本支持较低看情况
Knox + 双认证低,可加白名单推荐

3. 环境准备:Principal、Keytab、密码文件一个都不能少

3.1 KDC 上为 Trino 准备 principal 和 keytab

在 Ambari 开启 Kerberos 的环境里,KDC 通常已经存在,我这边是 MIT KDC。要做的第一步是给 Trino 的 HTTP Server 创建 principal。

使用HTTP作为 service name,因为 Trino 默认http-server.authentication.krb5.service-name=HTTP。假设 Trino 安装在trino-host.example.com,realm 是EXAMPLE.COM,命令如下:

sudo kadmin.local -q "addprinc -randkey HTTP/trino-host.example.com@EXAMPLE.COM" sudo kadmin.local -q "ktadd -k /tmp/trino.keytab HTTP/trino-host.example.com@EXAMPLE.COM"

然后把 keytab 拷到 Trino 节点上,并设置正确的属主和权限:

sudo scp /tmp/trino.keytab trino-host:/etc/trino/conf/ sudo chown trino:hadoop /etc/trino/conf/trino.keytab sudo chmod 400 /etc/trino/conf/trino.keytab

这里有个细节:Trino 的 HTTP principal 的 hostname 必须和浏览器访问的 hostname 一致。如果你希望通过 Knox 转发,其实 Trino 不需要对外开放,但 principal 里的 hostname 仍然要是本机实际解析名,否则 Trino 启动时拉取 keytab 会报 principal 不匹配。

3.2 Trino 端开启双认证

编辑 Trino 的config.properties,一般在/etc/trino/conf/config.properties。关键配置如下:

http-server.authentication.type=KERBEROS,PASSWORD http-server.authentication.krb5.service-name=HTTP http-server.authentication.krb5.keytab=/etc/trino/conf/trino.keytab http-server.authentication.krb5.principal=HTTP/trino-host.example.com@EXAMPLE.COM password-authenticator.name=file file.password-file=/etc/trino/password.db

http-server.authentication.type同时保留KERBEROSPASSWORD,这样 Trino 对同一端口既接受 Kerberos 协商,也接受 HTTP Basic 认证。Trino 在检测到请求头里的 Authorization 类型后会自动进入不同认证流程,不需要额外配置两个端口。

生成密码文件可以使用 htpasswd,Trino 的 file password authenticator 要求 bcrypt 格式:

sudo htpasswd -B -C 10 -c /etc/trino/password.db trino_service

这里我建了一个专用服务账号trino_service,后面 Knox 转发时统一用它。注意-B参数指定 bcrypt,-C 10指定 cost 值,Trino 对这个格式支持得很稳定。

如果你用的是 Ambari 管理的 Trino 服务,也可以在 Ambari UI 的 Trino Configs 里找自定义trino-config项,把上面的属性加进去。Ambari 保存后会重新生成配置并触发滚动重启。如果 Trino 是纯手工部署,直接改文件后重启 Trino 服务即可。

3.3 Knox 侧准备事项

在动手改拓扑之前,先确认三件事:

一是 Knox 服务本身的运行状态。HDP 环境下可以执行:

/usr/hdp/current/knox-server/bin/knoxcli.sh status

二是 Knox 节点到 Trino 节点的网络连通性。用 Knox 主机直接 curl 一下 Trino:

curl -u trino_service:password http://trino-host.example.com:8080/v1/info

如果这一步 401 或者连接超时,先解决网络和认证问题再配 Knox。

三是准备好 Knox 对外使用的认证用户。我这边用的是 LDAP 域账号,Knox 通过 ShiroProvider 接 LDAP 完成认证。如果你不想接 LDAP,也可以配置本地文件 realm,但生产环境建议 LDAP,方便和现有账号体系打通。

4. Knox 拓扑与服务定义:把 Trino UI 挂到网关路径上

4.1 查看 Knox 有没有现成的 Trino/Presto 服务定义

Knox 的 service definition 决定了一个服务角色支持哪些路径、如何做 URL rewrite、使用什么 dispatch 策略。先看本地有没有,避免重复造轮子:

ls /usr/hdp/current/knox-server/conf/services | grep -iE 'trino|presto'

我这边 HDP 版本的 Knox 自带了一个presto.xml,但打开后发现它主要覆盖的是/v1/**这一类 REST API 路径,对/ui/**静态资源路径支持不全。直接用它的话,/ui/页面能转发,但页面里的 JS 和 CSS 会加载不出来,或者路径被 rewrite 得乱七八糟。

最简单的办法是自己写一个专门给 Trino UI 用的服务定义。这个文件不影响 Knox 其他服务,安全可靠。

4.2 自定义一个 trino-ui 服务定义

在 Knox 的服务定义目录下新建trino-ui.xml

sudo vi /etc/knox/conf/services/trino-ui.xml

内容如下,核心是两条 rewrite 规则和两个 route:

<service role="TRINO-UI" name="trino-ui" version="1.0.0"> <rewrite name="inbound" path-params="true"> <rule pattern="http://${gateway.host}:${gateway.port}/${gateway.path}/trino-ui/{path=**}?{query}"> <rewrite template="/{path=**}?{query}" /> </rule> </rewrite> <rewrite name="outbound" path-params="true"> <rule pattern="http://trino-host.example.com:8080/{path=**}?{query}"> <rewrite template="http://${gateway.host}:${gateway.port}/${gateway.path}/trino-ui/{path=**}?{query}" /> </rule> </rewrite> <routes> <route path="/**"> <rewrite name="inbound" /> <rewrite name="outbound" /> </route> </routes> </service>

这个文件的作用是:

  • inbound 规则把用户访问https://knox-host:8443/gateway/default/trino-ui/xxx的路径剥掉 Knox 网关前缀,转成/xxx
  • outbound 规则把 Trino 返回的响应中所有指向http://trino-host.example.com:8080的地址改写成 Knox 的地址,这样页面里的链接、重定向、静态资源请求不会跳出网关。

不同 Knox 版本的 rewrite 标签可能有一点点差异,如果加载报错,看 Knox 的 gateway.log 会明确告诉你哪条规则解析失败。大部分网上流传的报错都是路径参数没开path-params="true",导致路径里的参数被吞。

4.3 拓扑文件里注册服务并配置认证

Knox 的拓扑文件放在/etc/knox/conf/topologies/下。生产环境我建议新建一个独立拓扑,比如trino.xml,这样访问路径会更清晰:/gateway/trino/trino-ui/ui/。但如果你们的 Knox 已经有default.xml并且不想引入太多拓扑,也可以在已有 topology 里加 service。

拓扑文件示例:

<topology> <gateway> <provider> <role>authentication</role> <name>ShiroProvider</name> <enabled>true</enabled> <param> <name>sessionTimeout</name> <value>30</value> </param> <param> <name>main.ldapRealm</name> <value>org.apache.knox.gateway.shirorealm.KnoxLdapRealm</value> </param> <param> <name>main.ldapRealm.contextFactory.url</name> <value>ldap://ldap.example.com:389</value> </param> <param> <name>main.ldapRealm.userDnTemplate</name> <value>uid={0},ou=people,dc=example,dc=com</value> </param> <param> <name>urls./**</name> <value>authcBasic</value> </param> </provider> </gateway> <service> <role>TRINO-UI</role> <url>http://trino-host.example.com:8080</url> </service> </topology>

注意 provider 里的urls./**设置为authcBasic,表示所有请求都需要 Basic 认证。如果你的 LDAP 用户和 Trino 密码文件里的用户不是同一套,那后面还需要让 Knox 把 Basic header 继续传到后端,我在踩坑部分会详细说。

4.4 重启并观察日志

改完拓扑文件后,重启 Knox 让拓扑生效:

sudo -u knox /usr/hdp/current/knox-server/bin/gateway.sh restart

查看启动日志:

tail -f /var/log/knox/gateway.log

看到类似Loaded topology trino.xml的日志说明拓扑加载成功。如果出现服务未定义之类的报错,先检查服务定义文件的文件名和 role 名称是否与拓扑里的TRINO-UI匹配。Knox 会根据文件名默认推断 role,文件名不匹配会导致拓扑加载失败。

5. 验证链路:curl 联调、浏览器登录、UI 加载

5.1 先直接验证 Trino HTTP 服务

在配 Knox 时最容易犯的错误是后端 Trino 本身还没就绪就急着调网关。先在 Trino 节点上验证:

curl -u trino_service:password http://trino-host.example.com:8080/v1/info

如果返回 JSON 数据,说明双认证配置生效,密码认证可以正常访问。

如果返回 401,查看 Trino 日志里有没有Authentication failed或者Basic authentication failed,确认password.db里的用户名密码是否正确。顺便提一句,http-server.authentication.type如果同时配置KERBEROSPASSWORD,一定不能写成KERBEROS,PASSWORD带空格,Trino 的属性解析对空格很敏感,写错会导致整个认证配置不生效。

5.2 验证 Knox 代理后的 API

在 Knox 节点或者办公网测试机执行:

curl -k -u alice:password https://knox-host:8443/gateway/trino/trino-ui/v1/info

这里的alice是 LDAP 域账号。如果返回和上一步一样的 JSON,说明 Knox 到 Trino 的转发链路已经打通,认证头也被正确传递。

如果这一步报 401,先用-v参数看完整请求响应:

curl -k -v -u alice:password https://knox-host:8443/gateway/trino/trino-ui/v1/info

重点看响应头里是否有WWW-Authenticate: Negotiate。如果后端 Trino 仍在要求 Kerberos 而不是 Basic,说明 Knox 转发时把Authorization头丢掉了或者没有带上。

5.3 验证 UI 页面

API 通了之后验证静态页面:

curl -k -u alice:password -i https://knox-host:8443/gateway/trino/trino-ui/ui/

正常情况下返回200 OKContent-Type: text/html。用浏览器的开发者工具打开 Network 面板,随便点击几个 JS 和 CSS 资源,确认它们的请求地址都落在https://knox-host:8443/gateway/trino/trino-ui/前缀下,而不是 Trino 的 8080 地址。

如果前端资源加载不出来,大概率是 outbound rewrite 没有覆盖到静态资源的响应路径。这时不要急着怀疑 Knox,先用 curl 把 HTML 内容拉下来,用文本编辑器搜索trino-host8080,看看是否还有裸地址残留。

5.4 浏览器实操

上面的步骤都过了之后,浏览器访问:

https://knox-host:8443/gateway/trino/trino-ui/ui/

浏览器弹出认证框,输入 LDAP 账号密码,进入 Trino 查询页面。

此时做两件事:先执行一个最简单的SELECT 1,确认 UI 能正常提交查询;再执行一次SHOW SCHEMAS FROM hive,确认 Trino 和 Hive 之间的 Kerberos 票据获取正常。如果查询报GSSException,那是 Trino 引擎自身访问 Hive 或 HDFS 的 Kerberos 认证问题,和 Knox 无关,需要回过去查 Trino 的 keytab 和 catalog 配置。

6. 踩坑记录:那些"明明配对了还是不行"的瞬间

6.1 Knox 自带的 Presto 服务只代理了/v1,UI 404

我一开始图省事,直接用 Knox 自带的PRESTO角色,在拓扑里加了:

<service> <role>PRESTO</role> <url>http://trino-host.example.com:8080</url> </service>

结果访问https://knox-host:8443/gateway/trino/presto/ui/返回 404。查 Knox 服务定义目录里的presto.xml,发现 routes 里只有/v1/**的路径映射,UI 路径完全没覆盖。

这就是前面说为什么要自定义trino-ui.xml的原因。Knox 自带的服务定义主要是为了 CLI 和 JDBC 走 REST API 设计的,Web UI 这种带静态资源的场景需要单独定义。

6.2 Trino 把 UI 重定向到自己的 8080

这个坑藏得很深。Trino 的/ui不带尾部斜杠时会 302 到/ui/。在特殊版本下,这个 Location 有时会被拼成http://trino-host.example.com:8080/ui/。浏览器收到后直接跳出了 Knox 网关。

排查方法很简单,用 curl 看 302 响应:

curl -k -u alice:password https://knox-host:8443/gateway/trino/trino-ui/ui

看返回的Location字段。如果指向后端 Trino 的 8080 端口,说明 outbound rewrite 没有处理这一个响应头。在我的自定义服务定义里,outbound 规则已经覆盖了 Trino 主机地址,所以这个坑其实是上一个坑的衍生问题,服务定义改好之后自然消失。

6.3 认证头被吞导致 Trino 报 401

Knox 的 ShiroProvider 完成认证后,默认不一定把用户的Authorization头透传给后端。如果 Trino 的 Password Authenticator 收不到 Basic 头,Knox 就会一直向后端发匿名请求,后端返回 401,Knox 再把 401 透给浏览器,浏览器再次弹认证框,形成循环。

我的拓扑里 LDAP 认证的账号和 Trino 密码文件里的账号并不一样。我是这样解决的:让 Knox 认证通过后,在 rewrite 阶段手动注入一个固定的 Basic Authorization 头,无论用户是谁,Knox 后端都统一用trino_service这个服务账号访问 Trino。这样用户侧认证和引擎侧认证解耦,我不用要求每个用户都在 Trino 密码文件里也有账号。

在 Knox 里实现 header 注入,要根据版本选择方式。新版本支持在 provider 里配置header预处理,老版本则需要写一个简单的过滤器。如果你遇到这个问题,可以先查 Knox 的gateway.log,看认证后的请求头长什么样,再决定用哪种方式。这是整个方案里唯一需要动代码或者高级配置的地方,建议留足时间。

6.4 Kerberos 的 SPNEGO 循环:浏览器反复弹框

如果你在 Trino 端只配置了KERBEROS认证,浏览器通过 Knox 访问时会出现反复弹框,输入账号密码也没用。原因很简单:后端返回的是WWW-Authenticate: Negotiate,浏览器以为你要走 Kerberos 协商,但 Knox 又没参与协商,最终双方僵住。

这就是我不推荐 Knox + Trino 纯 Kerberos 方案的原因。只要你能接受 Trino 的 Web UI 走 Password Authenticator,这个问题就不存在。CLI 和 JDBC 依旧走 Kerberos,不会因为开了 PASSWORD 而降低查询链路的安全等级。

6.5 页面能开但查询报 GSSException

Knox 这层完全连通后,Web UI 能打开,执行查询却报GSSException: No valid credentials provided。这个报错来自 Trino 引擎访问 Hive connector 时的 Kerberos 认证,和 Knox 无关。

检查方向:

  • Trino 进程是否以trino用户运行,keytab 是否可以读取。
  • klist -ekt /etc/trino/conf/trino.keytab确认 principal 和 keytab 条目。
  • jvm.config里有没有设置-Djava.security.krb5.conf=/etc/krb5.conf-Djavax.security.auth.useSubjectCredsOnly=false
  • Trino 的hive.metastore.authentication.type=KERBEROShive.metastore.service.principal是否配置正确。

页面能打开只是前菜,引擎能真正查询才是终点。

6.6 Cookie 和静态资源的 Path 问题

Trino UI 的某些版本会写 cookie,Path默认是/。如果 Knox 后面还挂了其他服务,这个 cookie 可能会污染其他路径。处理方式是在 Knox 的 outbound rewrite 里对Set-Cookie响应头做路径替换。我用的是自定义服务定义,outbound 规则会把Path=/替换成Path=/gateway/trino/trino-ui/,避免影响同域名下的其他服务。

这个坑不一定每个版本都会遇到,但如果页面能打开、查询也能跑,就是刷新后偶尔跳回登录页,先查 cookie 的 Path 对不对。

在我处理这个问题的整个过程中,最核心的体会是一定要把认证链路拆成两段来看:用户到 Knox 是一段,Knox 到 Trino 是另一段。Ambari 开启 Kerberos 只是让第一段的难度变高了,第二段反而可以用更可控的方式来做。如果你们跟我一样不想让 Trino 的 8080 端口暴露在办公网,同时又希望给数据分析师一个不太折腾的网页查询入口,Knox + Trino 双认证这个组合是目前比较稳妥的选择。最后再补一句,生产环境上线前一定要把 Trino 的 8080 端口用防火墙限到只有 Knox 节点能访问,双认证只是功能层面的兜底,网络层才是第一道防线。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询