Skip to content

Aether is a Kubernetes service mesh data plane that runs one Envoy per node instead of one per pod, capturing traffic transparently and mTLS-ing every hop with SPIFFE identities.

Written in Go. Routed with the Gateway API. Each node receives only the configuration its own pods actually use.

Get started → Architecture

Apache-2.0 · pre-1.0 · images and charts on GHCR

The shape of it

graph TD
    subgraph node["Node (DaemonSet)"]
        Pod["Workload Pod"]
        CNI["CNI Plugin<br/><i>netns setup · endpoint registration</i>"]
        Agent["Agent<br/><i>xDS · CNI server · proxy supervisor</i>"]
        Proxy["aether-proxy<br/><i>custom Envoy, hot-restart supervised</i>"]
        MeshDNS["mesh-dns<br/><i>own DaemonSet · snapshot-fed resolver</i>"]
        SPIRE["SPIRE Agent<br/><i>workload identity</i>"]

        Pod == "pod traffic" ==> Proxy
        Pod -. "DNS :53 (CNI DNAT)" .-> MeshDNS
        Agent -. "record snapshot (file)" .-> MeshDNS
        CNI -. "register (gRPC/UDS)" .-> Agent
        Agent -. "xDS, demand-scoped<br/>LDS·CDS·EDS·RDS·SDS·ODCDS" .-> Proxy
        Agent -. "Delegated Identity API" .-> SPIRE
        SPIRE -. "X.509 SVIDs (via SDS)" .-> Proxy
    end

    Peer["Peer node<br/><i>aether-proxy → workload pod</i>"]
    Proxy == "mTLS (SPIFFE)" ==> Peer

    Registrar["Registrar<br/><i>in-cluster Deployment, active/active</i>"]
    Agent -. "register · watch · list" .-> Registrar

    Registry[("External Registry<br/>DynamoDB · etcd · Kubernetes")]
    Registrar -. "sync + persist" .-> Registry

    OTel["OTel Collector<br/><i>metrics · traces</i>"]
    Agent -. "OTLP push" .-> OTel
    Proxy -. "stats sink + aether_stats" .-> OTel

Solid arrows are the workload data path; dashed arrows are control plane and telemetry.

Four decisions

One proxy per node

A single aether-proxy DaemonSet carries the traffic for every managed pod on the node, entering each pod's network namespace rather than living inside it. Interception is set up by a chained CNI plugin, so workloads are unmodified and there is no sidecar to inject, size, or restart.

Demand-scoped configuration

Each node receives only the clusters, registry watches, and endpoints its local pods actually depend on, declared with the config.aether.io/upstreams annotation, with on-demand CDS for the cold path. Config size tracks the node's footprint, not the size of the mesh. Proposal 004 →

Hitless proxy rollouts

The agent supervises Envoy through a cross-pod hot restart with two-phase connection draining. Zero dropped requests across eight-hour soak tests driving 30-plus rollouts of the data plane, measured by an external prober rather than the mesh's own telemetry. Proposal 001 →

The Gateway API, natively

No bespoke routing CRDs. East-west traffic uses GAMMA — HTTPRoute and GRPCRoute parented to a Service — and north-south uses the same API against the edge gateway. The GATEWAY-HTTP profile is fully conformant, Core 33/33 and Extended 10/10, and conformance is gated in CI. Proposal 018 → · Proposal 024 →

The design record

Every decision above was argued in writing before it was built, and the argument is published as it was written — status, dead ends and all. These are the five most recent.

Install

Two charts: the CRDs first, so they can be upgraded independently, then the system.

# Pick the published version (chart version == git commit of the release).
VERSION=0.x.0-<commit>

# 1) CRDs (MeshConfig, HTTPFilter, EdgeConfig, EndpointPolicy) — install/upgrade first.
helm upgrade --install aether-crds \
  oci://ghcr.io/bpalermo/aether/charts/crds \
  --version "$VERSION"

# 2) The system: agent + proxy + mesh-dns + registrar + controller.
helm upgrade --install aether \
  oci://ghcr.io/bpalermo/aether/charts/aether \
  --version "$VERSION" \
  --namespace aether-system --create-namespace \
  --set clusterName=my-cluster \
  --set meshDomain=aether.internal

Aether is pre-1.0 and built by one person. It is soak-tested on a real cluster and gated on Gateway API conformance in CI, but it has no support commitment. Read the proposals and the conformance baselines before you run it.