Multi-tenant keploy-agent: per-app isolation (user-space foundation)
Summary
Make the keploy-agent multi-tenant: one agent process serving many applications concurrently, with every piece of per-app state isolated by an app/session key (config, mocks, channels, static-dedup, capture filters, mode). Today the agent is structurally single-app — the proxy session, mock manager, syncMock, clientMocks, dedup, and mode are all process-global / hardcoded to a single key.
This issue tracks the OSS user-space foundation, which is the prerequisite for both deployment models:
- Sidecar/native — attribution via
/procancestry (container/netns mode in v1). - DaemonSet (enterprise) — the eBPF capture is already multi-tenant (gate admits all target pods, each event carries
kernelPid); it only needs this user-space layer to route per-app, fed by an authoritative PID→session resolver.
Root cause
The data path carries no app/session key. pkg/agent/proxy/proxy.go holds a single session/mockManager; pkg/service/agent/agent.go stores mocks at hardcoded clientMocks[uint64(0)]; pkg/agent/proxy/syncMock is a package-global singleton with one output channel; record-vs-replay mode is process-wide.
Design — one keyed user-space layer
Introduce an AppContext (per app/session key) that owns everything that is a singleton today, held in an AppRegistry keyed by a string session key. The key flows on context.Context (aligning with the context-keyed syncMock approach). Attribution is pluggable: /proc walk (native) or an authoritative resolver (daemonset). The kernel already stamps kernelPid into redirect_proxy_map; we surface it through DestInfo.Get.
Mixed modes (app A records while app B replays) fall out for free once Mode is per-app.
Phases (this issue = OSS user-space)
- Foundation — per-app session key type +
contexthelpers; surfaceKernelPidonagent.NetworkAddress(comm.go). - AppContext + AppRegistry — skeleton owning session/mockManager/dnsCache/recordedDNSMocks/errChannel +
Resolve(kernelPid). - De-globalize
syncMock—New()+ context-keyed managers; migrate emit call sites; per-app dedup queue. - Proxy per-app — thread the key through
Record/Mock/SetMocks/SetMocksWithWindow/GetConsumedMocks/GetMockErrors/Mapping/SetGracefulShutdown+handleConnection. - Service + routes per-app — un-hardcode
clientMocks[0]; per-apptcChan/drain;X-Keploy-App-Idmiddleware; per-app capture filters. - Client — key
AgentClient.appsby real key; stampX-Keploy-App-Idon every request;/agent/register+/agent/deregisterhandshake.
Out of scope (follow-ups)
- Enterprise per-feature isolation (time-freeze per-app paths/env, static-dedup partitioning, coverage sockets, per-app upload target).
- DaemonSet bridge (
SessionForPIDresolver + per-session routing at the two capture sites). - eBPF host-mode multi-tenancy and nested-PID-ns
cgroup_idstamping (needs BPF recompile).
Source: keploy/keploy