Skip to content

Architecture

Overview

Linkerd is an ultralight, security-first service mesh for Kubernetes. Its data plane uses linkerd2-proxy, a Rust-based micro-proxy designed specifically for the service mesh use case. The control plane runs as a small set of Kubernetes deployments. Linkerd prioritizes simplicity, minimal resource footprint, and automatic mTLS by default.

See also: index, service-mesh/linkerd/explanation, service-mesh/linkerd/how-to-guides

1. Control Plane Components

graph TB
    subgraph "Control Plane (linkerd namespace)"
        DEST["destination<br/>Service discovery & routing"]
        IDENTITY["identity<br/>Certificate authority (mTLS)"]
        INJECTOR["proxy-injector<br/>Mutating admission webhook"]
        HEARTBEAT["heartbeat<br/>Health & usage reporting"]
        WEB["web<br/>Dashboard UI"]
    end

    subgraph "Configuration"
        K8s["Kubernetes API"]
        SP["Service Profiles<br/>(linkerd.io/v1alpha2)"]
    end

    subgraph "Data Plane"
        PROXY_A["linkerd2-proxy<br/>(Rust, per-pod sidecar)"]
        PROXY_B["linkerd2-proxy<br/>(Rust, per-pod sidecar)"]
    end

    K8s -->|watches Services, Endpoints| DEST
    SP -->|retries, timeouts, routing| DEST
    DEST -->|service discovery info| PROXY_A
    DEST -->|service discovery info| PROXY_B
    IDENTITY -->|issues TLS certs| PROXY_A
    IDENTITY -->|issues TLS certs| PROXY_B
    K8s -->|pod creation events| INJECTOR
    INJECTOR -->|injects proxy + init containers| PROXY_A
    INJECTOR -->|injects proxy + init containers| PROXY_B
    PROXY_A <-->|automatic mTLS| PROXY_B

destination Service

The destination component is the equivalent of a service discovery and routing engine in Linkerd:

  • Watches Kubernetes Services, Endpoints, and ServiceProfile resources
  • Provides dynamic service discovery information to linkerd2-proxy instances via gRPC
  • Supplies retry budgets, timeouts, and load balancing configuration from Service Profiles
  • Handles traffic splitting for canary and blue/green deployments
  • Returns endpoint metadata including zone information for topology-aware routing

identity Controller

The identity component is the built-in certificate authority of Linkerd:

  • Issues TLS certificates to every linkerd2-proxy instance using a trust anchor chain
  • Certificate identity is derived from the Kubernetes Service Account of the pod
  • Identity format: <service-account>.<namespace>.serviceaccount.identity.linkerd.cluster.local
  • Manages automatic certificate rotation with a configurable lifetime (default 24 hours)
  • Root of trust is the trust anchor certificate (ECDSA, provisioned during install)

proxy-injector

The proxy-injector is a Kubernetes Mutating Admission Webhook that automatically injects the linkerd2-proxy sidecar into pods:

  • Triggered by the linkerd.io/inject: enabled annotation on namespaces or pods
  • Adds the linkerd2-proxy container and a linkerd-init container (iptables setup) to the pod spec
  • Configures proxy startup parameters: destination service address, identity service address, proxy metrics port
  • Supports annotation-based configuration for proxy resources (CPU, memory limits) and log levels

heartbeat

A CronJob-like component that periodically reports cluster health and anonymized usage data back to Buoyant (can be disabled). It also validates that the control plane is functioning correctly.

web (Dashboard)

Provides the Linkerd dashboard UI for visualizing service mesh health, traffic metrics, and topology. Optional -- not required for production data plane operation.

2. Data Plane -- linkerd2-proxy

