Cilium Network Policies: L7 HTTP Filtering with eBPF on Kubernetes
Traditional Kubernetes Network Policies only support L3/L4 filtering (IP addresses and ports). Cilium takes network security to the next…
Cilium Network Policies: L7 HTTP Filtering with eBPF on Kubernetes

Traditional Kubernetes Network Policies only support L3/L4 filtering (IP addresses and ports). Cilium takes network security to the next level by using eBPF (extended Berkeley Packet Filter) to provide L7 protocol-aware policies, enabling you to filter traffic based on HTTP paths, methods, headers, and more all enforced directly in the Linux kernel without sidecars.
Before diving deeper, let’s first understand eBPF and Cilium.
What is eBPF?
eBPF is a powerful Linux kernel technology that allows developers to run sandboxed, event-driven programs inside the Linux kernel without requiring changes to the kernel source code or loading kernel modules.
In simple terms, if you need to add additional capabilities to the operating system at runtime, you can use eBPF programs to achieve this. The OS guarantees safety and execution efficiency through a verification engine and Just-In-Time (JIT) compilation, allowing programs to run almost as if they were natively compiled kernel code.
What is Cilium?
Cilium is a cloud-native networking solution that uses eBPF to provide
- Network connectivity between pods
- Load balancing for services
- Advanced network security policies with L7 protocol awareness
- Service mesh capabilities (optional)
- Observability with deep network visibility
In this guide, we’ll focus on Cilium’s network policy capabilities, which go far beyond traditional Kubernetes NetworkPolicy objects by enabling application-layer filtering.
Let me show you something concrete: blocking specific HTTP endpoints using Layer 7 policies, all enforced directly in the Linux kernel, with zero application changes and no sidecar containers.
What We’ll Build
In this demo, we’ll
- Deploy a simple microservices app
- Apply HTTP-aware network policies (blocking specific API paths)
- Visualize everything with Hubble’s eBPF-powered observability
By the end, you’ll see exactly how Cilium uses eBPF to parse HTTP requests in the kernel and enforce policies at the application layer.
Demo — A Simple Microservices App
We’ll create a basic scenario
- A backend service exposing several API endpoints
- A client pod that should have limited access
The Goal: Use Cilium’s L7 policies to control access at the HTTP path level, not just the port level.
1. Install Cilium with Hubble
First, we need Cilium with Hubble enabled for observability
I’ll start by installing the Cilium CLI and then use it to install Cilium.
CILIUM_CLI_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/cilium-cli/main/stable.txt)
GOOS=$(go env GOOS)
GOARCH=$(go env GOARCH)
curl -L --remote-name-all https://github.com/cilium/cilium-cli/releases/download/${CILIUM_CLI_VERSION}/cilium-${GOOS}-${GOARCH}.tar.gz{,.sha256sum}
sha256sum --check cilium-${GOOS}-${GOARCH}.tar.gz.sha256sum
sudo tar -C /usr/local/bin -xzvf cilium-${GOOS}-${GOARCH}.tar.gz
rm cilium-${GOOS}-${GOARCH}.tar.gz{,.sha256sum}
After that, install Cilium
cilium install
Verify the installation
cilium status
If Cilium is correctly installed, you should see a healthy status output.

