在服务账户密钥过期后,Atlas Search的 $vectorSearch会向所有用户返回“PlanExecutor :: Authentication failed”

后端开发 2026-07-09

在一个MongoDB Atlas M10集群(GCP,MongoDB 8.0.23)上,$vectorSearch 查询突然对所有用户返回 PlanExecutor error during aggregation :: caused by :: Authentication failed —— 无论是我的管理员用户(atlasAdmin 角色)还是按租户划分的 readWrite 用户。

奇怪的部分:使用 相同的凭据,在 相同的集群/集合 上,这些操作都正常工作:

client[db].embedded_movies.estimated_document_count()              # → 3483 OK
list(client[db].embedded_movies.list_search_indexes())             # → vectorPlotIndex, READY, queryable=true
client.admin.command('connectionStatus')                           # → roles: atlasAdmin, readWriteAnyDatabase, ...

但我测试的每个用户都失败了:

list(client[db].embedded_movies.aggregate([
    {"$vectorSearch": {
        "index": "vectorPlotIndex",
        "path": "plot_embedding",
        "queryVector": [0.01] * 1536,
        "numCandidates": 50, "limit": 3,
    }},
]))

# pymongo.errors.OperationFailure:
#   PlanExecutor error during aggregation ::
#   caused by :: Authentication failed.
#   {'code': 8, 'codeName': 'UnknownError'}

向量搜索索引在所有分片上通过Admin API显示 status: READY, queryable: true。我尝试过:

  • 通过Atlas Admin API(非mongosh)删除并重新创建索引 → 同样的错误
  • 具有不同角色级别的多名用户 → 同样的错误
  • 从不同机器 / 不同的pymongo版本连接 → 同样的错误
  • Atlas自动触发 CLUSTER_UPDATE_STARTED + 3× HOST_MONGOT_RESTARTED 事件,在服务账户密钥过期后5 分钟发生 → 未解决

在Atlas项目事件日志中我注意到的情况:

21:34Z  (SA secret expires)
23:27Z  Atlas sends alert "Organization Service Account Secrets have expired"
23:32Z  CLUSTER_UPDATE_STARTED
23:34Z  HOST_MONGOT_RESTARTED  (shard 0)
23:36Z  HOST_MONGOT_RESTARTED  (shard 1)
23:37Z  HOST_MONGOT_RESTARTED  (shard 2)
23:37Z  CLUSTER_UPDATE_COMPLETED
23:38Z+ $vectorSearch starts failing

时间点强烈表明mongot(Atlas Search进程)为某些内部认证缓存了旧的服务账户密钥,自动重启没有刷新它。

如何在不重启整个集群的情况下强制Mongo刷新其内部身份验证缓存?还是我对错误的理解有误?

解决方案

我发现这个根本原因:当Atlas Organization Service Account有 2个活跃密钥时(标准轮换模式),已过期的那个在过期后仍然会给Atlas Search带来问题。mongot(Atlas Search进程)似乎在内部缓存了该密钥以进行自我校验,而Atlas的自动 HOST_MONGOT_RESTARTED 流程并不能彻底刷新这个缓存。

修复办法:通过Atlas Admin API显式 DELETE 过期的密钥:

curl -X DELETE \
  "https://cloud.mongodb.com/api/atlas/v2/orgs/${ORG_ID}/serviceAccounts/${SA_CLIENT_ID}/secrets/${EXPIRED_SECRET_ID}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/vnd.atlas.2024-08-05+json"

→ 响应:HTTP 204 No Content → 紧接着,$vectorSearch 再次生效。无需重启集群。

如何识别受影响的密钥

curl "https://cloud.mongodb.com/api/atlas/v2/orgs/${ORG_ID}/serviceAccounts/${SA_CLIENT_ID}" \
  -H "Authorization: Bearer ${TOKEN}" \
  -H "Accept: application/vnd.atlas.2024-08-05+json"

在过去的记录中寻找带有 expiresAt 的密钥——那就是需要删除的密钥。

教训总结

  1. 错误信息 PlanExecutor :: Authentication failed 具有误导性——它暗示被查询的集合存在权限问题,但实际根本原因是Atlas Search的内部认证状态。如果看到此问题,请检查你的服务账户密钥。
  2. Atlas自动因密钥过期触发的 HOST_MONGOT_RESTARTED 事件并不能解决这个问题——需要手动DELETE。
  3. 将此步骤纳入你的SA轮换运行手册:创建新密钥 → 更新应用 → 等待旧密钥过期 → 显式删除旧密钥

为持续监控,这段脚本用于检查仍然存在且已过期的密钥(你可以把它接到cron +警报系统):

# Pseudocode
sa = atlas_api_get(f"/orgs/{ORG_ID}/serviceAccounts/{SA_CLIENT_ID}")
for secret in sa["secrets"]:
    if datetime.fromisoformat(secret["expiresAt"]) <= datetime.now(UTC):
        alert(f"Expired SA secret still present: {secret['id']} — DELETE it")
站内所有文章版权归属LeftHeroAI导航站,无授权禁止任何主体转载、抄袭、复制内容,亦不得私自架设镜像站点。一经侵权,本站将通过法律途径追责。

相关文章