sequenceDiagram
    participant K8s as Kubernetes API
    participant Injector as proxy-injector
    participant Pod as Application Pod
    participant Proxy as linkerd2-proxy
    participant App as Application Container
    participant Dest as destination service
    participant Identity as identity controller

    K8s->>Injector: Pod creation event (inject=enabled)
    Injector->>Pod: Modified Pod spec with linkerd2-proxy + linkerd-init
    Pod->>Proxy: linkerd2-proxy starts
    Proxy->>Identity: Request TLS certificate (CSR)
    Identity-->>Proxy: Issue certificate (SPIFFE-style identity)
    Proxy->>Dest: Connect for service discovery
    Dest-->>Proxy: Endpoints, routing, retry configuration
    App->>Proxy: Outbound traffic (iptables redirect)
    Proxy->>Proxy: Apply routing, load balancing, mTLS
    Proxy->>Proxy: Forward to destination proxy via mTLS

linkerd2-proxy Design

The linkerd2-proxy is purpose-built for Linkerd and written in Rust:

  • Protocol detection -- automatically detects HTTP/1, HTTP/2, gRPC, and TCP traffic
  • L7 routing -- HTTP routing, retries, timeouts, and traffic splitting when Service Profiles are defined
  • L4 proxying -- transparent TCP proxying for non-HTTP protocols
  • Load balancing -- EWMA (Exponentially Weighted Moving Average) load balancing using latency estimates from the destination service
  • mTLS -- automatically encrypts all traffic between meshed pods using certificates from the identity controller
  • Telemetry -- reports request-level metrics (latency, success rate, throughput) to the control plane
  • Resource footprint -- approximately 10 MB RAM per proxy instance

Init Container (linkerd-init)

The linkerd-init container runs before the application starts and configures iptables rules to redirect all inbound and outbound TCP traffic through the linkerd2-proxy. Alternatively, Linkerd provides a CNI plugin that does this redirection at the network level. This removes the need for privileged init containers.

3. Service Profiles

Service Profiles are Linkerd CRDs that define per-service routing policies:

apiVersion: linkerd.io/v1alpha2
kind: ServiceProfile
metadata:
  name: my-service.my-namespace.svc.cluster.local
  namespace: my-namespace
spec:
  routes:
  - name: GET /api/users
    condition:
      method: GET
      pathRegex: /api/users
    responseClasses:
    - condition:
        status:
          min: 500
          max: 599
      isFailure: true
  retryBudget:
    retryRatio: 0.2
    minRetriesPerSecond: 10
    ttl: 10s

Service Profiles enable:

  • Retries with configurable budgets (retry ratio, min retries per second, TTL)
  • Timeouts per route
  • Traffic splitting for progressive delivery (canary, blue/green)
  • Response classification for success/failure rate calculation

4. Multi-Cluster Architecture

Linkerd supports multi-cluster communication via gateway proxies:

  • A linkerd-gateway deployment runs in each cluster
  • A mirror service that watches remote cluster endpoints handles remote service discovery
  • Traffic between clusters is automatically encrypted with mTLS
  • Applications need no special configuration in their code

5. Supported Features

Feature Status
HTTP, HTTP/2, gRPC proxying Stable
TCP proxying with protocol detection Stable
Automatic mTLS Stable (on by default)
Retries and timeouts Stable (via Service Profiles)
Traffic splitting (canary) Stable
Load balancing (EWMA) Stable
Distributed tracing Stable
Fault injection Stable
Gateway API support Stable
Multi-cluster communication Stable
CNI plugin Stable
Rate limiting Available
Topology-aware routing Available
Non-Kubernetes workloads Available (mesh expansion)

6. Resource Comparison

Metric Linkerd Istio (sidecar)
Proxy language Rust C++ (Envoy)
Proxy memory per pod ~10 MB ~50 MB
Control plane memory ~300 MB total ~500 MB (istiod)
Proxy startup time ~1 second ~3-5 seconds
Configuration CRDs ServiceProfile VirtualService, DestinationRule

Key Insight

