news 2026/9/12 7:02:41

Loki 标签级访问控制(LBAC)实战指南:基于 X-Prom-Label-Policy 的多租户日志查询隔离

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Loki 标签级访问控制(LBAC)实战指南:基于 X-Prom-Label-Policy 的多租户日志查询隔离

Loki 标签级访问控制(LBAC)实战指南:基于 X-Prom-Label-Policy 的多租户日志查询隔离

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

导读

标签级访问控制(Label-Based Access Control,LBAC)是 Loki(v3.7.3 起提供,实验特性)提供的一种细粒度查询隔离机制:它允许运维方为每个租户绑定一组 Prometheus 标签选择器(label selector),使该租户发起的查询只能命中与任一选择器匹配的日志流,从而实现"租户内再分权"的数据可见性边界。本文将基于 lbac.md 官方文档,结合 pkg/labelaccess 与 pkg/loki/labelaccess.go 的源码实现,完整讲解 LBAC 的安全模型、启用方式、标签策略头格式、多选择器组合、作用范围与边界限制,并给出可直接落地的网关侧配置示例。

什么是标签级访问控制(LBAC)

LBAC 的核心思想非常直接:把"租户能看哪些数据"从"整个租户的数据"细化为"满足若干标签选择器之一的数据"

  • 每个策略由一组标准的 Prometheus 标签选择器构成;
  • 一个租户可以关联多个选择器,选择器之间按OR(析取)组合;
  • 查询执行时,只有至少匹配其中一个选择器的日志流才会被返回,其余日志流在查询阶段即被过滤掉;
  • 由于选择器之间是 OR 关系,整个策略体系等价于析取范式(Disjunctive Normal Form, DNF)。源码中 pkg/labelaccess/types/label.go 的LabelPolicy结构体正是用一个Selector []*LabelMatcher表达"同一选择器内多个匹配器 AND",而LabelPolicySetmap[string][]*types.LabelPolicy,见 pkg/labelaccess/propagation.go)则通过"每个租户挂多个 Policy"表达"选择器之间 OR"。

从源码结构可以推断,这套 DNF 语义最终落在过滤器的ShouldFilter方法上(pkg/labelaccess/request_chunk_filterer.go):

  1. 遍历该租户的每个LabelPolicy
  2. 在单个 Policy 内,所有LabelMatcher必须全部匹配(AND);
  3. 只要任意一个Policy 匹配,就返回false(不过滤该 chunk/stream,即放行);
  4. 全部 Policy 都不匹配,才返回true(过滤掉)。

注意:LBAC 建立在 Loki 多租户机制之上,策略按租户隔离,因此必须运行在多租户模式下。

安全模型:信任边界与网关前置

Loki 本身不包含认证层。无论是租户标识还是标签策略,都来源于 HTTP 请求头:

请求头含义
X-Scope-OrgID租户(tenant / org)标识,Loki 多租户的标准头
X-Prom-Label-Policy标签策略,格式为<tenant>:<URL-encoded selector>

官方文档对此给出了一条硬性警告

绝不直接将 Loki API 暴露给客户端。任何能直接触达 Loki 的客户端都可以自行伪造X-Scope-OrgIDX-Prom-Label-Policy头,从而完全绕过标签级访问控制。必须在 Loki 前方部署认证网关,由网关完成请求认证、设置租户并附加正确的标签策略。

因此推荐架构为:

Client ──► Auth Gateway ──► Loki │ ├─ 1. 认证客户端身份 ├─ 2. 剥离用户提交的 X-Scope-OrgID / X-Prom-Label-Policy └─ 3. 依据认证后的身份,写入正确的 X-Scope-OrgID 与 X-Prom-Label-Policy

网关必须负责剥离用户自带的两个头,并以认证身份推导出的值替换之。官方文档提及的开源网关参考实现为 grafana/db-auth-gateway;更通用的认证反向代理部署指引可参考仓库内 authentication 文档(若存在)。

这一信任边界在源码中同样成立:Loki 侧只是"信任"X-Prom-Label-Policy头并解析执行,见 pkg/labelaccess/middleware.go 中NewLabelAccessMiddleware的注释——"parses the X-Prom-Label-Policy header and injects the parsed label selectors into the request context"。

启用标签级访问控制

1. 确保多租户模式

多租户模式默认开启,显式配置为:

auth_enabled: true

只有开启auth_enabled,请求才会携带租户标识,LBAC 才有"按租户"锚定策略的基础。

2. 开启 LBAC

lbac: enabled: true

对应配置结构体见 pkg/labelaccess/config.go,其中Enabled字段被标记为category:"experimental",默认false。也可以通过命令行参数启用:

-lbac.enabled=true

该 flag 的官方描述为"Enables label based access control through the X-Prom-Label-Policy header"

3. 启用后发生什么

