Skip to main content

Free Tokens for Everyone | Runbook Live, Nov 19

Register
close

Rate Limiting in Linkerd: Local and Global Patterns for Kubernetes

Linkerd Production Readiness Pre-Launch Checklist

Download Checklist

Oct 2026

TL;DR

  • Linkerd’s HTTPLocalRateLimitPolicy sets identity-aware limits per proxy. A shared quota requires an external service.
  • Istio documents a global pattern using an external rate-limit service and Redis. Cilium exposes Envoy configuration but has no dedicated rate-limit policy.
  • Best for per-tenant SaaS quotas: Use Linkerd’s ServiceAccount limits when each proxy can enforce its own quota.
  • Best for abuse protection: Use local limits to reject bursts, and add a shared service when you need one ceiling across replicas.
  • Best for API gateway integration: Put shared quota enforcement at the gateway when requests need a common counter.

Rate limiting as a zero-trust control

Zero-trust authorization decides which workloads may call a service. Rate limiting bounds how quickly an authorized workload may send requests. A compromised client can still carry valid credentials, and a bad retry loop can overwhelm an internal API without violating its access policy.

Linkerd authenticates meshed workloads using mutual TLS identities derived from Kubernetes ServiceAccounts. If you give a client its own ServiceAccount, you can apply a limit to that verified identity. Pod IPs change when Kubernetes reschedules workloads, and an ingress IP may represent several clients, so IP-based limits can't reliably identify the workload making a request.

For a multi-tenant service, distinct ServiceAccounts let you limit each tenant-facing client separately. A noisy tenant's batch job then hits its own limit instead of consuming a shared client allowance. Keep deny-by-default authorization in place to reject callers without permission, and use rate limits to bound the traffic permitted callers send.

How Linkerd enforces rate limits today

Linkerd enforces HTTP rate limits in each destination pod’s proxy. A Server selects the pods and port, and an HTTPLocalRateLimitPolicy points to that Server. The example below follows Linkerd’s rate-limiting configuration and gives authenticated clients a default limit of 4 requests per second.

apiVersion: policy.linkerd.io/v1beta3
kind: Server
metadata:
  name: web-http
  namespace: emojivoto
spec:
  podSelector:
    matchLabels:
      app: web-svc
  port: http
  proxyProtocol: HTTP/1
  accessPolicy: all-authenticated
---
apiVersion: policy.linkerd.io/v1alpha1
kind: HTTPLocalRateLimitPolicy
metadata:
  name: web-http
  namespace: emojivoto
spec:
  targetRef:
    group: policy.linkerd.io
    kind: Server
    name: web-http
  identity:
    requestsPerSecond: 4
  overrides:
    - requestsPerSecond: 6
      clientRefs:
        - kind: ServiceAccount
          namespace: emojivoto
          name: default

The identity limit applies per client workload identity. Here, clients using the default ServiceAccount in emojivoto get 6 requests per second instead of 4. You can also configure total.requestsPerSecond to cap all requests that a proxy sees, regardless of client identity. When a client exceeds an applicable limit, the destination proxy returns HTTP 429.

Each proxy keeps its own counters. If the workload has several replicas, their proxies enforce the policy independently, with no shared counter or cross-proxy coordination. The example’s all-authenticated access policy also requires a meshed client identity. Check the Server’s access policy separately if your workload must accept unmeshed traffic.

Identity-based limits: Linkerd's real differentiator

Linkerd can set request limits by the client’s mTLS workload identity, which comes from its Kubernetes ServiceAccount. You can set a default per-identity limit and give named ServiceAccounts different limits through HTTPLocalRateLimitPolicy overrides. The proxy verifies the caller’s identity, so the policy doesn’t have to infer it from a changing pod IP or trust a client-supplied header.

Best for per-tenant SaaS quotas. If each tenant runs under a separate ServiceAccount, you can assign each one a different local limit without changing application code. A ServiceAccount identifies a workload, though, not an end user. When tenants share a caller workload, Linkerd sees one identity and can’t give those tenants separate quotas on that basis.

Istio and Cilium configurations can use Envoy descriptors keyed to headers or JWT claims for finer tenant distinctions. Those values need a trusted source and validation. Linkerd’s ServiceAccount matching gives you a built-in identity primitive when your workload layout already separates tenants.

Local versus global: the honest pattern for scaling beyond one proxy

Linkerd’s local rate limit runs independently in each destination proxy. If you set a limit of 10 requests per second for a client identity and run 4 replicas, each proxy can admit 10 requests per second for that identity. Traffic spread across all 4 replicas can approach 40 requests per second. Adding replicas changes the effective ceiling.