The architecture of Linkerd is deliberately minimal: a single Rust micro-proxy per pod, a small control plane with three core services (destination, identity, proxy-injector), and automatic mTLS on by default. This design trades the rich L7 feature set of Istio for simplicity, lower resource consumption, and a faster time-to-value for teams that need secure service-to-service communication without complex traffic management.


How It Works

Rust micro-proxy internals, transparent iptables interception, mTLS trust chain, EWMA load balancing, and sidecar injection.

Proxy Data Path

sequenceDiagram
    participant App as App Container
    participant Proxy as linkerd2-proxy (Rust)
    participant Dest as Destination Service
    participant Peer as Remote linkerd2-proxy
    participant Remote as Remote App

    App->>Proxy: TCP connect (transparent iptables intercept)
    Proxy->>Dest: Lookup service endpoints + policy
    Proxy->>Proxy: Establish mTLS (ML-KEM-768 + X25519)
    Proxy->>Peer: mTLS tunnel + HTTP/2 multiplex
    Peer->>Remote: Forward request
    Remote-->>Peer: Response
    Peer-->>Proxy: Response
    Proxy-->>App: Response

    Note over Proxy: Emits metrics:<br/>latency, success rate, RPS

Transparent Interception

Linkerd uses iptables rules injected into the network namespace of each pod via an init container (linkerd-init). The rules redirect all TCP traffic through the proxy:

  1. Outbound redirect: All traffic from the app container to port 4140 (outbound proxy port)
  2. Inbound redirect: All incoming traffic on port 4143 (inbound proxy port)
  3. Exclusions: Traffic to 169.254.169.254 (metadata service) and the control port of the proxy itself is excluded

The iptables rules use the REDIRECT target, which keeps the original destination IP in the socket option SO_ORIGINAL_DST. The proxy reads this option to discover where the application intended to connect.

mTLS Identity and Trust Chain

Linkerd uses a rotating certificate system with a trust anchor (root CA):

Component Certificate Lifetime Rotation
Trust anchor Root CA (self-signed) 365 days Manual (on upgrade)
Identity issuer Intermediate CA 24 hours Automatic via linkerd-identity
Proxy certificate Leaf (SPIFFE ID) 24 hours Automatic on process start

SPIFFE ID format: spiffe://<trust-domain>/ns/<namespace>/sa/<service-account>

When proxy A connects to proxy B: 1. A presents its leaf certificate (signed by the identity issuer) 2. B validates the certificate chain back to the trust anchor 3. Both proxies verify each other's SPIFFE ID against the configured RBAC policy

EWMA Load Balancing

Linkerd uses Exponentially Weighted Moving Average -- it tracks backend latency and prevents routing to slow endpoints:

flowchart LR
    Req["Request"] --> LB["EWMA LB"]
    LB -->|"pick lowest\nlatency score"| B1["Backend A\n(EWMA: 5ms) ✅"]
    LB -.->|"avoid"| B2["Backend B\n(EWMA: 500ms) ❌"]
    LB -.->|"avoid"| B3["Backend C\n(EWMA: 200ms)"]

    style B1 fill:#2e7d32,color:#fff
    style B2 fill:#c62828,color:#fff

The EWMA algorithm: new_ewma = (1 - α) × old_ewma + α × latest_latency where α is a decay factor. After each request completes, the proxy updates the EWMA for that endpoint. Endpoints with the lowest EWMA scores receive more traffic. This automatically routes around degraded backends without health checks.

Control Plane Components

Component Purpose
linkerd-destination Service discovery: resolves Kubernetes services to endpoint lists + policy
linkerd-identity Certificate authority: issues leaf certificates to proxies on startup
linkerd-proxy-injector Mutating webhook: injects the proxy sidecar into pods based on annotations
linkerd-sp-validator Validates ServerPolicy and Server CRDs before admission

Sources


Benchmarks

Scope

Performance characteristics, scaling limits, and resource consumption for Linkerd.

Proxy Performance

