Cortex 多租户认证与授权实战:基于 X-Scope-OrgID 的租户隔离方案
工试云启 考证服务中心整理

可观测性时序数据库后端指标监控【免费下载链接】cortexA horizontally scalable, highly available, multi-tenant, long term Prometheus.项目地址https://gitcode.com/gh_mirrors/cortex6/cortex点击查看免费下载本篇技术指南围绕 Cortex 的多租户认证与授权机制展开核心讲解X-Scope-OrgID请求头的传递方式、-auth.enabledfalse单租户模式、可信环境下的remote_write免认证接入以及如何借助反向代理与 cortex-tenant 代理为 Prometheus 请求注入租户标识。读完本文你将掌握在真实部署中为 Cortex 正确配置租户隔离、处理写入与查询租户一致性以及规避常见安全误配的完整方案。多租户模型一切组件都信任 X-Scope-OrgIDCortex 是一个水平可扩展、高可用、多租户的长期 Prometheus 存储系统。在多租户模型下每一个 Cortex 组件都会从每个请求的X-Scope-OrgID请求头中读取租户 IDtenant ID也称为 user 或 org。一个租户是写入到 Cortex、并从 Cortex 查询的一组时序数据的属主租户 ID 本质上就是这套时序数据在集群中的命名空间。这一机制的落地贯穿了从 HTTP 到 gRPC 的整条链路。在 HTTP 层middleware.AuthenticateUser负责从请求头提取租户 ID 并注入请求上下文context在 gRPC 层则通过middleware.ServerUserHeaderInterceptor与StreamServerUserHeaderInterceptor两个拦截器完成同样的工作参见 pkg/util/fakeauth/fake_auth.go。提取出的租户 ID 最终会被各组件用于数据读写、配额限制overrides、环形哈希分片ring sharding等所有与租户相关的逻辑。以写入链路为例Prometheus 通过remote_write将数据推送到 Cortex 的/api/prom/push端点Distributor 会依据请求上下文中的租户 ID 将时序数据路由并写入对应租户的存储空间查询链路则相反Querier 从上下文中取出租户 ID只读取该租户名下的数据。整个流程对租户 ID 的依赖是全链路、无例外的。信任边界与安全模型为什么必须增加额外防护层需要特别强调的是Cortex 的所有组件都完全信任X-Scope-OrgID的值它不会对这个值做真实性校验也不会反向验证调用方的身份。如果你的 Cortex 实例暴露在不可信网络中任何能够构造请求的人都可以通过伪造X-Scope-OrgID头冒充任意租户读写数据。因此若需要防止意外或恶意的调用就必须在 Cortex 之外增加一层额外的保护。典型做法是把 Cortex 部署在反向代理reverse proxy之后并确保所有调用方——无论是通过remote_write接口推送数据的机器还是通过 GUI 发起查询的人——都必须提供能够标识身份并确认其已获授权的凭据credentials。反向代理负责完成认证Authentication你是谁与授权Authorisation你能访问哪个租户校验通过后再代为注入X-Scope-OrgID头转发给后端的 Cortex 组件。在配置 Prometheus 的remote_writeAPI 时可以使用 HTTP Basic Auth 的user与password字段或 Bearer token 来携带租户 ID 和/或凭据。这是官方推荐的身份传递方式因为它把租户标识与调用方身份认证统一到了标准 HTTP 认证机制中反向代理可以透明地解析并校验这些凭据再转换为X-Scope-OrgID头。可信环境下的免认证接入在 remote_write 中直接设置请求头如果你运行在可信环境trusted environment中——例如集群内部网络、所有写入方都已被信任——可以让 Prometheus 自己发送X-Scope-OrgID头通过在remote_write配置的headers字段中直接声明即可remote_write: - url: http://cortex/prometheus/api/v1/push headers: X-Scope-OrgID: org其中org替换为你的租户 IDcortex替换为 Cortex 集群的入口地址。这种方式的优点是不需要额外部署代理组件配置简单直接代价是安全性完全依赖于网络环境的可信度——只要网络内有任意主机能连到 Cortex它就可以伪造该头。从源码角度看这一配置之所以能生效是因为 HTTP 层提取租户 ID 的中间件只是机械地读取X-Scope-OrgID头并写入上下文见 pkg/api/api.go 中HTTPAuthMiddleware对处理器的包装逻辑它不区分这个头是 Prometheus 自己发的、代理注入的还是攻击者伪造的。因此可信环境 自带头和不可信环境 代理校验两种部署方式必须在设计安全模型时就明确区分。关闭多租户-auth.enabledfalse 与 fake 租户如果不需要多租户功能例如单租户的私有部署可以向每一个 Cortex 组件传入-auth.enabledfalse参数。此时所有请求的租户 ID 都会被统一设置为字符串fake。该开关在 pkg/cortex/cortex.go 中定义默认值为truef.BoolVar(c.AuthEnabled, auth.enabled, true, Set to false to disable auth.)当AuthEnabled为false时pkg/util/fakeauth/fake_auth.go 中的SetupAuthMiddleware会做三件事为 HTTP 层挂载fakeHTTPAuthMiddleware该中间件直接把fake注入请求上下文再透传请求user.InjectOrgID(r.Context(), fake)为 gRPC 一元调用挂载fakeGRPCAuthUniaryMiddleware同样注入fake租户 ID为 gRPC 流式调用挂载fakeGRPCAuthStreamMiddleware包裹ServerStream使其上下文携带fake。也就是说关闭认证后 Cortex 内部的租户解析逻辑依然在运行只是所有请求都被强行归一到fake这一个租户名下数据全部写入fake命名空间。这保证了组件间通信代码无需感知认证是否启用内部依然保持多租户的处理逻辑。需要留意的是即使auth.enabled保持开启也并非所有 gRPC 方法都需要校验租户 ID。在 pkg/cortex/cortex.go 中有一份显式的豁免名单noGRPCAuthOn包括健康检查grpc.health.v1.Health/Check、前端到调度器的长连接schedulerpb.SchedulerForFrontend/FrontendLoop、Querier 与调度器的schedulerpb.SchedulerForQuerier/QuerierLoop等方法。原因是这些调用要么天然不带租户如健康检查要么单次长连接会为多个租户服务无法在握手阶段绑定单一租户 ID。租户 ID 命名规范写入前必须先校验的约束在配置租户 ID 之前务必了解 Cortex 对租户 ID 命名的三条硬性约束详见 Tenant ID 命名规范。虽然租户 ID 对 Cortex 而言是不透明的字符串但命名仍有限制1. 支持的字符集以下字符是安全可用的字母与数字0-9、a-z、A-Z特殊字符感叹号!、连字符-、下划线_、单个句点.但.和..本身无效、星号*、单引号、左括号(、右括号)除此之外的字符都不安全尤其不支持斜杠/和空白字符空格。这一限制的底层实现位于 pkg/util/users/tenant.go 的isSupported函数它逐 rune 校验租户 ID 中的每个字符一旦遇到不支持的字符会返回形如tenant ID xxx contains unsupported character y的错误。2. 无效租户 ID以下租户 ID 在 Cortex 中被视为无效并会被拒绝当前目录.父目录..标记目录__markers__Cortex 内部用于块存储元数据标记的全局目录名用户索引文件user-index.json.gz这些判断在CheckTenantIDIsSupported中实现pkg/util/users/tenant.go目的是防止租户 ID 与对象存储中预留的目录/文件名冲突杜绝路径穿越类问题。3. 长度限制租户 ID 长度不应超过150 字节/字符超出会返回tenant ID is too long: max 150 characters错误pkg/util/users/tenant.go。上述全部规则都有对应的单元测试覆盖见 pkg/util/users/tenant_test.go测试用例包含了 150 字符边界、151 字符超限、./../__markers__/user-index.json.gz无效 ID以及全量特殊字符组合的合法校验。这些测试可以直接作为你选择租户 ID 时的合法性判据。写入与查询的租户一致性最常见的查不到数据根因官方文档明确了一个非常容易踩坑的约束写入数据时使用的租户 ID必须与查询时使用的租户 ID 完全一致。如果两者不匹配写入的时序数据会落在租户 A 的命名空间而查询却以租户 B 的身份发起结果自然是看不到任何数据即使匹配目前的实现中你也无法跨租户查看其他租户的时序数据——多租户隔离在读写路径上都是严格按租户 ID 分隔的。这一点可以在源码中得到印证从上下文提取租户 ID 后Querier、Distributor、Ingester 等组件均以该 ID 作为读写数据的键例如 pkg/util/users/resolver.go 中SingleResolver.TenantID的解析流程存储索引、overrides 限制、环形分片等全部按租户隔离。因此在接入新的写入源时务必先确认remote_write的认证配置、反向代理注入规则与查询端的租户 ID 三者一致再排查其他原因。如果你计划使用多个租户并希望允许跨租户查询Cortex 提供了租户联邦tenant federation能力当-tenant-federation.enabledtrue时请求中可用|分隔多个租户 ID例如X-Scope-OrgID: tenant-a|tenant-b底层通过 pkg/util/users/resolver.go 中的MultiResolver解析并归一化排序 去重租户列表。需要说明的是启用联邦后对租户 ID 字符集的限制会更严格|将变为保留分隔符而不能再出现在单个租户 ID 中。这是本文主文档之外、从源码结构推断的进阶能力具体可参考 Ruler 租户联邦 及相关实现 regex_resolver.go。Cortex-Tenant 代理从 Prometheus 标签自动提取租户当 Prometheus 实例较多、且你不想为每个实例单独配置认证头时可以采用cortex-tenant代理方案它是一个能够从 Prometheus 标签labels中提取租户 ID 的代理组件可以放置在 Prometheus 与 Cortex 之间。其工作流程是Prometheus 仍按原有方式将时序数据推送到代理代理在收到的时序数据中查找一个预定义标签将该标签的值作为X-Scope-OrgID头在将时序数据转发给 Cortex 时注入。这种方案非常适合在可信环境中运行 Cortex 并按某种标准例如团队、应用等将指标划分到不同命名空间的场景你只需在 Prometheus 的指标上打一个统一的租户标签代理即可自动完成标签 → 租户的映射无需逐台修改 Prometheus 的remote_write认证配置。需要特别提醒的是cortex-tenant 是第三方社区项目并非由 Cortex 团队维护。在将它引入生产环境前你需要自行评估其维护活跃度、安全性与功能完整性同时由于它只是做标签到请求头的转换并不承担身份认证职责它更适合可信环境下的命名空间划分而非不可信环境下的访问控制。完整接入检查清单最后汇总一份将新数据源接入 Cortex 多租户集群的检查清单覆盖本文全部要点确定租户 ID遵循 租户 ID 命名规范字符集受限、长度 ≤ 150、避开保留名选择接入方式可信环境可让 Prometheus 在remote_write.headers中直接声明X-Scope-OrgID不可信环境必须在反向代理处完成认证再注入该头或使用 cortex-tenant 从标签自动提取统一读写租户确认写入认证配置与查询端使用的租户 ID 完全一致否则查询将看不到数据确认认证开关单租户部署可对所有组件传-auth.enabledfalse统一使用fake租户多租户部署保持默认true并理解 gRPC 豁免名单的边界验证隔离性确认不存在跨租户可见性除非显式启用租户联邦并可在 tenant_test.go 的用例基础上补充自己的租户 ID 合法性自测。按照以上步骤你就能在 Cortex 上搭建出符合预期隔离语义的多租户读写链路同时避免查不到数据租户串号这两类最典型的生产事故。赞分享可观测性时序数据库后端指标监控【免费下载链接】cortexA horizontally scalable, highly available, multi-tenant, long term Prometheus.项目地址https://gitcode.com/gh_mirrors/cortex6/cortex点击查看免费下载相关推荐Grafana Loki 多租户隔离实战从 X-Scope-OrgID 认证到跨租户查询与 __tenant_id__ 标签Grafana Loki 多租户隔离实战从 X Scope OrgID 认证到跨租户查询与 __tenant_id__ 标签 Loki 从设计之初就是一个多租可观测性日志分析后端微服务对象存储云原生Grafana Tempo 多租户Multi-tenancy实战指南基于 X-Scope-OrgID 的租户隔离配置与源码剖析Grafana Tempo 多租户Multi tenancy实战指南基于 X Scope OrgID 的租户隔离配置与源码剖析 Tempo 是一个开箱即用后端可观测性链路追踪Thanos 多租户实战基于外部标签与分层 Querier 的租户隔离方案Thanos 多租户实战基于外部标签与分层 Querier 的租户隔离方案 本文围绕 docs/operating/multi tenancy.md http可观测性云原生时序数据库运维上一篇UniExtract2500格式一键提取你的万能文件解压神器下一篇GSD-2 编码 Agent 推倒重来决策指南四大信号、重新评估协议与低成本重写的架构支撑创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考