For a global quota, route every request covered by that quota through a gateway that checks a shared counter before forwarding it. A rate-limit service backed by Redis can track requests under an authenticated tenant ID and tell the gateway whether to admit the next request. You can keep Linkerd’s local limits on destination workloads for per-proxy protection. Requests that bypass the gateway also bypass its global quota.

Internal workload traffic needs its own path to that shared check, such as application middleware or an enforcement proxy. You’ll also need to decide whether requests pass or fail when the rate-limit service is unavailable. Linkerd’s HTTPLocalRateLimitPolicy doesn’t make the external call for you. Istio’s Envoy-based configuration has a more established path for calling an external rate-limit service, though you still have to operate the service and counter store.

Rate limiting in Linkerd vs. Istio vs. Cilium

Each mesh has a path to local HTTP rate limiting. The main differences are how you configure it and how much work a shared quota requires.

Capability Linkerd Istio Cilium
Local rate limiting HTTPLocalRateLimitPolicy enforces limits at each server-side proxy. Envoy’s local filter enforces limits per proxy. Envoy can enforce local limits through raw configuration.
Global rate limiting Requires an external quota service in front of or alongside the mesh. Documented pattern uses an external rate-limit service backed by Redis. Requires custom wiring to an external service.
Identity awareness Sets per-client limits using mTLS workload identity, with ServiceAccount overrides. Can build quota keys from request attributes such as JWT claims or headers. Depends on the attributes you configure in Envoy.
Configuration Dedicated HTTPLocalRateLimitPolicy CRD targets a Server. EnvoyFilter configures local and global filters. CiliumEnvoyConfig exposes raw Envoy configuration.
Operational overhead Low for local limits. A shared quota adds external infrastructure. Local limits require filter configuration. Global limits also require a service, Redis, and quota rules. Raw filter configuration requires more hands-on work. A shared quota adds external infrastructure.

Istio has the most developed global rate-limiting path of the 3, though you still have to operate Redis and a separate service. Linkerd gives you a simpler API for identity-aware local limits. Cilium’s L7 rate-limiting path is the least developed here, with no dedicated rate-limit API or comparably documented global pattern.

Best-for callouts by use case

  • Per-tenant SaaS quotas. Use Linkerd’s identity-based local limits when each tenant’s traffic has a distinct ServiceAccount and a per-replica ceiling works for you. A shared ServiceAccount can’t give you separate tenant limits.
  • Abuse and DDoS protection. Set local limits on a meshed ingress workload to cap the requests its proxy passes to the application. Put upstream protection in front of the cluster for large traffic floods. If you need 1 request budget across ingress replicas, add an external rate-limit service with a shared counter.
  • API gateway integration. Keep Linkerd’s local limits on meshed workloads for an additional service-level guard. Enforce customer-wide quotas at the gateway through an external rate-limit service when requests can reach multiple backend replicas or clusters.

Getting started

Apply the Server and HTTPLocalRateLimitPolicy example to a meshed workload you can safely test. Send requests from a designated ServiceAccount above its configured rate, check for HTTP 429 responses, and repeat the test after adding a server replica.

If you need a quota shared across replicas or clusters, plan for an external rate-limit service with a shared counter. Buoyant Enterprise for Linkerd provides operational tooling and FIPS-validated builds for regulated environments, but it doesn’t turn local limits into a global quota.

FAQs

Does Linkerd support global rate limiting natively?

No. Linkerd’s HTTPLocalRateLimitPolicy enforces limits independently at each server-side proxy. If you need 1 quota shared across replicas, put an external rate-limit service with shared counters in front of, or alongside, the mesh.

What happens when a request exceeds the limit?

The Linkerd proxy returns HTTP 429. Each proxy makes that decision using its own local limit, so adding server replicas can raise the number of requests your service accepts overall.

Can I set a limit for a specific tenant or ServiceAccount?

You can give a ServiceAccount its own requests-per-second limit through a policy override. For a tenant-specific limit based on workload identity, each tenant needs a distinct ServiceAccount. If tenants share one ServiceAccount, that identity can’t separate their traffic.

How does configuration compare with Istio and Cilium?

Linkerd uses a dedicated policy resource for local limits. Istio configures Envoy filters for local limits and documents an external rate-limit service for global limits, typically backed by Redis. Cilium can use raw Envoy configuration through CiliumEnvoyConfig, but it lacks a dedicated rate-limit policy resource.