Metric Linkerd2-proxy Envoy (Istio) Notes
Latency added (P50) < 1ms 1-2ms Rust vs C++
Latency added (P99) 1-3ms 3-10ms Under load
Memory per proxy 15-25MB 50-100MB Significantly lighter
CPU per proxy 10-50m 50-100m Lighter workload
Throughput 95-98% native 90-95% native Minimal overhead

Control Plane Resources

Mesh Size (pods) Destination CPU Destination Memory Identity Memory
100 100m 128Mi 64Mi
500 200m 256Mi 128Mi
2,000 500m 512Mi 256Mi

Scaling Limits

Dimension Limit Notes
Pods in mesh 10,000+ Per cluster
Services 5,000+
Endpoints per service 5,000 EndpointSlice support
Certificate rotation Auto, 24h default Zero-downtime

Sourcing Status

Unsourced Performance Data

The performance numbers in this document are estimated from vendor documentation, community benchmarks, and engineering judgment. They do not represent controlled benchmarks with documented test conditions. Specific hardware configurations, software versions, and test methodologies were not recorded.

Use these figures as rough guidance only. For production capacity planning, run your own benchmarks against your specific workload and infrastructure.

Sources


Security

Overview

Linkerd takes a security-first approach: automatic mTLS is enabled by default for all traffic between meshed pods. This requires zero configuration. The identity system uses a simple PKI chain anchored by a trust anchor certificate. Authorization policies use the Kubernetes-native Server and ServerAuthorization CRDs.

See also: index, service-mesh/linkerd/explanation, service-mesh/linkerd/how-to-guides

1. Automatic mTLS

Linkerd automatically enables mutually-authenticated TLS (mTLS) for all TCP traffic between meshed pods. This means every connection between meshed workloads is both encrypted and authenticated without application code changes or manual certificate management.

graph LR
    subgraph "Source Pod"
        AppA["Application"] --> PA["linkerd2-proxy"]
    end
    subgraph "Destination Pod"
        PB["linkerd2-proxy"] --> AppB["Application"]
    end
    PA <-->|mTLS<br/>encrypted & authenticated| PB
    PA -.->|certificate request| ID["identity controller"]
    PB -.->|certificate request| ID

Key characteristics:

  • On by default -- no configuration needed to enable mTLS
  • Zero application changes -- encryption and authentication happen at the proxy layer
  • Protocol agnostic -- works for HTTP, HTTP/2, gRPC, and raw TCP
  • Control plane also secured -- the Linkerd control plane components themselves communicate via mTLS

2. Trust Anchor PKI

Linkerd uses a simple two-tier PKI (Public Key Infrastructure):

Trust Anchor (root certificate, long-lived)
  └── Issuer Certificate (intermediate, managed by identity controller)
        └── Workload Certificate (per-Service Account, short-lived)

Trust Anchor

The trust anchor is the root of trust for the entire mesh:

  • Generated during linkerd install or provided manually
  • Typically uses ECDSA (P-256) for small key size and fast verification
  • Common name format: root.linkerd.cluster.local
  • Distributed to all proxies as a read-only ConfigMap (linkerd-identity-trust-roots)
  • Store it securely. Rotate it infrequently

Issuer Certificate

The issuer certificate is signed by the trust anchor and used by the identity controller to sign workload certificates:

  • Stored as a Kubernetes Secret in the linkerd namespace
  • Can be managed by cert-manager for automatic rotation
  • Rotating the issuer does not require restarting proxies

Provisioning with cert-manager

For production deployments, cert-manager can manage the trust anchor and issuer lifecycle:

apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
  name: linkerd-trust-anchor
  namespace: cert-manager
spec:
  issuerRef:
    kind: Issuer
    name: linkerd-trust-root-issuer
  secretName: linkerd-trust-anchor
  isCA: true
  commonName: root.linkerd.cluster.local
  duration: 8760h    # 1 year
  renewBefore: 7320h  # renew 60 days before expiry
  privateKey:
    rotationPolicy: Always
    algorithm: ECDSA

