DEV Community

Hiro Ventolero
Hiro Ventolero

Posted on

Building NetZero: Automated Zero-Trust K8s Network Policies Using Go and eBPF

NetZero: Automated Zero-Trust K8s Network Policies Using Go and eBPF

Implementing zero-trust networking in a microservice architecture is a massive pain point. In production, security best practices dictate that Service A should only be allowed to communicate with Service B, and everything else must be blocked.

But as developers, how do we actually implement this?

Usually, it involves a painful guessing game: combing through raw source code, tracing configuration files, or parsing logs to write complex Kubernetes NetworkPolicy YAML files. If you miss a single third-party API or internal caching layer, your application crashes in production.

To solve this, I built and open-sourced NetZero: a zero-configuration developer tool written in Go and C that observes actual runtime traffic directly from the Linux kernel to auto-generate flawless network policies.

Here is a deep technical look under the hood at how it works.


The Architecture: Why eBPF + Go?

Traditional network sniffing utilities rely on heavy user-space proxies (like Envoy sidecars) or intrusive SDK integration. This introduces significant latency and eats up local laptop RAM.

NetZero completely bypasses user space during tracing by leveraging eBPF (Extended Berkeley Packet Filter).

       [ Local App / Docker Container ]
                      │ (Makes network request via socket)
                      ▼
 ───────────────── KERNEL SPACE (C) ─────────────────
   eBPF Hook: security_socket_connect() 
      │ 
      ▼ Extracts: PID, Dest IP, Dest Port, Family
   Shoved into BPF_MAP_TYPE_RINGBUF
 ────────────────────────────────────────────────────
                      │ Streamed in real-time
                      ▼
 ────────────────── USER SPACE (Go) ──────────────────
   Cilium/ebpf Reader ──> Event Channel
                          ──> K8s Metadata Enricher (/proc lookup)
                          ──> Traffic Aggregator Engine
                          ──> YAML Manifest Exporter
 ────────────────────────────────────────────────────

Enter fullscreen mode Exit fullscreen mode

By splitting the architecture, we get the raw speed of a kernel probe written in C combined with the rapid asynchronous processing and robust DevOps ecosystem of Go.


1. The Kernel Space: The C Probe

Inside the kernel, NetZero hooks into the security_socket_connect kprobe helper function. Every time an application attempts to instantiate an outbound network connection, our eBPF program catches it before the first packet ever touches the wire.

We define a data structure to pass telemetry data out of the kernel space:

struct bpf_flow_event {
    u32 pid;
    u32 remote_ip;
    u16 remote_port;
    char comm[16];
};
Enter fullscreen mode Exit fullscreen mode

Using a highly efficient lockless ring buffer (BPF_MAP_TYPE_RINGBUF), our C probe pushes events out to user space instantly, introducing practically zero overhead to the application process.


2. The User Space: The Go Controller

Our Go layer acts as the coordinator and intelligence engine. It uses the excellent github.com/cilium/ebpf library to compile, load, and attach the C bytecode directly into the running kernel.

Context Enrichment via /proc

A raw IP address and a Process ID aren't enough to generate a high-level Kubernetes manifest. The Go daemon listens to the ring buffer channel and enriches the raw telemetry data using the host filesystem:

  • Process Translation: The controller takes the raw PID and checks /proc/{PID}/cgroup or /proc/{PID}/cmdline to identify whether the connection originated from a specific Docker container or a native host process.
  • Reverse DNS Resolution: If the target IP is external, Go performs an asynchronous reverse-DNS lookup to group dynamic, ephemeral cloud IPs into stable domain names (e.g., mapping 3.210.12.4 to api.stripe.com).

3. The Output: From Packets to YAML

Once your local integration test suite concludes, NetZero stops tracing and evaluates the aggregate network state. It deduplicates the unique flow routes and maps them into a declarative standard Kubernetes NetworkPolicy.

Instead of hand-writing 50 lines of YAML, NetZero spits out a precise, production-ready manifest derived entirely from actual running code:

apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: payment-service-egress-rules
spec:
  podSelector:
    matchLabels:
      app: payment-service
  egress:
  - to:
    - podSelector:
        matchLabels:
          app: postgres-database
    ports:
    - protocol: TCP
      port: 5432
Enter fullscreen mode Exit fullscreen mode

Try it out & Contribute!

NetZero is completely open-source and ready for early adopters. If you are looking to dip your toes into low-level systems programming, eBPF, or advanced Go concurrency engines, we would love your help!

Top comments (0)