vSphere Client 登录失败:WS1B OAuth2 Client 丢失排查与恢复(KB 311960 实战)
某天早上打开 vSphere Client,登录页转两下就报错,连错误提示都很含糊。打开浏览器 F12 看到的是一个很”底层”的错误码:
1 | oauth2.client.with.client.id.not.found |
顺着这条线挖下去,最后定位到是 vCenter 的 WS1B OAuth2 Client 记录丢失,用 Broadcom KB 311960 的步骤重建后恢复。
这篇记录完整排查链路、取证命令和几个把我带偏的坑。
一、先确认:不是密码错,也不是锁定
登录失败最容易被误导的方向是”密码错了”或”账号被锁”。用 LDAP 直接绑一下,然后去 vmdird 日志里看具体是哪一种:
1 | # LDAP bind 失败 |
日志里的关键区别:
| 日志事件 | 含义 |
|---|---|
VdirPasswordFailEvent + LDAP_INVALID_CREDENTIALS(49) |
密码错 |
| lockout 相关事件 | 账号被锁定 |
两者在客户端都表现为 “Invalid credentials”,必须靠日志区分。本次是前者——但我清楚地知道密码没错,所以问题不在这条路上。
顺带一个教训:root 的 SSH 密码 ≠ SSO administrator 的密码。这是两套完全独立的体系,排查时不要混用。
二、复现:直接打 authorize 端点
vSphere Client 的登录本质是一次标准 OAuth2 authorization code 流程。直接打那个端点,就能看到裸的、不带前端美化的错误:
1 | curl -sk -H 'Host: vcenter.example.com' -H 'User-Agent: Mozilla/5.0' \ |
返回:
1 | HTTP 400 |
注意这里有个大坑:请求必须带正确的 Host 头。vCenter 前面是 envoy 反代,Host 不对的话 Header 校验失败,envoy 直接返回 444 且无响应体——看起来像”服务挂了”,其实只是 Host 写错了。这个假象很容易让人往”vCenter 服务异常”的错误方向跑。
三、日志证据
| 日志路径 | 关键内容 |
|---|---|
/var/log/vmware/vc-ws1a-broker/accesscontrol-service.log |
OAuth2ClientNotFoundException: oauth2.client.with.client.id.not.found[getValidatedClient] Client not found |
/var/log/vmware/envoy/envoy-access-*.log.gz |
登录流量的真实请求:GET /acs/t/CUSTOMER/authorize?client_id=...&redirect_uri=.../ui/login/oauth2/authcode |
/var/log/vmware/vmdird/vmdird-syslog.log |
VdirPasswordFailEvent(用来排除密码问题) |
四、去数据库里确认”客户端真的没了”
vCenter 的 OAuth2 client 存在 VCDB 的 vidm_schema.ACS_OAuth2Client 表里。Appliance 自带的 postgres 可以免密登录:
1 | psql -h localhost -U postgres -d VCDB |
注意:表名和列名全是驼峰,查询时必须加双引号,否则会报列不存在。
1 | -- 列出所有 OAuth2 client |
本环境查出来的结果很说明问题:表里只有 8 个 2022 年创建的内部 client(crypto / accesscontrol / token / operator / usergroup / federation / tenant_admin × HWS / CUSTOMER / OPERATOR),而 vCenter 登录实际使用的那个 client —— 一条记录都没有。
结论明确:不是配置写错,是记录整个丢失了。
ACS_OAuth2Client 的关键列:
clientId/tenantId/secret(varchar 4000)grantTypes/scopesredirectUri(varchar 2048,正好对应 KB 里说的长度上限)postLogoutRedirectUri(2048)isOIDCClient
五、好消息:原始凭据还在 VMDir 里
client 记录没了,但 provider 的配置保存在 VMDir 的 LMDB 数据库里:
1 | /storage/db/vmware-vmdir/data.mdb |
正常应该用 LDAP 查。但当没有可用凭据、LDAP 查不到时,可以直接从 LMDB 文件里按字符串提取:
1 | import re |
提取出来的字段(顺序即文件中的顺序):
1 | auth.example.cn # 外部 IdP 主机 |
有了 client_id 和 client_secret,就能按 KB 重建了。
六、恢复步骤(KB 311960)
前置条件:需要一个能正常登录的 vsphere.local 管理员账号。
1 | SSO='administrator@vsphere.local' |
验收:重新执行第二步那个 authorize 请求,应从 HTTP 400 + client.id.not.found 变成 302(跳转到外部 IdP 登录页)。
实际结果:
- POST 重建 → HTTP 201,返回新记录 uuid
- DB 检查 →
ACS_OAuth2Client出现该行(tenant=CUSTOMER,isInternal=false,redirectUri 正确) POST /acs/t/customer/token(Basic + client_credentials)→ 200 + access_token(说明 secret 正确)- authorize 端点 → 从 400 变 302(location 指向
/federation/t/CUSTOMER/auth/login?...)
KB 文档本身有个笔误:文档示例里 post_logout_redirect_uris 最后一条写成了 .../ui/login/oauth2/authcode,与前面几条的 .../ui/login?logout 格式不一致,按 ?logout 写。
顺带验证了一下 KB 提到的”ELM 节点多 + 主机名长导致 redirectUri 超过 2048”这个成因是否成立:
1 | python /usr/lib/vmware-lookupsvc/tools/lstool.py list \ |
只有一个节点 → 本环境的成因不是”超长”,就是记录单纯丢失。
七、踩过的坑(重点)
1. 差点改错关联表——动手前先反查 uuid
ACS_RuleSetAssociation 表里有两行 subjectType=client 的记录。我一度认为它们是”被删 client 留下的悬空引用”,准备 UPDATE 成新 client 的 uuid。
结果发现搞错了:那个 uuid 其实是 tenant_admin_client(CUSTOMER)的 uuid,对应 “Super Admin” 规则集,是正常的原有配置。
好在动手前有备份,发现后逐行还原并比对通过。
教训:修改任何关联关系之前,先把 uuid 反查清楚它属于哪条记录。
1 select "clientId","tenantId","displayName" from vidm_schema."ACS_OAuth2Client";全表扫一遍,花不了 10 秒。
2. 改表前必须备份整表
1 | copy (select * from vidm_schema."ACS_OAuth2Client") |
这次能顺利完成回滚验证,全靠这份备份。
3. 别用响应长度判断 session 是否成功
401 的错误 JSON 也有 400+ 字符,肉眼扫一眼很容易误判成”拿到 token 了”。
**必须看 [HTTP %{http_code}]**,或者判断响应体里是否包含 "value":"。
4. psql -f 不能和 -c 混用
1 | psql -tAc -f file # ❌ 会把 -f 当成 -c 的参数值 |
5. 想查”某个 uuid 被哪些表引用”?别逐表二分
用 information_schema 生成 union all 查询一次性扫完,效率高得多:
1 | select string_agg( |
6. 内部服务端口清单(别指望绕过鉴权)
accesscontrol=10114、token=10113、usergroup=10118、federation=10115 —— 都是内部 HTTP,直接访未授权请求只会返回 444/401。
7. /etc/krb5.keytab 可能是 0 字节
没有 default realm 的情况下,GSSAPI 机器账号绑定完全不可用,别指望走这条路读 VMDir。
八、遗留问题
client 修好后,第二段链路继续跟下去会撞到另一个错:
1 | Workspace ONE Access encountered an error. Message: Invalid access policy |
排查记录(留档给接手的人):
- 换完整 Chrome UA、带 cookie jar 跟重定向、直连该端点 —— 都是 500,不是单纯的 UA 问题
ACS_RuleSet里 CUSTOMER 与 OPERATOR 的default_access_policy_set(tag=APP_ACCESS)规则体完全一致,没法通过”对比租户”判断哪边缺配置- 日志里有真实浏览器请求(9/14 16:04、16:06)也撞到同一个
Deny access based on ruleset resolution result→ 这个策略拒绝很可能早于本次 client 丢失就存在,属独立问题 - vCenter 在 9/14 23:21 / 23:26 / 00:00 / 00:14 被连续重启 4 次,说明当晚已经有人在排查;日志只保留到 9/14 15:32 之后,没法对比更早的”登录成功”记录
- 下一步方向:确认 client 是否应绑定 app access policy(
rule_set_names)。本次创建时该字段为空数组(KB 的 content-type 名叫...with.rule.sets+json,暗示本应带规则集),但该版本上 API 的 GET/PUT 走/acs/oauth2clients/<uuid>返回 404、PUT 返回 405,没能通过 API 补写
九、小结
- 症状含糊时,直接打底层端点。vSphere Client 前端只给一句”登录失败”,而
curl打 authorize 端点能拿到精确到 client_id 的裸错误。 - 注意 Host 头。envoy 在 Host 不对时返回 444 无响应体,极易误判成”服务挂了”。
- **先确认”是记录没了”还是”是配置错了”**。查 DB 全表,比对着文档瞎猜快得多。
- 凭据可能还在别处。client 记录没了,但 VMDir 的 LMDB 里还躺着 client_id / secret。
- 动关联表之前,先反查 uuid 属于谁;动表之前,先备份整表。 这两条让我避免了一次真实的误操作。