Istio — Interfaces#
Sampling note#
Istio has 263 interface definitions outside vendor/. The 8 interfaces analyzed here were selected because they appear directly in the architecture result as the load-bearing abstractions of the control plane. Trivial single-method helpers, test-only interfaces, and widget-level watcher interfaces were skipped.
Interface catalog#
ConfigStore#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/config.go:125 - Methods:
Schemas() collection.Schemas Get(typ config.GroupVersionKind, name, namespace string) *config.Config List(typ config.GroupVersionKind, namespace string) []config.Config Create(config config.Config) (revision string, err error) Update(config config.Config) (newRevision string, err error) UpdateStatus(config config.Config) (newRevision string, err error) Delete(typ config.GroupVersionKind, name, namespace string, resourceVersion *string) error - Purpose: Platform-agnostic CRUD access to all Istio configuration resources (VirtualService, DestinationRule, Gateway, AuthorizationPolicy, PeerAuthentication, Sidecar, Telemetry, etc.). The interface is intentionally storage-agnostic: it makes no assumptions about Kubernetes, etcd, or any backend.
- Implementations:
crdclient.Client(pilot/pkg/config/kube/crdclient/client.go) — Kubernetes CRD-backed store using typed kclient informersfile.KubeSource(pilot/pkg/config/file/store.go) — filesystem-backed store (used in integration tests and offline mode)configaggregate.Store— fan-out aggregate that reads from multiple backing stores and merges resultsFakeStore— test double
- Design quality: Well-segregated CRUD contract. Only 7 methods; each is orthogonal. The
GroupVersionKindkey is the right abstraction for a multi-schema config system. The documentation notes intentional eventual consistency (mutations may not be immediately visible on Get), which is honest about k8s informer semantics.
ConfigStoreController#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/config.go:172 - Methods:
// embeds ConfigStore, plus: RegisterEventHandler(kind config.GroupVersionKind, handler EventHandler) Run(stop <-chan struct{}) HasSynced() bool KrtCollection(kind config.GroupVersionKind) krt.Collection[config.Config] - Purpose: Extends
ConfigStorewith lifecycle management and change notifications. Represents a running local cache (backed by an informer) that propagates config-change events to downstream handlers. TheKrtCollectionmethod is a newer addition that exposes the underlying krt collection, enabling reactive pipelines to subscribe directly without the legacy callback mechanism. - Implementations: Same as
ConfigStore(every production implementation satisfies both). - Design quality: Appropriate ISP split — read-only callers (xDS generators) receive only
ConfigStore; lifecycle owners receive the full controller interface. TheKrtCollectionescape hatch is a transitional affordance while migrating from event callbacks to krt-style reactive composition.
ServiceDiscovery#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/service.go:929 - Methods:
// embeds NetworkGatewaysWatcher and AmbientIndexes, plus: Services() []*Service GetService(hostname host.Name) *Service GetProxyServiceTargets(proxy *Proxy) []ServiceTarget GetProxyWorkloadLabels(proxy *Proxy) labels.Instance MCSServices() []MCSServiceInfo - Purpose: Unified abstraction for enumerating services, endpoints, and workload metadata across one or more service registries. Istio can simultaneously watch Kubernetes services, ServiceEntry CRDs, and cloud-provider registries;
ServiceDiscoveryhides this multiplicity from the xDS generation layer. - Implementations:
aggregate.Controller(pilot/pkg/serviceregistry/aggregate) — fans out to N registries and mergesserviceregistry.Instance(pilot/pkg/serviceregistry/instance.go) — combinesmodel.Controller+model.ServiceDiscoveryinto a per-registry handle; Kubernetes and ServiceEntry controllers both implement this interface
- Design quality: The interface is relatively broad (5 own methods + embedded interfaces), but each method is genuinely needed by the xDS generators that consume it. The embedding of
AmbientIndexesdeserves scrutiny — it bundles sidecar-mode and ambient-mode concerns in a single type, which creates coupling (anyServiceDiscoveryimplementation must stub out ambient methods even if they’re irrelevant). This is a pragmatic trade-off to avoid a separate runtime type assertion path for ambient mode.
AmbientIndexes#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/service.go:965 - Methods:
ServicesWithWaypoint(key string) []ServiceWaypointInfo AddressInformation(addresses sets.String) ([]AddressInfo, sets.String) AdditionalPodSubscriptions(proxy *Proxy, allAddresses, currentSubs sets.String) sets.String Policies(requested sets.Set[ConfigKey]) []WorkloadAuthorization ServicesForWaypoint(WaypointKey) []ServiceInfo WorkloadsForWaypoint(WaypointKey) []WorkloadInfo ServiceInfo(key string) *ServiceInfo - Purpose: Ambient mesh queries — lookups needed by the PCDS and workload xDS generators to serve ztunnel and waypoint proxies. The ambient data model differs fundamentally from the sidecar model: identity is IP/address-based, not pod-centric, and waypoints act as L7 proxies for services. These 7 methods encapsulate that alternative index.
- Implementations:
ambientindex.AmbientIndexesImpl(built using krt collections); stub implementations in test code. - Design quality: Reasonably cohesive as an ambient-specific contract. The choice to embed it directly in
ServiceDiscoveryrather than compose it via an interface field means non-ambient implementations must provide no-op stubs for all 7 methods, which is slightly leaky.
XDSUpdater#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/push_context.go:327 - Methods:
EDSUpdate(shard ShardKey, hostname, namespace string, entry []*IstioEndpoint) EDSCacheUpdate(shard ShardKey, hostname, namespace string, entry []*IstioEndpoint) SvcUpdate(shard ShardKey, hostname, namespace string, event Event) ConfigUpdate(req *PushRequest) ProxyUpdate(clusterID cluster.ID, ip string) RemoveShard(shardKey ShardKey) - Purpose: The callback bridge between service registries (Kubernetes controllers, ServiceEntry controller) and the xDS push pipeline (
DiscoveryServer). The interface inverts the dependency so that registries call upward into the discovery server without a direct import cycle.EDSUpdatetriggers a push;EDSCacheUpdateonly updates state (for bulk loading before serving).ConfigUpdateis the full-push trigger.ProxyUpdateallows per-proxy targeted pushes. - Implementations:
xds.DiscoveryServer— the primary implementation;ConfigUpdateenqueues topushChannel,EDSUpdateenqueues an incremental pushxdsfake.Updater(pilot/pkg/serviceregistry/util/xdsfake/updater.go) — test double that records callsFakeEndpointIndexUpdater— minimal test double
- Design quality: Clean dependency-inversion interface. The split between
EDSUpdate(push) andEDSCacheUpdate(no-push) is a subtle but important optimization for the case where multiple endpoint shards are being loaded; callers batch with cache-only updates, then trigger a single push. 6 methods is slightly wide but each is distinct in semantics.
XdsResourceGenerator / XdsDeltaResourceGenerator#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/context.go:290,296 - Methods:
// XdsResourceGenerator: Generate(proxy *Proxy, w *WatchedResource, req *PushRequest) (Resources, XdsLogDetails, error) // XdsDeltaResourceGenerator (embeds XdsResourceGenerator): GenerateDeltas(proxy *Proxy, req *PushRequest, w *WatchedResource) (Resources, DeletedResources, XdsLogDetails, bool, error) - Purpose: The plugin interface for xDS resource generation.
DiscoveryServerkeeps amap[string]XdsResourceGeneratorkeyed by xDS type URL (e.g.,"type.googleapis.com/envoy.config.listener.v3.Listener"). When a push is needed for a proxy, the server looks up the generator for each subscribed type and callsGenerate. The delta variant is for Incremental xDS (Delta ADS) where only changed/removed resources need to be sent. - Implementations:
LdsGenerator— Listener Discovery Service (LDS)CdsGenerator(implementsXdsDeltaResourceGenerator) — Cluster Discovery Service (CDS)EdsGenerator(implementsXdsDeltaResourceGenerator) — Endpoint Discovery Service (EDS)RdsGenerator— Route Discovery Service (RDS)NdsGenerator— Name Discovery Service (NDS, DNS)EcdsGenerator— Extension Config Discovery Service (ECDS)PcdsGenerator— Policy Config Discovery Service (PCDS, ambient RBAC)SecretGen— Secret Discovery Service (SDS, TLS certificates)- Ambient workload generator (registered for ambient mode type URL)
- Design quality: Near-perfect ISP. The single-method
XdsResourceGeneratorinterface is one of the cleanest in the codebase — trivially mockable, trivially composable, with zero coupling between generators. The delta sub-interface is optional opt-in, which is the right choice. This design is the direct reason why adding a new xDS type (PCDS, workload) requires zero changes to the core push loop.
ConfigGenerator#
- Package:
pilot/pkg/networking/core - File:
pilot/pkg/networking/core/configgen.go:28 - Methods:
BuildListeners(node *model.Proxy, push *model.PushContext) []*listener.Listener BuildClusters(node *model.Proxy, req *model.PushRequest) ([]*discovery.Resource, model.XdsLogDetails) BuildDeltaClusters(proxy *model.Proxy, updates *model.PushRequest, watched *model.WatchedResource) ([]*discovery.Resource, []string, model.XdsLogDetails, bool) BuildHTTPRoutes(node *model.Proxy, req *model.PushRequest, routeNames []string) ([]*discovery.Resource, model.XdsLogDetails) BuildNameTable(node *model.Proxy, push *model.PushContext) *dnsProto.NameTable BuildExtensionConfiguration(node *model.Proxy, push *model.PushContext, extensionConfigNames []string, pullSecrets map[string][]byte) []*core.TypedExtensionConfig MeshConfigChanged(mesh *meshconfig.MeshConfig) - Purpose: A higher-level, Envoy-aware translation interface that sits above
XdsResourceGenerator. WhereXdsResourceGenerator.Generateis protocol-generic,ConfigGeneratormethods work directly with Envoy proto types (listener, cluster, route). The individual xDS generators (LdsGenerator, CdsGenerator, etc.) delegate toConfigGeneratormethods on their internalConfigGeneratorImplreference.ConfigGeneratoris thus the domain-logic layer; the xDS generators handle framing, caching, and protocol handling. - Implementations:
ConfigGeneratorImpl— the sole production implementation; no test doubles needed because the xDS generators test viaXdsResourceGenerator. - Design quality: 7 methods makes it a moderately wide interface. Only one implementation exists, so the interface primarily serves as a seam for testing and to document the expected contract.
MeshConfigChangedis a cache-invalidation hook and feels slightly out of place, but it is legitimately needed sinceConfigGeneratorImplholds theaccessLogBuildercache.
XdsCache#
- Package:
pilot/pkg/model - File:
pilot/pkg/model/xds_cache.go:36 - Methods:
Run(stop <-chan struct{}) Add(entry XdsCacheEntry, pushRequest *PushRequest, value *discovery.Resource) Get(entry XdsCacheEntry) *discovery.Resource Clear(sets.Set[ConfigKey]) ClearAll() Keys(t string) []any // debug/test only Snapshot() []*discovery.Resource // debug/test only - Purpose: Content-addressed cache for encoded Envoy
proto.AnyxDS resources. Keys areXdsCacheEntryobjects whoseDependentConfigs()returns the set of config hashes this resource depends on; when any of those configs change, the cache entry is invalidated. This avoids re-encoding identical protobuf between push cycles. TheAddmethod silently drops writes for stalePushRequests, preventing a race where a slow generator writes stale data after a newer push cycle has already started. - Implementations:
XdsCacheImpl— the sole production implementation (backed by four type-specifictypedXdsCache[K]instances for CDS, EDS, RDS, SDS). - Design quality: The design of a separate
XdsCacheEntryinterface is elegant — it decouples the cache from knowledge of specific resource types and lets each generator define its own cache key logic.Keys/Snapshotbeing explicitly documented as “testing/debug only” in comments is a good signal; they should arguably be in a separate interface.
Collection[T]#
- Package:
pkg/kube/krt - File:
pkg/kube/krt/core.go:28 - Methods:where
GetKey(k string) *T List() []T EventStream[T] // Register, RegisterBatch Metadata() MetadataEventStream[T]embedsSyncerand adds:Register(f func(o Event[T])) HandlerRegistration RegisterBatch(f func(o []Event[T]), runExistingState bool) HandlerRegistration - Purpose: The foundational abstraction for Istio’s declarative reactive controller framework (krt). A
Collection[T]is a live, typed view of a Kubernetes resource or a derived transformation. Consumers list the current state or subscribe to change events; the krt runtime propagates changes through the dependency graph automatically. This eliminates the need to write imperative reconcile-loops with manual mutex management. - Implementations: Multiple internal implementations —
StaticCollection,informerCollection[T](wrapping a kclient informer),derivedCollection[T](built viaNewCollection/NewManyCollectiontransformations),Singleton[T]. - Design quality: The generic interface is well-designed: small surface, clear semantics, and the
EventStreamembedding follows Go’s composability idiom. TheinternalCollectionsuper-interface (unexported) adds uid/dump/augment methods needed by the krt engine without exposing them to consumers — correct information hiding. The framework is a genuine architectural investment for the next generation of Istio controllers.
Interface patterns#
Size distribution: The core interfaces average 5–7 methods. The single-method
XdsResourceGeneratoris a standout example of ISP applied perfectly. The broader interfaces (ServiceDiscovery,ConfigGenerator) reflect real domain complexity rather than design laziness — each method is genuinely used by multiple callers.Embedding: Used consistently for interface composition:
ConfigStoreControllerembedsConfigStoreServiceDiscoveryembedsNetworkGatewaysWatcherandAmbientIndexesXdsDeltaResourceGeneratorembedsXdsResourceGeneratorserviceregistry.Instanceembedsmodel.Controllerandmodel.ServiceDiscoveryEventStream[T]embedsSyncerThis produces clean ISP splits: callers that only need read access getConfigStore; callers needing lifecycle management getConfigStoreController.
Implicit satisfaction: All interfaces are defined in consumer-side packages (
pilot/pkg/model,pkg/kube/krt) rather than provider-side packages. Implementations usevar _ Interface = (*ConcreteType)(nil)compile-time assertions throughout. This is idiomatic Go and correctly places the contract ownership with the consumer.stdlib interfaces used: Minimal direct use.
XdsCacheEntryuses a pattern resemblinghash.Hash. TheSyncertype (embedded inEventStream) is an Istio-internal interface analogous tocache.InformerSynced. Most interfaces are domain-specific rather than wrapping stdlib contracts.
Key abstractions#
XdsResourceGenerator — The single most elegant interface in the codebase. One method, zero coupling, directly enables the plugin-map architecture of the xDS push loop. Adding a new xDS resource type is a one-file change: implement
Generate, register in the map. This is the pattern that allowed PCDS and workload xDS for Ambient mode to be added without touching the push loop.ConfigStore / ConfigStoreController — The gateway to all Istio user configuration. By abstracting over Kubernetes CRDs, filesystem, and xDS-over-MCP backends, it makes the entire xDS generation layer portable and testable. The ISP split into a read-only
ConfigStoreand a lifecycle-owningConfigStoreControlleris the right design decision.XDSUpdater — The dependency-inversion interface that decouples service registries from
DiscoveryServer. Without it,pilot/pkg/serviceregistry/kube/controllerwould need to importpilot/pkg/xds, creating a circular dependency. The separation ofEDSUpdate(push-triggering) fromEDSCacheUpdate(cache-only) shows mature operational thinking about bulk loading.ServiceDiscovery — The unified registry abstraction. Its embedding of
AmbientIndexesis architecturally significant: it forces all registry implementations to speak both the sidecar and ambient vocabularies, which keeps theDiscoveryServerpush path generic. The trade-off is that non-ambient registries must implement ambient stubs.Collection[T] — The foundational type of the krt framework. It is the most architecturally forward-looking interface in the codebase, representing Istio’s intent to replace all imperative Kubernetes controller code with declarative reactive pipelines. Its design — generic, event-streaming, with lazy propagation — is a blueprint for how large-scale Kubernetes controller frameworks should be structured.
Interface-driven extensibility#
Istio achieves extensibility at three levels through interfaces:
xDS type extensibility via
XdsResourceGenerator: New Envoy resource types (PCDS for policy, workload for ambient ztunnel) are registered intoDiscoveryServer’s generator map with no changes to the core push loop. Third-party Istio forks have used this to add custom xDS types.Backend extensibility via
ConfigStore/ServiceDiscovery: In principle, non-Kubernetes backends (cloud registries, custom service meshes) can plug in by implementing these interfaces. In practice, the aggregate controller pattern (configaggregate,serviceregistry/aggregate) means new backends are added as additional registries that are merged transparently.Controller modernization via
Collection[T]: The krt framework provides an extension point for building new control loops declaratively. New subsystems (Ambient mode’s workload indexing, gateway-api integration) are being built as krt collections composed from existing collections, enabling safe incremental replacement of legacy controller code.