Understanding Hubble
Before enabling Hubble, let’s understand what it is.
Hubble is Cilium’s observability platform that gives you complete visibility into your Kubernetes network traffic. Built on eBPF, it captures every network flow in your cluster — from DNS queries to HTTP requests — with near-zero overhead and no application changes required.
Now, enable Hubble
cilium hubble enable --ui
Start the Hubble UI
cilium hubble ui
You can now view the Hubble dashboard at [http://localhost:12000/](http://localhost:12000/)
Alternative: Install Cilium with Helm
You can also install Cilium using Helm:
helm repo add cilium https://helm.cilium.io/
helm repo update
#replace `<cluster-name>` with your actual cluster name
helm install cilium cilium/cilium --version 1.14.5 \
--namespace kube-system \
--set cluster.name=<cluster-name> \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,icmp,http}"
Verify everything is running
kubectl -n kube-system rollout status deployment/cilium-operator
kubectl -n kube-system rollout status deployment/hubble-relay
2. Deploy the Demo Application
Create a new namespace in the k8s cluster
kubectl create namespace demo-app
Here’s the backend application and its service definition
apiVersion: apps/v1
kind: Deployment
metadata:
name: backend
namespace: demo-app
spec:
replicas: 2
selector:
matchLabels:
app: backend
template:
metadata:
labels:
app: backend
spec:
containers:
- name: backend
image: nginx:alpine
ports:
- containerPort: 8080
command: ["/bin/sh"]
args:
- -c
- |
cat > /etc/nginx/conf.d/default.conf <<EOF
server {
listen 8080;
location /api/users {
return 200 '{"users": ["alice", "bob"]}';
add_header Content-Type application/json;
}
location /api/products {
return 200 '{"products": ["laptop", "phone"]}';
add_header Content-Type application/json;
}
location /admin {
return 200 '{"admin": "secret data"}';
add_header Content-Type application/json;
}
location /health {
return 200 'OK';
add_header Content-Type text/plain;
}
}
EOF
nginx -g 'daemon off;'
---
apiVersion: v1
kind: Service
metadata:
name: backend
namespace: demo-app
labels:
app: backend
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: backend
Apply the configuration
kubectl apply -f demo.yaml
Backend exposes these endpoints:
/api/users - User data (should be accessible to client)
/api/products - Product catalog (restricted from client)
/admin - Admin panel (restricted from everyone except specific apps)
/health - Health check (public)
Generating Traffic
We can visualize the traffic with the Hubble UI at [localhost:12000](http://localhost:12000/). Since this service uses ClusterIP, let's generate some traffic by creating a temporary pod in the same namespace
// create a temp pod
kubectl run client -n demo-app --image=curlimages/curl -- sleep 3600
// exec in to the pod
kubectl -n demo-app exec -it client -- sh
// then generate the traffic
curl http://backend/api/users
curl http://backend/api/products
curl http://backend/admin
From the Hubble dashboard, you can see the client and backend resources. Each request from client to backend appears with multiple records showing different TCP flags like ACK, ACK-FIN, ACK-PSH, SYN, etc.

Now let’s restrict some endpoints using network policies in Cilium.
3. Apply L7 Network Policy
Let’s create a policy that restricts the client to only /api/users and /health
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: backend-l7-policy
namespace: demo-app
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: client
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET"
path: "/api/users"
- method: "GET"
path: "/health"
The explanation is as follows
FOR pods labeled "app: backend" ← endpointSelector
ALLOW incoming traffic ← ingress
FROM pods labeled "app: client" ← fromEndpoints
TO port 8080/TCP ← toPorts
ONLY IF it's an HTTP GET request ← rules.http
TO path "/api/users" OR "/health" ← path
After applying this policy, only /api/users and /health can be reached. Other endpoints will be blocked.

When you test the endpoints, you’ll see that calls to restricted endpoints are dropped, while calls to public endpoints return the expected response.
Note: If you try with another pod that isn’t labeled as app: client, all endpoints will be dropped.
Why This Matters - The eBPF Advantage
Let’s compare this to traditional approaches:
Traditional Network Policies
- Only L3/L4 (IP addresses, ports) — no application-layer awareness
- Cannot inspect HTTP paths, methods, or headers
- Cannot filter gRPC methods, Kafka topics, or DNS queries
- Limited to basic allow/deny rules
Service Mesh Sidecar Proxies (e.g., Istio with Envoy)
- Can do L7 filtering, but requires sidecar containers in every pod
- Packets processed in userspace (multiple context switches)
- Higher resource overhead (CPU, memory per pod)
- Adds complexity to deployment and debugging
Cilium with eBPF
- No sidecars needed
- Kernel-level enforcement
- L7 protocol awareness (HTTP, gRPC, Kafka, DNS, etc.)
- Near-zero overhead
- Real-time observability via Hubble
The magic of eBPF is that it processes packets in the kernel without copying them to userspace. No context switching. No packet copying. Just direct kernel-level processing.
What Else Can Cilium Do?
This demo shows HTTP path filtering, but Cilium’s eBPF can do much more
HTTP Filtering
- Headers matching
- Host-based routing
- Method restrictions
- Status code inspection
Other Protocols
- gRPC method filtering
- Kafka topic access control
- DNS-based policies
- TLS SNI inspection
Conclusion
In this demo, we’ve seen how Cilium uses eBPF to bring application-layer awareness to Kubernetes network policies. What traditionally required either service mesh sidecars or was simply impossible with standard NetworkPolicy objects, Cilium achieves efficiently in the kernel.
Key Takeaways
- eBPF enables L7 protocol awareness without sidecars — reducing complexity and overhead
- Policies are enforced at the kernel level — providing security without application modifications
- Hubble provides comprehensive observability — capturing every flow with minimal performance impact
- No iptables complexity — Cilium’s eBPF datapath is more efficient and easier to debug
By leveraging eBPF, Cilium transforms Kubernetes network security, making it more powerful, more efficient, and simpler to manage.
What’s Next?
This is my first article in the Cilium series. I’ll be publishing more articles exploring advanced Cilium features, real-world use cases, and deep dives into eBPF networking.
Feel free to share your feedback, questions, or experiences with Cilium in the comments below. I especially appreciate constructive feedback; it helps us all learn and grow together.
Stay tuned for the next article in this series!
메타데이터
- post_id
- cfddeb8434cb
- slug
- cilium-network-policies-l7-http-filtering-with-ebpf-on-kubernetes-cfddeb8434cb
- url
- https://medium.com/pickme-engineering-blog/cilium-network-policies-l7-http-filtering-with-ebpf-on-kubernetes-cfddeb8434cb
- canonical_url
- https://medium.com/pickme-engineering-blog/cilium-network-policies-l7-http-filtering-with-ebpf-on-kubernetes-cfddeb8434cb
- author_url
- https://medium.com/@dilandashintha
- status
- ok
- fetched_at
- 2026-06-23 03:48:11