In my previous post I walked through deploying Cilium as the CNI on Azure Kubernetes Service (AKS) and wiring up a simple L7 CiliumNetworkPolicy to control HTTP traffic between pods. That gave us powerful enforcement, but only a limited view into why certain requests were allowed or denied. In this article we’ll focus on the observability side: how to get rich L7 visibility using Hubble (both from the CLI and the web UI).
Table of Contents
Before you start with Hubble
Before you start with Hubble, make sure you have the following in place:
- Cilium installed and in
OKstate (cilium status) kubectlbinary installedazCLI configured andaz aks get-credentialsexecuted sokubectl get nodesworksciliumCLI installed
Hubble Installation
The Cilium CLI can talk to Hubble Relay, but for richer queries I also installed the standalone Hubble CLI:
cd ~
curl -fsSLO https://github.com/cilium/hubble/releases/latest/download/hubble-linux-amd64.tar.gz
tar xzf hubble-linux-amd64.tar.gz
sudo mv hubble /usr/local/bin/hubble
sudo chmod +x /usr/local/bin/hubble
rm hubble-linux-amd64.tar.gz
hubble version
cilium status
Deploying PODs and Cilium L7 Network Policy
Let’s deploy two Pods within the l7-pods namespace:
kubectl create ns l7-pods
kubectl -n l7-pods run web \
--image=nginxdemos/hello \
--port=80 \
--labels app=web
kubectl -n l7-pods run client \
--image=curlimages/curl \
--restart=Never \
--labels app=client \
--command -- sleep 365d
Let’s create and apply L7 network policy (l7-pods-policy.yaml):
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: l7-pods-test
namespace: l7-pods
spec:
endpointSelector:
matchLabels:
app: web
ingress:
- fromEndpoints:
- matchLabels:
app: client
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET"
path: "/allowed$"
kubectl apply -f l7-pods-policy.yaml
Let’s run a couple of checks:
- get the IP of Web Pod
- confirm the Cilium endpoints
kubectl get ciliumendpoints -n l7-pods
Use Hubble to Inspect Dropped flows
First, enable port-forwarding:
cilium hubble port-forward
Cilium L7 Network Policy Test
Open another terminal (#2), observe flows in Hubble CLI:
hubble observe \
--server 127.0.0.1:4245 \
--namespace l7-pods \
--follow
You can focus only on Dropped flows with the parameter: –verdict DROPPED
Hubble CLI
Open another terminal (#3) and generate traffic, e.g.:
kubectl -n l7-pods exec -it client -- curl -s -o /dev/null -w "%{http_code}\n" http://10.0.1.253/
kubectl -n l7-pods exec -it client -- curl -s -o /dev/null -w "%{http_code}\n" http://10.0.1.253/foo
kubectl -n l7-pods exec -it client -- curl -s -o /dev/null -w "%{http_code}\n" http://10.0.1.253/allowed
In terminal #2, you’ll see live flow records:
Hubble UI
The Hubble UI runs in the cluster as a service hubble-ui in the kube-system namespace. All you need locally is a port‑forward.
Open yet another terminal (#4) and execute:
kubectl port-forward -n kube-system svc/hubble-ui 12000:80
Now open your browser and inspect flows in the UI:
http://localhost:12000
The UI gives you a rich view: timeline, verdict, source and destination information (labels, IP, Cilium endpoint ID), and more.
Summary
Cilium extends Kubernetes NetworkPolicy with L7‑aware policies, so you can define intent like “allow only GET /public” instead of just “allow port 80,” significantly strengthening zero‑trust security boundaries.
Hubble complements this by giving rich L7 observability (HTTP methods, paths, status codes, and verdicts) so you can immediately see which requests are allowed or denied.
