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.
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.
035Vanity Go module path aethermesh.dev
033Node-taint lifecycle — re-arm the agent-not-ready taint across reboots and agent outages
032Upgrade Gateway API to v1.6.1
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.