System Architecture
kguardian is designed as a distributed system with four main components that work together to observe, analyze, and secure your Kubernetes workloads.Components
Controller
Language: Rust + eBPF (C)Deployment: DaemonSet (one per node)Purpose: Observes kernel-level events
Broker
Language: Rust + Actix-webDeployment: Deployment with PostgreSQLPurpose: Stores and serves telemetry data
CLI
Language: GoDeployment: kubectl pluginPurpose: Generates security policies
UI
Language: React + TypeScriptDeployment: Web applicationPurpose: Visualizes network topology
Data Flow
1. eBPF Monitoring
The Controller attaches eBPF programs to kernel hooks (
tcp_connect, syscall enter/exit, etc.) on each node. When pods make network connections or execute syscalls, eBPF programs capture:- Source/destination IPs and ports
- Protocol (TCP/UDP)
- Syscall names and arguments
- Container network namespace inode
- Timestamp
eBPF runs in the kernel with minimal overhead (~1-2% CPU), avoiding the need for sidecar proxies or agent injection.
2. Event Enrichment
The Controller’s userspace component:
- Receives events from eBPF via perf buffers
- Queries containerd to map network namespace inodes to container IDs
- Matches containers to Kubernetes pods via the API server
- Enriches events with pod name, namespace, labels, and owner references
3. Data Transmission
Enriched events are sent to the Broker via HTTP POST:
- Network traffic →
/podsand/pod/spec - Syscall data →
/pods/syscalls - Service mappings →
/svc/spec
4. Storage & Indexing
The Broker stores all telemetry in PostgreSQL with indexes on:
- Pod IP address
- Pod name + namespace
- Timestamp (for time-range queries)
- Traffic type (INGRESS/EGRESS)
5. Policy Generation
The CLI queries the Broker API:
- Fetches all traffic for a specific pod
- Identifies unique source/destination IPs
- Resolves IPs to pods/services via the Broker
- Groups traffic by protocol and port
- Deduplicates rules
- Generates K8s/Cilium NetworkPolicy YAML
6. Visualization
The UI fetches data from the Broker and renders:
- An interactive graph of pod-to-pod communication (React Flow)
- Tables of traffic details with filtering
- Real-time updates as new data arrives
Technology Stack
Controller (Rust + eBPF)
Why Rust?
Why Rust?
- Memory safety without garbage collection (critical for low-level system programming)
- Performance on par with C/C++ for userspace eBPF handling
- libbpf-rs bindings provide excellent eBPF ergonomics
- Tokio async runtime for efficient event processing
eBPF Programs
eBPF Programs
- Written in C, compiled with
clang -target bpf - Use
libbpf-cargoto generate Rust skeleton bindings (.skel.rs) - Attach to kprobes:
tcp_connect,tcp_sendmsg, etc. - Use BPF maps for kernel ↔ userspace communication
Kubernetes Integration
Kubernetes Integration
- kube-rs: Rust Kubernetes client for pod watching
- Watches pods on the current node via field selector
- Filters by excluded namespaces (kube-system, kguardian, etc.)
- Handles pod lifecycle events (create, update, delete)
Broker (Rust + Actix-web + PostgreSQL)
API Framework
API Framework
- Actix-web: High-performance HTTP server (thousands of req/sec)
- RESTful API with JSON payloads
- Async request handling with Tokio
- Diesel ORM for type-safe SQL queries
Data Schema
Data Schema
Tables:
pods: Pod metadata (name, namespace, IP, labels, spec)services: Service metadata (name, namespace, cluster IP, selectors)pod_traffic: Network connections (src/dst IP, port, protocol, type)pod_syscalls: Syscall observations (pod, syscall names, count, architecture)
Data Retention
Data Retention
Currently, data is retained indefinitely. Future versions will support:
- Configurable retention periods
- Automatic data aggregation/rollup
- Export to external systems (S3, etc.)
CLI (Go)
Why Go?
Why Go?
- kubectl plugin ecosystem: Natural fit for K8s tooling
- client-go: Official Kubernetes Go client
- cobra: Industry-standard CLI framework
- Cross-platform binaries without dependencies
Policy Generation Logic
Policy Generation Logic
Network policies:
- Query
/pod/traffic/name/:namespace/:podfrom Broker - For each unique peer IP, query
/pod/ip/:ipor/svc/ip/:ip - Build
NetworkPolicyPeerwithpodSelector+namespaceSelector - Group by direction (ingress/egress) and port/protocol
- Deduplicate rules via JSON marshaling comparison
- Generate YAML with
sigs.k8s.io/yaml
Seccomp Generation Logic
Seccomp Generation Logic
- Query
/pod/syscalls/name/:namespace/:podfrom Broker - Extract unique syscall names from aggregated data
- Group by architecture (x86_64, arm64, etc.)
- Generate JSON with
defaultAction: SCMP_ACT_ERRNO - Add
syscallsarray withaction: SCMP_ACT_ALLOW
UI (React + TypeScript)
Frontend Stack
Frontend Stack
- React 19: Modern UI framework
- TypeScript: Type safety for complex state
- Vite: Fast build tooling
- TailwindCSS 4: Utility-first styling
- React Flow: Interactive network graph rendering
Visualization
Visualization
- Pods rendered as collapsible nodes (expand to show containers)
- Edges show traffic direction with arrows
- Namespace-based grouping with color coding
- Interactive filtering by namespace, pod, traffic type
Data Display
Data Display
- Traffic table with sorting and pagination
- Pod details panel with labels and metadata
- Real-time updates via polling the Broker API
- Dark mode support (matches Cilium Hubble aesthetic)
Deployment Architecture
Standard Deployment (Helm)
High Availability
For production, configure:- Broker replicas: 2-3 for load balancing
- PostgreSQL: Use managed service (RDS, Cloud SQL) or PostgreSQL operator with replication
- Controller: Automatically HA via DaemonSet (one per node)
- UI: 2+ replicas behind ingress/load balancer
Security Considerations
Controller Privileges
Controller Privileges
The Controller requires:
- Privileged container (to load eBPF programs)
- hostNetwork (to access node network namespace)
- CAP_BPF, CAP_PERFMON, CAP_SYS_RESOURCE capabilities
Data Access
Data Access
- Broker API currently has no authentication (assumes network isolation)
- For production, consider:
- Network policies to restrict Broker access
- Ingress with authentication (OAuth2 proxy, etc.)
- mTLS between components
Data Sensitivity
Data Sensitivity
The PostgreSQL database contains:
- Pod names, namespaces, labels
- IP addresses and ports of communication
- Syscall activity
Performance Characteristics
| Component | CPU (idle) | CPU (busy) | Memory | Notes |
|---|---|---|---|---|
| Controller | 10-20m | 50-100m | 50-100Mi | Per node, depends on pod count |
| Broker | 5-10m | 50-200m | 100-200Mi | Scales with request rate |
| PostgreSQL | 10-20m | 50-100m | 256Mi-1Gi | Depends on data volume |
| UI | 1-5m | 10-20m | 50-100Mi | Static content serving |
In testing with 100 pods generating moderate traffic, total cluster overhead is ~200-400m CPU and ~500Mi-1Gi memory.
Scalability
- Controllers: Scale linearly with node count (DaemonSet)
- Broker: Stateless, can add replicas behind a load balancer
- PostgreSQL: Vertical scaling or read replicas for high query loads
- CLI: No scaling concerns (client-side)
- UI: Horizontal scaling behind ingress
- Sharding data by namespace
- Time-windowed queries
- Data aggregation/rollup