开启后,Loki 会在请求链路上解析X-Prom-Label-Policy头并强制执行其中的策略。从 pkg/loki/labelaccess.go 的setupLBAC()可以看到,LBAC 是一个贯穿几乎全部查询路径的横切特性,它注册了十余个内部模块并注入依赖:

  • AuthMiddleware:合并labelaccess.NewLabelAccessMiddleware到 HTTP 认证中间件链,负责解析策略头并注入请求上下文(pkg/loki/labelaccess.go);
  • LabelAccessStoreWrapper / LabelAccessIngesterWrapper / Filterers:分别包装 Store、Ingester,并为 Ingester 配置 ChunkFilterer,实现存储与内存侧过滤;
  • LabelAccessV2Engine:为 V2 查询引擎设置RequestStreamFilterer,实现数据对象上的流级过滤(pkg/loki/labelaccess.go,对应实现 pkg/labelaccess/request_stream_filterer.go);
  • LabelAccessInterceptors:为 Ingester / IndexGateway 的 gRPC 服务端与客户端追加 LBAC 拦截器,保证策略在 gRPC 链路上不丢失;
  • LabelAccessTripperware / LabelAccessUserIDTransformer:处理查询前端中间件与缓存键的用户维度变换。

对应测试 pkg/loki/lbac_setup_test.go 验证了:开启 LBAC 时这些模块全部注册且依赖无环(TestSetupLBACEnabled),关闭时这些模块全部不注册(TestSetupLBACDisabled),并确保 LBAC 中间件只安装一次(TestLBACAuthMiddlewareRegisteredOnce)。

设置标签策略:X-Prom-Label-Policy 头的格式

标签策略通过X-Prom-Label-Policy请求头传给 Loki。该头由认证网关设置,而不是客户端

单个策略的格式

每个头的值形如:

<tenant>:<URL-encoded selector>

其中 selector 是一组标准标签匹配器,例如{env="dev"}。因为花括号、引号等字符不适合直接出现在 HTTP 头中,需要做URL 编码。官方示例:租户tenant1的策略{env="dev"}编码为:

X-Prom-Label-Policy: tenant1:%7Benv%3D%22dev%22%7D

解码后即为tenant1:{env="dev"}

一个租户关联多个选择器

要把多个选择器关联到同一租户,有两种等价写法:

方式一:重复头(每个值一条):

X-Prom-Label-Policy: tenant1:%7Benv%3D%22prod%22%7D X-Prom-Label-Policy: tenant1:%7Benv%3D%22dev%22%7D

方式二:逗号分隔(合并到同一个头值中):

X-Prom-Label-Policy: tenant1:%7Benv%3D%22prod%22%7D,tenant1:%7Benv%3D%22dev%22%7D

两种写法的解析路径在源码中都能找到依据:gRPC 侧解析函数ExtractLabelMatchersGRPC(pkg/labelaccess/codec.go)会对头值按逗号strings.Split(headerValue, ",")拆分后逐条解析;HTTP 侧同样按此语义合并成LabelPolicySet。多个选择器之间按OR组合——一个日志流只要匹配其中任意一个选择器就会被返回。

实战示例:排除带敏感标签的日志

最常见的 LBAC 需求是"排除带有某标签的日志"。例如排除所有带secret=true标签的日志行,使用不等匹配器:

{secret!="true"}

对应网关头:

X-Prom-Label-Policy: tenant1:%7Bsecret%21%3D%22true%22%7D

!编码为%21=编码为%3D"编码为%22

实战示例:多选择器组合策略

假设某租户需要同时满足:

  • 能访问生产环境(env="prod")日志,但生产环境中排除secret=true的日志;
  • 能访问开发环境(env="dev")日志,开发环境不做敏感标签排除。

则策略应配置两个选择器:

{secret!="true", env="prod"} {env="dev"}

该策略的执行语义如下:

选择器匹配行为
{secret!="true", env="prod"}返回生产环境中没有secret: true标签的日志行(选择器内多个匹配器是 AND 关系)
{env="dev"}返回开发环境的日志行,即使它们带有secret: true标签

这正是 DNF 的表达力所在:两个选择器 OR,第一个选择器内部 AND 两个条件,从而在一个策略内同时表达"排除 + 放行"的差异化规则。

对应到源码,每个选择器内部是 AND 逻辑(见上文ShouldFilter的单 Policy 全匹配判断),而不同选择器之间是 OR(任一匹配即放行)。测试文件 pkg/labelaccess/request_chunk_filterer_test.go 与 pkg/labelaccess/middleware_test.go 覆盖了这类组合场景。

标签策略的作用范围

需要特别明确 LBAC 的边界

标签策略只作用于查询中的日志流选择器(Log stream selector)不作用于标签过滤表达式(Label filter expression)

举例来说,查询:

{env="prod", secret!="true"} |= "error"

中,LBAC 策略只会叠加/约束{env="prod", secret!="true"}这部分流选择器;|= "error"这类过滤表达式(以及解析后的 label filter)不在 LBAC 的管辖范围内。相关概念可参考仓库内日志查询文档中关于 Log stream selector 与 Label filter expression 的说明(以仓库实际文档为准)。