The trust-manager Bundle resource distributes trust anchors to all namespaces:

apiVersion: trust.cert-manager.io/v1alpha1
kind: Bundle
metadata:
  name: linkerd-identity-trust-roots
  namespace: linkerd
spec:
  sources:
  - secret:
      name: "linkerd-trust-anchor"
      key: "tls.crt"
  target:
    configMap:
      key: "ca-bundle.crt"
    namespaceSelector:
      matchLabels:
        linkerd.io/is-control-plane: "true"

3. Identity Controller

The identity controller is the built-in certificate authority of Linkerd:

  • Issues TLS certificates to linkerd2-proxy instances on startup
  • Identity is derived from the Kubernetes Service Account of the pod
  • Identity format: <service-account>.<namespace>.serviceaccount.identity.linkerd.cluster.local
  • Validates CSR (Certificate Signing Request) against the Kubernetes API
  • Short-lived certificates (default 24 hours) with automatic rotation
  • Runs as part of the linkerd-control-plane deployment

4. Certificate Rotation

Linkerd handles certificate rotation at multiple levels:

Certificate Lifetime Rotation Mechanism
Trust anchor 1+ years Manual or cert-manager
Issuer certificate Configurable cert-manager or manual
Workload certificate 24 hours (default) Automatic via identity controller

Workload certificate rotation is transparent to the application. The proxy requests a new certificate from the identity controller before the current one expires, with no connection interruption.

5. Server and ServerAuthorization

Linkerd uses two CRDs for fine-grained authorization:

Server

The Server resource defines which traffic a policy applies to, selecting pods by label and specifying the port and protocol:

apiVersion: policy.linkerd.io/v1beta1
kind: Server
metadata:
  name: backend-server
  namespace: production
spec:
  podSelector:
    matchLabels:
      app: backend
  port: 8080
  proxyProtocol: HTTP/2

ServerAuthorization

The ServerAuthorization resource specifies which clients are allowed to connect to a Server:

apiVersion: policy.linkerd.io/v1beta1
kind: ServerAuthorization
metadata:
  name: backend-authz
  namespace: production
spec:
  server:
    name: backend-server
  client:
    meshTLS:
      identities:
      - "frontend.production.serviceaccount.identity.linkerd.cluster.local"
    unauthenticated: false

Authorization features:

  • Identity-based access control -- restrict access to specific Service Account identities
  • Namespace-based access control -- allow traffic from specific namespaces
  • Network-based access control -- allow traffic from specific CIDR ranges
  • Protocol-aware -- HTTP method and path matching for L7 policies

6. Tap RBAC

The Linkerd tap feature allows real-time inspection of traffic flowing through the mesh. Access to tap data is controlled by Kubernetes RBAC:

  • The linkerd-tap role controls who can tap traffic
  • Tap can be scoped to specific namespaces, deployments, or pods
  • Sensitive data (headers, body) is not exposed by default
  • Requires explicit RBAC binding to use

Tap Access

Grant tap permissions carefully. While tap does not expose payload data by default, it reveals request metadata including URIs, headers, and response codes that can contain sensitive information.

7. Security Comparison with Istio

Aspect Linkerd Istio
mTLS default On by default PERMISSIVE by default (requires PeerAuthentication STRICT)
Identity format Service Account based (custom format) SPIFFE format
Authorization CRD Server + ServerAuthorization AuthorizationPolicy
JWT validation Not built-in (use external) RequestAuthentication (native)
Certificate management Built-in or cert-manager Built-in Citadel or external CA
Ambient / sidecar-less Not available ztunnel + waypoint

Key Insight

The security philosophy of Linkerd is "secure by default." mTLS is automatically enabled for all meshed traffic, the PKI is simple (trust anchor + issuer + workload), and authorization uses Kubernetes-native CRDs. This trades the richer security features of Istio (native JWT, SPIFFE standard, ambient mode) for a dramatically simpler operational model where the default configuration is already production-ready.