This is documentation for the next version of Grafana Loki documentation. For the latest stable release, go to the latest version.
Use label-based access control with Loki
Note
This feature is generally available from v4.0. For the latest releases, refer to the Release notes.
Label-based access control (LBAC) restricts the logs a tenant can query to those that match one or more Prometheus label selectors. You associate a set of selectors with a tenant, and queries from that tenant only return data from log streams that match at least one of the selectors. Because selectors can be combined into “OR” groups, where each group is a list of things joined by “AND” you can express any required policy. For example, (A and B and C) or (D and E) or (F).
LBAC builds on Loki’s multi-tenancy: policies are scoped per tenant, so you must run Loki in multi-tenant mode. For more information, refer to the multi-tenancy documentation.
Why use LBAC
LBAC lets you share a single Loki tenant across multiple teams or users while still limiting what each of them can see. Common reasons to use LBAC include:
- Restrict a tenant to a subset of its own data. For example, one team should only see logs from its own Kubernetes namespace, even though the tenant contains logs from many namespaces.
- Exclude sensitive log streams from some users. For example, you can hide streams labeled
secret="true"from most users, while still letting a smaller group of users query them. - Enforce access boundaries per tenant without creating a separate Loki tenant for every team. Running one tenant per team adds operational overhead. LBAC lets you keep a single tenant and instead scope access with label policies.
Security model
Loki does not include its own authentication layer. Both the tenant (X-Scope-OrgID) and the label policy (X-Prom-Label-Policy) are read from trusted HTTP headers on incoming requests.
Warning
Never expose the Loki API directly to clients. A client that can reach Loki can set the
X-Scope-OrgIDandX-Prom-Label-Policyheaders itself and bypass label-based access control entirely. You must run an authentication gateway in front of Loki that authenticates the request, sets the tenant, and attaches the correct label policy.
The gateway is responsible for stripping any user supplied X-Scope-OrgID and X-Prom-Label-Policy and replacing them with values it derives from the authenticated identity. One open-source gateway that sets these headers is db-auth-gateway. For general guidance on putting an authenticating reverse proxy in front of Loki, refer to the
authentication documentation.
How LBAC works
At a high level, your gateway attaches a label policy to each request, and Loki carries that policy through the read path so that every component filters data to match it.
- Your authentication gateway authenticates the request and sets the
X-Prom-Label-PolicyHTTP header. Each value in the header has the form<TENANT>:<URL-ENCODED SELECTOR>, for exampletenant1:%7Benv%3D%22dev%22%7Dfor the selector{env="dev"}. - An HTTP middleware inside Loki parses this header on every incoming request and stores the resulting policies in the request context.
- As the request moves between Loki’s internal components, for example from the query frontend to the queriers, ingesters, and index gateway, the policies travel with it as gRPC metadata. This means the same policy applies no matter which component ultimately reads the data.
- Loki enforces the policy at several points in the read path:
- It filters chunks and streams while running the query, for both the original query engine and the newer query engine.
- It filters the results of label-values queries against the store and the ingesters.
- In the query frontend, it filters the response of volume queries, and it rewrites aggregated-metrics queries so they only return permitted data.
The following diagram shows the request flow for a query from a client through the gateway and into Loki:
sequenceDiagram
participant Client
participant Gateway as Authentication gateway
participant QF as Query frontend
participant Q as Querier / Ingester
Client->>Gateway: Query request
Gateway->>Gateway: Authenticate request
Gateway->>QF: Query request + X-Scope-OrgID + X-Prom-Label-Policy
QF->>Q: Query request (policy propagated over gRPC)
Q->>Q: Filter streams and chunks by policy
Q->>QF: Filtered results
QF->>Gateway: Filtered response
Gateway->>Client: Filtered responseLBAC and ingestion
Label-based access control is not enforced on write (push) requests. It only restricts what a tenant can read. A tenant that is allowed to write can push log lines with any labels, regardless of the label policy that applies to its queries.
LBAC and alertmanager and ruler
Label policies are not enforced by the Alertmanager or ruler HTTP endpoints. This means that the requests they serve contain everything for a particular tenant without applying label-based access control. For example, listing all rule groups in the ruler returns all rule groups for the tenant, even if a label selector in the policy would exclude some of the labels on the rules. However it does apply when you query the metrics those components generate, such as ALERTS.
LBAC and querying
LogQL queries use the following format:
{ log stream selector } | log pipelineLBAC only applies to the log stream selector portion of a query, that is the part of the query that comes before the pipe (|). It does not apply to label filter expressions or other parts of the log pipeline.
For more information, refer to the Log stream selector and Label filter expression sections in the documentation about Log queries.
Enable label-based access control
LBAC requires multi-tenant mode, which is the default. Ensure authentication is enabled so that requests carry a tenant:
auth_enabled: trueThen enable LBAC:
lbac:
enabled: trueThis can also be set with the -lbac.enabled command-line flag. When enabled, Loki parses the X-Prom-Label-Policy header on incoming requests and enforces the policies it contains.
Configuration reference
LBAC currently has a single configuration setting. There are no per-tenant settings in Loki’s YAML configuration: policies for each tenant arrive dynamically in the X-Prom-Label-Policy header, set by your authentication gateway, not through Loki’s configuration file.
lbac:
# Enables label based access control through the X-Prom-Label-Policy header.
[enabled: <boolean> | default = false]Setting up a label policy
A label policy is conveyed to Loki in the X-Prom-Label-Policy request header. This header is set by your authentication gateway, not by clients. Each header value has the form:
<TENANT>:<URL-ENCODED SELECTOR>The selector is a standard label matcher set such as {env="dev"}, URL-encoded so that it is safe to carry in a header. For example, the policy {env="dev"} for tenant tenant1 is encoded as:
X-Prom-Label-Policy: tenant1:%7Benv%3D%22dev%22%7DTo associate multiple selectors with a tenant, set multiple values. You can either repeat the header or separate the encoded policies with a comma (,). The selectors are combined with OR into groups where each group is a list of things joined by AND: a stream is returned if any of the streams matches any one of the selector groups. For example, a policy written {a='true', b='true, c='true'} OR {x='true', y='true'} reads as {a='true' AND b='true'AND c='true'} OR {x='true'AND y='true'}.
Exclude a label
One common use case for an LBAC policy is to exclude logs that have a specific label. For example, to exclude all log lines with the label secret=true, use a selector with secret!="true":
{secret!="true"}Use multiple selectors
To allow access to both the production and development environments while excluding logs with the label secret=true in the production environment, use multiple selectors:
{secret!="true", env="prod"}
{env="dev"}These selectors enforce the policy as follows:
{secret!="true", env="prod"}matches and returns log lines from the production environment that do not have thesecret: truelabel.{env="dev"}matches and returns log lines from the development environment, even if they have thesecret: truelabel.
Real-world examples
The following examples use labels that Loki assigns by default when logs are collected through OpenTelemetry, such as service_name, k8s_namespace_name, and deployment_environment_name. For the full list of default OpenTelemetry-derived labels, refer to
Default labels. Each example shows the LogQL selector and the resulting X-Prom-Label-Policy header value that your gateway would set, following the same format as Setting up a label policy.
Restrict a team to one namespace
Scope a tenant so that it can only see logs from the checkout Kubernetes namespace. This is useful when a platform team gives a single application team access to a shared tenant, but the application team should only see its own namespace.
Selector:
{k8s_namespace_name="checkout"}Header:
X-Prom-Label-Policy: team-checkout:%7Bk8s_namespace_name%3D%22checkout%22%7DRestrict by environment
Give separate policies to a production support team and a staging support team that share the same tenant.
Production team selector:
{deployment_environment_name="production"}Header:
X-Prom-Label-Policy: team-prod:%7Bdeployment_environment_name%3D%22production%22%7DStaging team selector:
{deployment_environment_name="staging"}Header:
X-Prom-Label-Policy: team-staging:%7Bdeployment_environment_name%3D%22staging%22%7DRestrict by service, with an exclusion
Combine a service restriction with an exclusion, similar to Use multiple selectors, but scoped to a specific service.
Allow access to the payments-api service, but exclude any of its streams labeled secret="true", and separately allow access to every other service:
{service_name="payments-api", secret!="true"}
{service_name!="payments-api"}Header:
X-Prom-Label-Policy: team-payments:%7Bservice_name%3D%22payments-api%22%2C%20secret%21%3D%22true%22%7D,team-payments:%7Bservice_name%21%3D%22payments-api%22%7DRestrict by region for a distributed team
Scope a regional on-call team so that it only sees logs from its own region.
Selector:
{cloud_region="us-west-1"}Header:
X-Prom-Label-Policy: team-uswest:%7Bcloud_region%3D%22us-west-1%22%7DCombine selectors across multiple namespaces
Grant a tenant access to logs from two Kubernetes namespaces by giving it two separate selectors for the same tenant:
{k8s_namespace_name="frontend"}
{k8s_namespace_name="checkout"}Because a tenant’s selectors are combined with OR, a stream is returned if it matches either one: the frontend namespace or the checkout namespace.
Header:
X-Prom-Label-Policy: team-multi:%7Bk8s_namespace_name%3D%22frontend%22%7D,team-multi:%7Bk8s_namespace_name%3D%22checkout%22%7D