源码层面,Loki 会先解析查询的流选择器,再与策略选择器做合并/交集判断:例如 volume 查询场景下,中间件会把策略匹配器 AND 进查询的流选择器中,使索引层只返回租户被允许看到的流(pkg/labelaccess/middleware.go 的modifyVolumeQuery);多策略时则跳过查询改写、改由响应级过滤保证 OR 语义。

写入路径不受限:LBAC 只约束查询

LBAC 不作用于写入(push)请求。只要某租户被允许写入,它就可以推送携带任意标签的日志行,无论其查询策略如何。

这是"读时过滤"模型的自然结果:LBAC 在查询链路上做过滤,而不是在写入时对标签做校验或改写。如果你需要限制租户能写入的标签,需要另行配置写入侧校验(如租户限制、标签验证等机制),LBAC 本身不提供该能力。

已知边界:Alertmanager 与 ruler 不受 LBAC 约束

标签策略不会被 Alertmanager 和 ruler 强制执行。这意味着:

  • ruler 服务处理的请求包含该租户的全部内容,不应用 LBAC 过滤;
  • 例如列出 ruler 中某租户的全部规则组(rule groups)时,即使策略中的某个标签选择器会排除部分规则上的标签,这些规则仍会全部返回。

这一点对依赖 ruler 告警规则的部署方尤为重要:不要把敏感数据可见性的最终防线寄托在 ruler/Alertmanager 上,需要为告警与规则评估链路单独设计访问控制。

从模块依赖看,LBAC 的模块注入集中在Querier / QueryFrontend / QueryEngine / Ingester / IndexGateway / Server等查询相关链路(pkg/loki/labelaccess.go),ruler/Alertmanager 组件并不在 LBAC 的注入清单中,与文档描述的"不受约束"一致。

端到端落地检查清单

  1. 部署形态:Loki 必须开启auth_enabled: true(默认即开启),运行在多租户模式;
  2. 功能开关:配置lbac.enabled: true-lbac.enabled=true
  3. 网关前置:任何客户端不得直连 Loki API;由认证网关剥离并重写X-Scope-OrgIDX-Prom-Label-Policy
  4. 策略编码:头值格式<tenant>:<URL-encoded selector>;多选择器用重复头或逗号分隔;选择器间 OR、选择器内 AND;
  5. 查询验证:用logcli或 Grafana 以目标租户身份发起查询,确认只返回策略允许的日志流;对 volume 等索引类查询同样验证;
  6. 边界确认:明确写入请求、ruler、Alertmanager 不受 LBAC 约束,按需为这些链路补充其他控制手段。

相关资源

  • 官方文档原文:Use label-based access control with Loki
  • LBAC 配置结构体与命令行参数:pkg/labelaccess/config.go
  • LBAC 模块装配与依赖注入:pkg/loki/labelaccess.go、pkg/loki/lbac_setup_test.go
  • 策略头解析与传播(X-Prom-Label-Policy、URL 解码、FNV 哈希缓存键):pkg/labelaccess/propagation.go、pkg/labelaccess/codec.go
  • HTTP 中间件(解析、注入、volume 查询改写):pkg/labelaccess/middleware.go
  • 过滤实现(V1 chunk 级 / V2 stream 级):pkg/labelaccess/request_chunk_filterer.go、pkg/labelaccess/request_stream_filterer.go
  • 策略与匹配器的 protobuf 风格类型定义:pkg/labelaccess/types/label.go
  • 多租户文档:multi-tenancy(以仓库实际路径为准)

【免费下载链接】lokiLike Prometheus, but for logs.项目地址: https://gitcode.com/GitHub_Trending/lok/loki

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/12 7:00:51

ASP.NET Core仿Steam商城开发:从MVC到订单防超卖实战

简介&#xff1a;面向ASP.NET初学者的游戏商城网页项目&#xff0c;以仿Steam界面为切入点&#xff0c;完整串联用户认证、游戏数据展示、购物车订单与后台管理流程。项目基于ASP.NET MVC架构&#xff0c;包含登录注册、热门游戏/全部游戏列表、游戏详情、购物车结算和管理员维…

作者头像 李华
网站建设 2026/9/12 6:53:38

Backstage Scaffolder 如何为自定义 Action 启用并测试 dry run?

Backstage Scaffolder 如何为自定义 Action 启用并测试 dry run&#xff1f; 【免费下载链接】backstage Backstage is an open framework for building developer portals 项目地址: https://gitcode.com/GitHub_Trending/ba/backstage 如果你写了一个自定义 Scaffolde…

作者头像 李华
网站建设 2026/9/12 6:53:09

企业文件管理软件选型指南与10款产品深度评测

1. 企业文件管理现状与核心痛点作为在IT行业摸爬滚打十多年的老鸟&#xff0c;我见证过太多企业因为文件管理混乱导致的"灾难现场"——市场部把合同存进财务部的共享文件夹、技术部门的设计图纸被误删后无法恢复、异地团队协作时版本混乱到需要人工比对...这些场景每…

作者头像 李华