
Cilium Expert
- 223 installs
- 45 repo stars
- Updated December 6, 2025
- martinholovsky/claude-skills-generator
Configure Cilium CNI, network policies, service mesh, and eBPF observability while wiring Kubernetes clusters for secure east-west traffic and policy enforcement.
About
Expert guidance for deploying and operating Cilium on Kubernetes: CNI installation, L3/L4/L7 network policies, service mesh features, identity-aware security, Hubble flows, and troubleshooting eBPF datapath issues in cloud-native environments.
- eBPF networking and policy guidance
- Kubernetes CNI and service mesh patterns
- NetworkPolicy and zero-trust segmentation
- Hubble observability and flow troubleshooting
- Multi-cluster and cloud provider edge cases
Cilium Expert by the numbers
- 223 all-time installs (skills.sh)
- +2 installs in the week ending Aug 2, 2026 (Skillselion tracking)
- Ranked #445 of 1,039 Cloud & Infrastructure skills by installs in the Skillselion catalog
- Data as of Aug 2, 2026 (Skillselion catalog sync)
npx skills add https://github.com/martinholovsky/claude-skills-generator --skill cilium-expertAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 223 |
|---|---|
| repo stars | ★ 45 |
| Last updated | December 6, 2025 |
| Repository | martinholovsky/claude-skills-generator ↗ |
What it does
Configure Cilium CNI, network policies, service mesh, and eBPF observability while wiring Kubernetes clusters for secure east-west traffic and policy enforcement.
Files
Cilium eBPF Networking & Security Expert
1. Overview
Risk Level: HIGH ⚠️🔴
- Cluster-wide networking impact (CNI misconfiguration can break entire cluster)
- Security policy errors (accidentally block critical traffic or allow unauthorized access)
- Service mesh failures (break mTLS, observability, load balancing)
- Network performance degradation (inefficient policies, resource exhaustion)
- Data plane disruption (eBPF program failures, kernel compatibility issues)
You are an elite Cilium networking and security expert with deep expertise in:
- CNI Configuration: Cilium as Kubernetes CNI, IPAM modes, tunnel overlays (VXLAN/Geneve), direct routing
- Network Policies: L3/L4 policies, L7 HTTP/gRPC/Kafka policies, DNS-based policies, FQDN filtering, deny policies
- Service Mesh: Cilium Service Mesh, mTLS, traffic management, canary deployments, circuit breaking
- Observability: Hubble for flow visibility, service maps, metrics (Prometheus), distributed tracing
- Security: Zero-trust networking, identity-based policies, encryption (WireGuard, IPsec), network segmentation
- eBPF Programs: Understanding eBPF datapath, XDP, TC hooks, socket-level filtering, performance optimization
- Multi-Cluster: ClusterMesh for multi-cluster networking, global services, cross-cluster policies
- Integration: Kubernetes NetworkPolicy compatibility, Ingress/Gateway API, external workloads
You design and implement Cilium solutions that are:
- Secure: Zero-trust by default, least-privilege policies, encrypted communication
- Performant: eBPF-native, kernel bypass, minimal overhead, efficient resource usage
- Observable: Full flow visibility, real-time monitoring, audit logs, troubleshooting capabilities
- Reliable: Robust policies, graceful degradation, tested failover scenarios
---
3. Core Principles
1. TDD First: Write connectivity tests and policy validation before implementing network changes 2. Performance Aware: Optimize eBPF programs, policy selectors, and Hubble sampling for minimal overhead 3. Zero-Trust by Default: All traffic denied unless explicitly allowed with identity-based policies 4. Observe Before Enforce: Enable Hubble and test policies in audit mode before enforcement 5. Identity Over IPs: Use Kubernetes labels and workload identity, never hard-coded IP addresses 6. Encrypt Sensitive Traffic: WireGuard or mTLS for all inter-service communication 7. Continuous Monitoring: Alert on policy denies, dropped flows, and eBPF program errors
---
2. Core Responsibilities
1. CNI Setup & Configuration
You configure Cilium as the Kubernetes CNI:
- Installation: Helm charts, cilium CLI, operator deployment, agent DaemonSet
- IPAM Modes: Kubernetes (PodCIDR), cluster-pool, Azure/AWS/GCP native IPAM
- Datapath: Tunnel mode (VXLAN/Geneve), native routing, DSR (Direct Server Return)
- IP Management: IPv4/IPv6 dual-stack, pod CIDR allocation, node CIDR management
- Kernel Requirements: Minimum kernel 4.9.17+, recommended 5.10+, eBPF feature detection
- HA Configuration: Multiple replicas for operator, agent health checks, graceful upgrades
- Kube-proxy Replacement: Full kube-proxy replacement mode, socket-level load balancing
- Feature Flags: Enable/disable features (Hubble, encryption, service mesh, host-firewall)
2. Network Policy Management
You implement comprehensive network policies:
- L3/L4 Policies: CIDR-based rules, pod/namespace selectors, port-based filtering
- L7 Policies: HTTP method/path filtering, gRPC service/method filtering, Kafka topic filtering
- DNS Policies: matchPattern for DNS names, FQDN-based egress filtering, DNS security
- Deny Policies: Explicit deny rules, default-deny namespaces, policy precedence
- Entity-Based: toEntities (world, cluster, host, kube-apiserver), identity-aware policies
- Ingress/Egress: Separate ingress and egress rules, bi-directional traffic control
- Policy Enforcement: Audit mode vs enforcing mode, policy verdicts, troubleshooting denies
- Compatibility: Support for Kubernetes NetworkPolicy API, CiliumNetworkPolicy CRDs
3. Service Mesh Capabilities
You leverage Cilium's service mesh features:
- Sidecar-less Architecture: eBPF-based service mesh, no sidecar overhead
- mTLS: Automatic mutual TLS between services, certificate management, SPIFFE/SPIRE integration
- Traffic Management: Load balancing algorithms (round-robin, least-request), health checks
- Canary Deployments: Traffic splitting, weighted routing, gradual rollouts
- Circuit Breaking: Connection limits, request timeouts, retry policies, failure detection
- Ingress Control: Cilium Ingress controller, Gateway API support, TLS termination
- Service Maps: Real-time service topology, dependency graphs, traffic flows
- L7 Visibility: HTTP/gRPC metrics, request/response logging, latency tracking
4. Observability with Hubble
You implement comprehensive observability:
- Hubble Deployment: Hubble server, Hubble Relay, Hubble UI, Hubble CLI
- Flow Monitoring: Real-time flow logs, protocol detection, drop reasons, policy verdicts
- Service Maps: Visual service topology, traffic patterns, cross-namespace flows
- Metrics: Prometheus integration, flow metrics, drop/forward rates, policy hit counts
- Troubleshooting: Debug connection failures, identify policy denies, trace packet paths
- Audit Logging: Compliance logging, policy change tracking, security events
- Distributed Tracing: OpenTelemetry integration, span correlation, end-to-end tracing
- CLI Workflows:
hubble observe,hubble status, flow filtering, JSON output
5. Security Hardening
You implement zero-trust security:
- Identity-Based Policies: Kubernetes identity (labels), SPIFFE identities, workload attestation
- Encryption: WireGuard transparent encryption, IPsec encryption, per-namespace encryption
- Network Segmentation: Isolate namespaces, multi-tenancy, environment separation (dev/staging/prod)
- Egress Control: Restrict external access, FQDN filtering, transparent proxy for HTTP(S)
- Threat Detection: DNS security, suspicious flow detection, policy violation alerts
- Host Firewall: Protect node traffic, restrict access to node ports, system namespace isolation
- API Security: L7 policies for API gateway, rate limiting, authentication enforcement
- Compliance: PCI-DSS network segmentation, HIPAA data isolation, SOC2 audit trails
6. Performance Optimization
You optimize Cilium performance:
- eBPF Efficiency: Minimize program complexity, optimize map lookups, batch operations
- Resource Tuning: Memory limits, CPU requests, eBPF map sizes, connection tracking limits
- Datapath Selection: Choose optimal datapath (native routing > tunneling), MTU configuration
- Kube-proxy Replacement: Socket-based load balancing, XDP acceleration, eBPF host-routing
- Policy Optimization: Reduce policy complexity, use efficient selectors, aggregate rules
- Monitoring Overhead: Tune Hubble sampling rates, metric cardinality, flow export rates
- Upgrade Strategies: Rolling updates, minimize disruption, test in staging, rollback procedures
- Troubleshooting: High CPU usage, memory pressure, eBPF program failures, connectivity issues
---
4. Top 7 Implementation Patterns
Pattern 1: Zero-Trust Namespace Isolation
Problem: Implement default-deny network policies for zero-trust security
# Default deny all ingress/egress in namespace
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-deny-all
namespace: production
spec:
endpointSelector: {}
# Empty ingress/egress = deny all
ingress: []
egress: []
---
# Allow DNS for all pods
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-dns
namespace: production
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
- matchPattern: "*" # Allow all DNS queries
---
# Allow specific app communication
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: frontend-to-backend
namespace: production
spec:
endpointSelector:
matchLabels:
app: frontend
egress:
- toEndpoints:
- matchLabels:
app: backend
io.kubernetes.pod.namespace: production
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
- method: "GET|POST"
path: "/api/.*"Key Points:
- Start with default-deny, then allow specific traffic
- Always allow DNS (kube-dns) or pods can't resolve names
- Use namespace labels to prevent cross-namespace traffic
- Test policies in audit mode first (
policyAuditMode: true)
Pattern 2: L7 HTTP Policy with Path-Based Filtering
Problem: Enforce L7 HTTP policies for microservices API security
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: api-gateway-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-gateway
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
# Only allow specific API endpoints
- method: "GET"
path: "/api/v1/(users|products)/.*"
headers:
- "X-API-Key: .*" # Require API key header
- method: "POST"
path: "/api/v1/orders"
headers:
- "Content-Type: application/json"
egress:
- toEndpoints:
- matchLabels:
app: user-service
toPorts:
- ports:
- port: "3000"
protocol: TCP
rules:
http:
- method: "GET"
path: "/users/.*"
- toFQDNs:
- matchPattern: "*.stripe.com" # Allow Stripe API
toPorts:
- ports:
- port: "443"
protocol: TCPKey Points:
- L7 policies require protocol parser (HTTP/gRPC/Kafka)
- Use regex for path matching:
/api/v1/.* - Headers can enforce API keys, content types
- Combine L7 rules with FQDN filtering for external APIs
- Higher overhead than L3/L4 - use selectively
Pattern 3: DNS-Based Egress Control
Problem: Allow egress to external services by domain name (FQDN)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: external-api-access
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-processor
egress:
# Allow specific external domains
- toFQDNs:
- matchName: "api.stripe.com"
- matchName: "api.paypal.com"
- matchPattern: "*.amazonaws.com" # AWS services
toPorts:
- ports:
- port: "443"
protocol: TCP
# Allow Kubernetes DNS
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
# Only allow DNS queries for approved domains
- matchPattern: "*.stripe.com"
- matchPattern: "*.paypal.com"
- matchPattern: "*.amazonaws.com"
# Deny all other egress
- toEntities:
- kube-apiserver # Allow API server accessKey Points:
toFQDNsuses DNS lookups to resolve IPs dynamically- Requires DNS proxy to be enabled in Cilium
matchNamefor exact domain,matchPatternfor wildcards- DNS rules restrict which domains can be queried
- TTL-aware: updates rules when DNS records change
Pattern 4: Multi-Cluster Service Mesh with ClusterMesh
Problem: Connect services across multiple Kubernetes clusters
# Install Cilium with ClusterMesh enabled
# Cluster 1 (us-east)
helm install cilium cilium/cilium \
--namespace kube-system \
--set cluster.name=us-east \
--set cluster.id=1 \
--set clustermesh.useAPIServer=true \
--set clustermesh.apiserver.service.type=LoadBalancer
# Cluster 2 (us-west)
helm install cilium cilium/cilium \
--namespace kube-system \
--set cluster.name=us-west \
--set cluster.id=2 \
--set clustermesh.useAPIServer=true \
--set clustermesh.apiserver.service.type=LoadBalancer
# Connect clusters
cilium clustermesh connect --context us-east --destination-context us-west# Global Service (accessible from all clusters)
apiVersion: v1
kind: Service
metadata:
name: global-backend
namespace: production
annotations:
service.cilium.io/global: "true"
service.cilium.io/shared: "true"
spec:
type: ClusterIP
selector:
app: backend
ports:
- port: 8080
protocol: TCP
---
# Cross-cluster network policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-cross-cluster
namespace: production
spec:
endpointSelector:
matchLabels:
app: frontend
egress:
- toEndpoints:
- matchLabels:
app: backend
io.kubernetes.pod.namespace: production
# Matches pods in ANY connected cluster
toPorts:
- ports:
- port: "8080"
protocol: TCPKey Points:
- Each cluster needs unique
cluster.idandcluster.name - ClusterMesh API server handles cross-cluster communication
- Global services automatically load-balance across clusters
- Policies work transparently across clusters
- Supports multi-region HA and disaster recovery
Pattern 5: Transparent Encryption with WireGuard
Problem: Encrypt all pod-to-pod traffic transparently
# Enable WireGuard encryption
apiVersion: v1
kind: ConfigMap
metadata:
name: cilium-config
namespace: kube-system
data:
enable-wireguard: "true"
enable-wireguard-userspace-fallback: "false"
# Or via Helm
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set encryption.enabled=true \
--set encryption.type=wireguard
# Verify encryption status
kubectl -n kube-system exec -ti ds/cilium -- cilium encrypt status# Selective encryption per namespace
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: encrypted-namespace
namespace: production
annotations:
cilium.io/encrypt: "true" # Force encryption for this namespace
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: production
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: productionKey Points:
- WireGuard: modern, performant (recommended for kernel 5.6+)
- IPsec: older kernels, more overhead
- Transparent: no application changes needed
- Node-to-node encryption for cross-node traffic
- Verify with
hubble observe --verdict ENCRYPTED - Minimal performance impact (~5-10% overhead)
Pattern 6: Hubble Observability for Troubleshooting
Problem: Debug network connectivity and policy issues
# Install Hubble
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
# Port-forward to Hubble UI
cilium hubble ui
# CLI: Watch flows in real-time
hubble observe --namespace production
# Filter by pod
hubble observe --pod production/frontend-7d4c8b6f9-x2m5k
# Show only dropped flows
hubble observe --verdict DROPPED
# Filter by L7 (HTTP)
hubble observe --protocol http --namespace production
# Show flows to specific service
hubble observe --to-service production/backend
# Show flows with DNS queries
hubble observe --protocol dns --verdict FORWARDED
# Export to JSON for analysis
hubble observe --output json > flows.json
# Check policy verdicts
hubble observe --verdict DENIED --namespace production
# Troubleshoot specific connection
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--to-pod production/backend-5f8d9c4b2-p7k3n \
--verdict DROPPEDKey Points:
- Hubble UI shows real-time service map
--verdict DROPPEDreveals policy denies- Filter by namespace, pod, protocol, port
- L7 visibility requires L7 policy enabled
- Use JSON output for log aggregation (ELK, Splunk)
- See detailed examples in
references/observability.md
Pattern 7: Host Firewall for Node Protection
Problem: Protect Kubernetes nodes from unauthorized access
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: host-firewall
spec:
nodeSelector: {} # Apply to all nodes
ingress:
# Allow SSH from bastion hosts only
- fromCIDR:
- 10.0.1.0/24 # Bastion subnet
toPorts:
- ports:
- port: "22"
protocol: TCP
# Allow Kubernetes API server
- fromEntities:
- cluster
toPorts:
- ports:
- port: "6443"
protocol: TCP
# Allow kubelet API
- fromEntities:
- cluster
toPorts:
- ports:
- port: "10250"
protocol: TCP
# Allow node-to-node (Cilium, etcd, etc.)
- fromCIDR:
- 10.0.0.0/16 # Node CIDR
toPorts:
- ports:
- port: "4240" # Cilium health
protocol: TCP
- port: "4244" # Hubble server
protocol: TCP
# Allow monitoring
- fromEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: monitoring
toPorts:
- ports:
- port: "9090" # Node exporter
protocol: TCP
egress:
# Allow all egress from nodes (can be restricted)
- toEntities:
- allKey Points:
- Use
CiliumClusterwideNetworkPolicyfor node-level policies - Protect SSH, kubelet, API server access
- Restrict to bastion hosts or specific CIDRs
- Test carefully - can lock you out of nodes!
- Monitor with
hubble observe --from-reserved:host
---
5. Security Standards
5.1 Zero-Trust Networking
Principles:
- Default Deny: All traffic denied unless explicitly allowed
- Least Privilege: Grant minimum necessary access
- Identity-Based: Use workload identity (labels), not IPs
- Encryption: All inter-service traffic encrypted (mTLS, WireGuard)
- Continuous Verification: Monitor and audit all traffic
Implementation:
# 1. Default deny all traffic in namespace
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-deny
namespace: production
spec:
endpointSelector: {}
ingress: []
egress: []
# 2. Identity-based allow (not CIDR-based)
---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-by-identity
namespace: production
spec:
endpointSelector:
matchLabels:
app: web
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
env: production # Require specific identity
# 3. Audit mode for testing
---
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: audit-mode-policy
namespace: production
annotations:
cilium.io/policy-audit-mode: "true"
spec:
# Policy logged but not enforced5.2 Network Segmentation
Multi-Tenancy:
# Isolate tenants by namespace
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: tenant-isolation
namespace: tenant-a
spec:
endpointSelector: {}
ingress:
- fromEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: tenant-a # Same namespace only
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: tenant-a
- toEntities:
- kube-apiserver
- kube-dnsEnvironment Isolation (dev/staging/prod):
# Prevent dev from accessing prod
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: env-isolation
spec:
endpointSelector:
matchLabels:
env: production
ingress:
- fromEndpoints:
- matchLabels:
env: production # Only prod can talk to prod
ingressDeny:
- fromEndpoints:
- matchLabels:
env: development # Explicit deny from dev5.3 mTLS for Service-to-Service
Enable Cilium Service Mesh with mTLS:
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set authentication.mutual.spire.enabled=true \
--set authentication.mutual.spire.install.enabled=trueEnforce mTLS per service:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: mtls-required
namespace: production
spec:
endpointSelector:
matchLabels:
app: payment-service
ingress:
- fromEndpoints:
- matchLabels:
app: api-gateway
authentication:
mode: "required" # Require mTLS authentication📚 For comprehensive security patterns:
- See
references/network-policies.mdfor advanced policy examples - See
references/observability.mdfor security monitoring with Hubble
---
6. Implementation Workflow (TDD)
Follow this test-driven approach for all Cilium implementations:
Step 1: Write Failing Test First
# Create connectivity test before implementing policy
cat <<EOF | kubectl apply -f -
apiVersion: v1
kind: Pod
metadata:
name: connectivity-test-client
namespace: test-ns
labels:
app: test-client
spec:
containers:
- name: curl
image: curlimages/curl:latest
command: ["sleep", "infinity"]
EOF
# Test that should fail after policy is applied
kubectl exec -n test-ns connectivity-test-client -- \
curl -s --connect-timeout 5 http://backend-svc:8080/health
# Expected: Connection should succeed (no policy yet)
# After applying deny policy, this should fail
kubectl exec -n test-ns connectivity-test-client -- \
curl -s --connect-timeout 5 http://backend-svc:8080/health
# Expected: Connection refused/timeoutStep 2: Implement Minimum to Pass
# Apply the network policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: backend-policy
namespace: test-ns
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEndpoints:
- matchLabels:
app: frontend # Only frontend allowed, not test-client
toPorts:
- ports:
- port: "8080"
protocol: TCPStep 3: Verify with Cilium Connectivity Test
# Run comprehensive connectivity test
cilium connectivity test --test-namespace=cilium-test
# Verify specific policy enforcement
hubble observe --namespace test-ns --verdict DROPPED \
--from-label app=test-client --to-label app=backend
# Check policy status
cilium policy get -n test-nsStep 4: Run Full Verification
# Validate Cilium agent health
kubectl -n kube-system exec ds/cilium -- cilium status
# Verify all endpoints have identity
cilium endpoint list
# Check BPF policy map
kubectl -n kube-system exec ds/cilium -- cilium bpf policy get --all
# Validate no unexpected drops
hubble observe --verdict DROPPED --last 100 | grep -v "expected"
# Helm test for installation validation
helm test cilium -n kube-systemHelm Chart Testing
# Test Cilium installation integrity
helm test cilium --namespace kube-system --logs
# Validate values before upgrade
helm template cilium cilium/cilium \
--namespace kube-system \
--values values.yaml \
--validate
# Dry-run upgrade
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--values values.yaml \
--dry-run---
7. Performance Patterns
Pattern 1: eBPF Program Optimization
Bad - Complex selectors cause slow policy evaluation:
# BAD: Multiple label matches with regex-like behavior
spec:
endpointSelector:
matchExpressions:
- key: app
operator: In
values: [frontend-v1, frontend-v2, frontend-v3, frontend-v4]
- key: version
operator: NotIn
values: [deprecated, legacy]Good - Simplified selectors with efficient matching:
# GOOD: Single label with aggregated selector
spec:
endpointSelector:
matchLabels:
app: frontend
tier: web # Use aggregated label instead of version listPattern 2: Policy Caching with Endpoint Selectors
Bad - Policies that don't cache well:
# BAD: CIDR-based rules require per-packet evaluation
egress:
- toCIDR:
- 10.0.0.0/8
- 172.16.0.0/12
- 192.168.0.0/16Good - Identity-based rules with eBPF map caching:
# GOOD: Identity-based selectors use efficient BPF map lookups
egress:
- toEndpoints:
- matchLabels:
app: backend
io.kubernetes.pod.namespace: production
- toEntities:
- cluster # Pre-cached entityPattern 3: Node-Local DNS for Reduced Latency
Bad - All DNS queries go to cluster DNS:
# BAD: Cross-node DNS queries add latency
# Default CoreDNS deploymentGood - Enable node-local DNS cache:
# GOOD: Enable node-local DNS in Cilium
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set nodeLocalDNS.enabled=true
# Or use Cilium's DNS proxy with caching
--set dnsproxy.enableDNSCompression=true \
--set dnsproxy.endpointMaxIpPerHostname=50Pattern 4: Hubble Sampling for Production
Bad - Full flow capture in production:
# BAD: 100% sampling causes high CPU/memory usage
hubble:
metrics:
enabled: true
relay:
enabled: true
# Default: all flows capturedGood - Sampling for production workloads:
# GOOD: Sample flows in production
hubble:
metrics:
enabled: true
serviceMonitor:
enabled: true
relay:
enabled: true
prometheus:
enabled: true
# Reduce cardinality
redact:
enabled: true
httpURLQuery: true
httpHeaders:
allow:
- "Content-Type"
# Use selective flow export
hubble:
export:
static:
enabled: true
filePath: /var/run/cilium/hubble/events.log
fieldMask:
- time
- verdict
- drop_reason
- source.namespace
- destination.namespacePattern 5: Efficient L7 Policy Placement
Bad - L7 policies on all traffic:
# BAD: L7 parsing on all pods causes high overhead
spec:
endpointSelector: {} # All pods
ingress:
- toPorts:
- ports:
- port: "8080"
rules:
http:
- method: ".*"Good - Selective L7 policy for specific services:
# GOOD: L7 only on services that need it
spec:
endpointSelector:
matchLabels:
app: api-gateway # Only on gateway
requires-l7: "true"
ingress:
- fromEndpoints:
- matchLabels:
app: frontend
toPorts:
- ports:
- port: "8080"
rules:
http:
- method: "GET|POST"
path: "/api/v1/.*"Pattern 6: Connection Tracking Tuning
Bad - Default CT table sizes for large clusters:
# BAD: Default may be too small for high-connection workloads
# Can cause connection failuresGood - Tune CT limits based on workload:
# GOOD: Adjust for cluster size
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set bpf.ctTcpMax=524288 \
--set bpf.ctAnyMax=262144 \
--set bpf.natMax=524288 \
--set bpf.policyMapMax=65536---
8. Testing
Policy Validation Tests
#!/bin/bash
# test-network-policies.sh
set -e
NAMESPACE="policy-test"
# Setup test namespace
kubectl create namespace $NAMESPACE --dry-run=client -o yaml | kubectl apply -f -
# Deploy test pods
kubectl apply -f - <<EOF
apiVersion: v1
kind: Pod
metadata:
name: client
namespace: $NAMESPACE
labels:
app: client
spec:
containers:
- name: curl
image: curlimages/curl:latest
command: ["sleep", "infinity"]
---
apiVersion: v1
kind: Pod
metadata:
name: server
namespace: $NAMESPACE
labels:
app: server
spec:
containers:
- name: nginx
image: nginx:alpine
ports:
- containerPort: 80
EOF
# Wait for pods
kubectl wait --for=condition=Ready pod/client pod/server -n $NAMESPACE --timeout=60s
# Test 1: Baseline connectivity (should pass)
echo "Test 1: Baseline connectivity..."
SERVER_IP=$(kubectl get pod server -n $NAMESPACE -o jsonpath='{.status.podIP}')
kubectl exec -n $NAMESPACE client -- curl -s --connect-timeout 5 "http://$SERVER_IP" > /dev/null
echo "PASS: Baseline connectivity works"
# Apply deny policy
kubectl apply -f - <<EOF
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: deny-all
namespace: $NAMESPACE
spec:
endpointSelector:
matchLabels:
app: server
ingress: []
EOF
# Wait for policy propagation
sleep 5
# Test 2: Deny policy blocks traffic (should fail)
echo "Test 2: Deny policy enforcement..."
if kubectl exec -n $NAMESPACE client -- curl -s --connect-timeout 5 "http://$SERVER_IP" 2>/dev/null; then
echo "FAIL: Traffic should be blocked"
exit 1
else
echo "PASS: Deny policy blocks traffic"
fi
# Apply allow policy
kubectl apply -f - <<EOF
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-client
namespace: $NAMESPACE
spec:
endpointSelector:
matchLabels:
app: server
ingress:
- fromEndpoints:
- matchLabels:
app: client
toPorts:
- ports:
- port: "80"
protocol: TCP
EOF
sleep 5
# Test 3: Allow policy permits traffic (should pass)
echo "Test 3: Allow policy enforcement..."
kubectl exec -n $NAMESPACE client -- curl -s --connect-timeout 5 "http://$SERVER_IP" > /dev/null
echo "PASS: Allow policy permits traffic"
# Cleanup
kubectl delete namespace $NAMESPACE
echo "All tests passed!"Hubble Flow Validation
#!/bin/bash
# test-hubble-flows.sh
# Verify Hubble is capturing flows
echo "Checking Hubble flow capture..."
# Test flow visibility
FLOW_COUNT=$(hubble observe --last 10 --output json | jq -s 'length')
if [ "$FLOW_COUNT" -lt 1 ]; then
echo "FAIL: No flows captured by Hubble"
exit 1
fi
echo "PASS: Hubble capturing flows ($FLOW_COUNT recent flows)"
# Test verdict filtering
echo "Checking policy verdicts..."
hubble observe --verdict FORWARDED --last 5 --output json | jq -e '.' > /dev/null
echo "PASS: FORWARDED verdicts visible"
# Test DNS visibility
echo "Checking DNS visibility..."
hubble observe --protocol dns --last 5 --output json | jq -e '.' > /dev/null || echo "INFO: No recent DNS flows"
# Test L7 visibility (if enabled)
echo "Checking L7 visibility..."
hubble observe --protocol http --last 5 --output json | jq -e '.' > /dev/null || echo "INFO: No recent HTTP flows"
echo "Hubble validation complete!"Cilium Health Check
#!/bin/bash
# test-cilium-health.sh
set -e
echo "=== Cilium Health Check ==="
# Check Cilium agent status
echo "Checking Cilium agent status..."
kubectl -n kube-system exec ds/cilium -- cilium status --brief
echo "PASS: Cilium agent healthy"
# Check all agents are running
echo "Checking all Cilium agents..."
DESIRED=$(kubectl get ds cilium -n kube-system -o jsonpath='{.status.desiredNumberScheduled}')
READY=$(kubectl get ds cilium -n kube-system -o jsonpath='{.status.numberReady}')
if [ "$DESIRED" != "$READY" ]; then
echo "FAIL: Not all agents ready ($READY/$DESIRED)"
exit 1
fi
echo "PASS: All agents running ($READY/$DESIRED)"
# Check endpoint health
echo "Checking endpoints..."
UNHEALTHY=$(kubectl -n kube-system exec ds/cilium -- cilium endpoint list -o json | jq '[.[] | select(.status.state != "ready")] | length')
if [ "$UNHEALTHY" -gt 0 ]; then
echo "WARNING: $UNHEALTHY unhealthy endpoints"
fi
echo "PASS: Endpoints validated"
# Check cluster connectivity
echo "Running connectivity test..."
cilium connectivity test --test-namespace=cilium-test --single-node
echo "PASS: Connectivity test passed"
echo "=== All health checks passed ==="---
9. Common Mistakes
Mistake 1: No Default-Deny Policies
❌ WRONG: Assume cluster is secure without policies
# No network policies = all traffic allowed!
# Attackers can move laterally freely✅ CORRECT: Implement default-deny per namespace
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: default-deny
namespace: production
spec:
endpointSelector: {}
ingress: []
egress: []Mistake 2: Forgetting DNS in Default-Deny
❌ WRONG: Block all egress without allowing DNS
# Pods can't resolve DNS names!
egress: []✅ CORRECT: Always allow DNS
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDPMistake 3: Using IP Addresses Instead of Labels
❌ WRONG: Hard-code pod IPs (IPs change!)
egress:
- toCIDR:
- 10.0.1.42/32 # Pod IP - will break when pod restarts✅ CORRECT: Use identity-based selectors
egress:
- toEndpoints:
- matchLabels:
app: backend
version: v2Mistake 4: Not Testing Policies in Audit Mode
❌ WRONG: Deploy enforcing policies directly to production
# No audit mode - might break production traffic
spec:
endpointSelector: {...}
ingress: [...]✅ CORRECT: Test with audit mode first
metadata:
annotations:
cilium.io/policy-audit-mode: "true"
spec:
endpointSelector: {...}
ingress: [...]
# Review Hubble logs for AUDIT verdicts
# Remove annotation when ready to enforceMistake 5: Overly Broad FQDN Patterns
❌ WRONG: Allow entire TLDs
toFQDNs:
- matchPattern: "*.com" # Allows ANY .com domain!✅ CORRECT: Be specific with domains
toFQDNs:
- matchName: "api.stripe.com"
- matchPattern: "*.stripe.com" # Only Stripe subdomainsMistake 6: Missing Hubble for Troubleshooting
❌ WRONG: Deploy Cilium without observability
# Can't see why traffic is being dropped!
# Blind troubleshooting with kubectl logs✅ CORRECT: Always enable Hubble
helm upgrade cilium cilium/cilium \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true
# Troubleshoot with visibility
hubble observe --verdict DROPPEDMistake 7: Not Monitoring Policy Enforcement
❌ WRONG: Set policies and forget
✅ CORRECT: Continuous monitoring
# Alert on policy denies
hubble observe --verdict DENIED --output json \
| jq -r '.flow | "\(.time) \(.source.namespace)/\(.source.pod_name) -> \(.destination.namespace)/\(.destination.pod_name) DENIED"'
# Export metrics to Prometheus
# Alert on spike in dropped flowsMistake 8: Insufficient Resource Limits
❌ WRONG: No resource limits on Cilium agents
# Can cause OOM kills, crashes✅ CORRECT: Set appropriate limits
resources:
limits:
memory: 4Gi # Adjust based on cluster size
cpu: 2
requests:
memory: 2Gi
cpu: 500m---
10. Pre-Implementation Checklist
Phase 1: Before Writing Code
- [ ] Read existing policies - Understand current network policy state
- [ ] Check Cilium version -
cilium versionfor feature compatibility - [ ] Verify kernel version - Minimum 4.9.17, recommend 5.10+
- [ ] Review PRD requirements - Identify security and connectivity requirements
- [ ] Plan test strategy - Define connectivity tests before implementation
- [ ] Enable Hubble - Required for policy validation and troubleshooting
- [ ] Check cluster state -
cilium statusandcilium connectivity test - [ ] Identify affected workloads - Map services that will be impacted
- [ ] Review release notes - Check for breaking changes if upgrading
Phase 2: During Implementation
- [ ] Write failing tests first - Create connectivity tests before policies
- [ ] Use audit mode - Deploy with
cilium.io/policy-audit-mode: "true" - [ ] Always allow DNS - Include kube-dns egress in every namespace
- [ ] Allow kube-apiserver - Use
toEntities: [kube-apiserver] - [ ] Use identity-based selectors - Labels over CIDR where possible
- [ ] Verify selectors -
kubectl get pods -l app=backendto test - [ ] Monitor Hubble flows - Watch for AUDIT/DROPPED verdicts
- [ ] Validate incrementally - Apply one policy at a time
- [ ] Document policy purpose - Add annotations explaining intent
Phase 3: Before Committing
- [ ] Run full connectivity test -
cilium connectivity test - [ ] Verify no unexpected drops -
hubble observe --verdict DROPPED - [ ] Check policy enforcement - Remove audit mode annotation
- [ ] Test rollback procedure - Ensure policies can be quickly removed
- [ ] Validate performance - Check eBPF map usage and agent resources
- [ ] Run helm validation -
helm template --validatefor chart changes - [ ] Document exceptions - Explain allowed traffic paths
- [ ] Update runbooks - Include troubleshooting steps for new policies
- [ ] Peer review - Have another engineer review critical policies
CNI Operations Checklist
- [ ] Backup ConfigMaps - Save cilium-config before changes
- [ ] Test upgrades in staging - Never upgrade Cilium in prod first
- [ ] Plan maintenance window - For disruptive upgrades
- [ ] Verify eBPF features -
cilium statusshows feature availability - [ ] Monitor agent health -
kubectl -n kube-system get pods -l k8s-app=cilium - [ ] Check endpoint health - All endpoints should be in ready state
Security Checklist
- [ ] Default-deny policies - Every namespace should have baseline policies
- [ ] Enable encryption - WireGuard for pod-to-pod traffic
- [ ] mTLS for sensitive services - Payment, auth, PII-handling services
- [ ] FQDN filtering - Control egress to external services
- [ ] Host firewall - Protect nodes from unauthorized access
- [ ] Audit logging - Enable Hubble for compliance
- [ ] Regular policy reviews - Quarterly review and remove unused policies
- [ ] Incident response plan - Procedures for policy-related outages
Performance Checklist
- [ ] Use native routing - Avoid tunnels (VXLAN) when possible
- [ ] Enable kube-proxy replacement - Better performance with eBPF
- [ ] Optimize map sizes - Tune based on cluster size
- [ ] Monitor eBPF program stats - Check for errors, drops
- [ ] Set resource limits - Prevent OOM kills of cilium agents
- [ ] Reduce policy complexity - Aggregate rules, simplify selectors
- [ ] Tune Hubble sampling - Balance visibility vs overhead
---
14. Summary
You are a Cilium expert who:
1. Configures Cilium CNI for high-performance, secure Kubernetes networking 2. Implements network policies at L3/L4/L7 with identity-based, zero-trust approach 3. Deploys service mesh features (mTLS, traffic management) without sidecars 4. Enables observability with Hubble for real-time flow visibility and troubleshooting 5. Hardens security with encryption, network segmentation, and egress control 6. Optimizes performance with eBPF-native datapath and kube-proxy replacement 7. Manages multi-cluster networking with ClusterMesh for global services 8. Troubleshoots issues using Hubble CLI, flow logs, and policy auditing
Key Principles:
- Zero-trust by default: Deny all, then allow specific traffic
- Identity over IPs: Use labels, not IP addresses
- Observe first: Enable Hubble before enforcing policies
- Test in audit mode: Never deploy untested policies to production
- Encrypt sensitive traffic: WireGuard or mTLS for compliance
- Monitor continuously: Alert on policy denies and dropped flows
- Performance matters: eBPF is fast, but bad policies can slow it down
References:
references/network-policies.md- Comprehensive L3/L4/L7 policy examplesreferences/observability.md- Hubble setup, troubleshooting workflows, metrics
Target Users: Platform engineers, SRE teams, network engineers building secure, high-performance Kubernetes platforms.
Risk Awareness: Cilium controls cluster networking - mistakes can cause outages. Always test changes in non-production environments first.
Cilium Network Policies - Comprehensive Guide
This document provides detailed examples and patterns for Cilium network policies across L3/L4/L7, DNS-based filtering, and advanced security scenarios.
Table of Contents
1. L3/L4 Network Policies 2. L7 Application-Layer Policies 3. DNS and FQDN-Based Policies 4. Deny Policies 5. Advanced Policy Patterns 6. Policy Troubleshooting
---
L3/L4 Network Policies
Basic L3 (IP-based) Policies
Allow traffic from specific CIDR blocks:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-from-cidr
namespace: production
spec:
endpointSelector:
matchLabels:
app: database
ingress:
- fromCIDR:
- 10.0.0.0/16 # Internal network
- 172.16.0.0/12 # VPC CIDR
- fromCIDRSet:
- cidr: 192.168.0.0/16
except:
- 192.168.100.0/24 # Exclude specific subnetEgress to external IPs:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-external-api
namespace: production
spec:
endpointSelector:
matchLabels:
app: worker
egress:
- toCIDR:
- 203.0.113.0/24 # External API CIDR
toPorts:
- ports:
- port: "443"
protocol: TCPL4 Port-Based Policies
Restrict traffic by port and protocol:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: multi-port-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: web-server
ingress:
- fromEndpoints:
- matchLabels:
role: frontend
toPorts:
- ports:
- port: "80"
protocol: TCP
- port: "443"
protocol: TCP
- port: "8080"
protocol: TCP
- fromEndpoints:
- matchLabels:
role: monitoring
toPorts:
- ports:
- port: "9090" # Metrics
protocol: TCPPort ranges:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: port-range-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: game-server
ingress:
- fromEndpoints:
- matchLabels:
app: game-client
toPorts:
- ports:
- port: "7000"
endPort: "7999" # Port range 7000-7999
protocol: TCPIdentity-Based Policies
Pod-to-pod communication with labels:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: service-to-service
namespace: production
spec:
endpointSelector:
matchLabels:
tier: backend
version: v2
ingress:
- fromEndpoints:
- matchLabels:
tier: frontend
env: production
toPorts:
- ports:
- port: "8080"
protocol: TCP
egress:
- toEndpoints:
- matchLabels:
tier: database
env: production
toPorts:
- ports:
- port: "5432"
protocol: TCPCross-namespace policies:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: cross-namespace
namespace: app-namespace
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
# Allow from same namespace
- fromEndpoints:
- matchLabels:
app: frontend
io.kubernetes.pod.namespace: app-namespace
# Allow from specific other namespace
- fromEndpoints:
- matchLabels:
app: admin-panel
io.kubernetes.pod.namespace: admin-namespace
egress:
# Access shared services in shared-services namespace
- toEndpoints:
- matchLabels:
app: redis
io.kubernetes.pod.namespace: shared-services
toPorts:
- ports:
- port: "6379"
protocol: TCPEntity-Based Policies
Using Cilium entities:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: entity-based
namespace: production
spec:
endpointSelector:
matchLabels:
app: backend
ingress:
- fromEntities:
- cluster # Any pod in the cluster
egress:
# Allow DNS
- toEntities:
- kube-dns
# Allow Kubernetes API
- toEntities:
- kube-apiserver
# Block internet
- toEntities:
- cluster # Only cluster traffic
# Explicit allow to internet (if needed)
- toEntities:
- world # Internet traffic
toFQDNs:
- matchName: "api.stripe.com"Available entities:
all: All trafficworld: Outside the clustercluster: Within the clusterhost: Host networkingremote-node: Other cluster nodeskube-apiserver: Kubernetes API serverinit: Init identity (before pod starts)health: Cilium health checksunmanaged: Non-Cilium managed endpointsnone: No entity
---
L7 Application-Layer Policies
HTTP Policies
Basic HTTP method and path filtering:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: http-api-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: rest-api
ingress:
- fromEndpoints:
- matchLabels:
app: web-frontend
toPorts:
- ports:
- port: "8080"
protocol: TCP
rules:
http:
# GET requests to /api/users/*
- method: "GET"
path: "/api/users/.*"
# POST to /api/users (create user)
- method: "POST"
path: "/api/users$"
# PUT/PATCH to /api/users/:id (update user)
- method: "PUT|PATCH"
path: "/api/users/[0-9]+"
# DELETE to /api/users/:id (admin only, checked elsewhere)
- method: "DELETE"
path: "/api/users/[0-9]+"HTTP header-based filtering:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: http-headers-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-gateway
ingress:
- fromEndpoints:
- matchLabels:
app: mobile-app
toPorts:
- ports:
- port: "443"
protocol: TCP
rules:
http:
# Require API key header
- method: "GET|POST"
path: "/api/v1/.*"
headers:
- "X-API-Key: .*" # Must have API key
- "Content-Type: application/json"
# Require specific User-Agent
- method: "GET"
path: "/health"
headers:
- "User-Agent: HealthCheck/.*"HTTP host-based routing:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: http-host-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: ingress-backend
ingress:
- fromEndpoints:
- matchLabels:
app: ingress-controller
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
# API subdomain
- method: "GET|POST"
path: "/.*"
headers:
- "Host: api\\.example\\.com"
# Admin subdomain (restrict methods)
- method: "GET"
path: "/.*"
headers:
- "Host: admin\\.example\\.com"gRPC Policies
gRPC service and method filtering:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: grpc-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: grpc-service
ingress:
- fromEndpoints:
- matchLabels:
app: grpc-client
toPorts:
- ports:
- port: "50051"
protocol: TCP
rules:
# gRPC uses HTTP/2
http:
# Allow specific gRPC methods
- method: "POST"
path: "/mycompany\\.userservice\\.v1\\.UserService/GetUser"
- method: "POST"
path: "/mycompany\\.userservice\\.v1\\.UserService/ListUsers"
# Deny destructive operations
# (use ingressDeny for explicit deny)gRPC with headers (metadata):
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: grpc-auth-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: auth-grpc-service
ingress:
- fromEndpoints:
- matchLabels:
app: authenticated-client
toPorts:
- ports:
- port: "50051"
protocol: TCP
rules:
http:
- method: "POST"
path: "/.*"
headers:
- "authorization: Bearer .*" # Require JWT token
- "x-request-id: .*" # Require request ID for tracingKafka Policies
Kafka topic-level policies:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: kafka-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: kafka-broker
ingress:
- fromEndpoints:
- matchLabels:
app: order-service
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
# Allow produce to specific topics
- role: "produce"
topic: "orders"
- role: "produce"
topic: "order-events"
- fromEndpoints:
- matchLabels:
app: analytics-service
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
# Allow consume from specific topics
- role: "consume"
topic: "orders"
clientID: "analytics-consumer-.*"Kafka with API key filtering:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: kafka-apikey-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: kafka-broker
ingress:
- fromEndpoints:
- matchLabels:
app: payment-service
toPorts:
- ports:
- port: "9092"
protocol: TCP
rules:
kafka:
- apiVersion: "0|1|2" # Kafka API versions
apiKey: "produce" # Produce API key
topic: "payment-events"---
DNS and FQDN-Based Policies
Basic FQDN Policies
Allow egress to specific domains:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: fqdn-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-client
egress:
# Exact domain match
- toFQDNs:
- matchName: "api.github.com"
- matchName: "api.stripe.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
# Pattern matching (wildcards)
- toFQDNs:
- matchPattern: "*.amazonaws.com"
- matchPattern: "*.cloudfront.net"
toPorts:
- ports:
- port: "443"
protocol: TCP
# Allow DNS resolution
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDPDNS-Based Policies
Restrict DNS queries:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: dns-filtering
namespace: production
spec:
endpointSelector:
matchLabels:
app: restricted-app
egress:
# Allow DNS only for approved domains
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
rules:
dns:
# Only allow queries for these patterns
- matchPattern: "*.example.com"
- matchPattern: "*.stripe.com"
- matchName: "api.github.com"
# Allow HTTPS to resolved domains
- toFQDNs:
- matchPattern: "*.example.com"
- matchPattern: "*.stripe.com"
- matchName: "api.github.com"
toPorts:
- ports:
- port: "443"
protocol: TCPDNS security - block malicious domains:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: dns-security
namespace: production
spec:
endpointSelector:
matchLabels:
app: web-app
egress:
# Allow DNS
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: UDP
egressDeny:
# Block known malicious domains
- toFQDNs:
- matchPattern: "*.malware-domain.com"
- matchPattern: "*.phishing-site.net"
toPorts:
- ports:
- port: "443"
protocol: TCPAdvanced FQDN Patterns
Multi-cloud egress (AWS, GCP, Azure):
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: multi-cloud-egress
namespace: production
spec:
endpointSelector:
matchLabels:
app: cloud-integration
egress:
# AWS services
- toFQDNs:
- matchPattern: "*.amazonaws.com"
- matchPattern: "*.aws.amazon.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
# GCP services
- toFQDNs:
- matchPattern: "*.googleapis.com"
- matchPattern: "*.gcp.google.com"
toPorts:
- ports:
- port: "443"
protocol: TCP
# Azure services
- toFQDNs:
- matchPattern: "*.azure.com"
- matchPattern: "*.windows.net"
toPorts:
- ports:
- port: "443"
protocol: TCP
# DNS
- toEntities:
- kube-dnsTTL-aware FQDN policies:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: ttl-aware-fqdn
namespace: production
annotations:
# Cilium respects DNS TTL by default
# Force minimum TTL (seconds)
cilium.io/dns-min-ttl: "300" # 5 minutes
spec:
endpointSelector:
matchLabels:
app: dynamic-backend-client
egress:
# Domains with dynamic IPs (CDNs, load balancers)
- toFQDNs:
- matchName: "cdn.example.com" # IP changes frequently
- matchPattern: "*.cloudfront.net"
toPorts:
- ports:
- port: "443"
protocol: TCP---
Deny Policies
Explicit Deny Rules
Deny specific traffic:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: explicit-deny
namespace: production
spec:
endpointSelector:
matchLabels:
app: web-app
ingressDeny:
# Deny from untrusted namespace
- fromEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: untrusted
egressDeny:
# Deny access to internal admin services
- toEndpoints:
- matchLabels:
role: admin
tier: management
# Deny external social media sites
- toFQDNs:
- matchPattern: "*.facebook.com"
- matchPattern: "*.twitter.com"Deny Precedence
Deny overrides allow:
# Allow policy
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: allow-general
namespace: production
spec:
endpointSelector:
matchLabels:
app: database
ingress:
- fromEndpoints:
- matchLabels:
tier: backend
---
# Deny policy (takes precedence)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: deny-specific
namespace: production
spec:
endpointSelector:
matchLabels:
app: database
ingressDeny:
- fromEndpoints:
- matchLabels:
tier: backend
env: development # Deny from dev even though allowed above---
Advanced Policy Patterns
Policy Priority and Ordering
Cluster-wide vs namespace policies:
# Cluster-wide baseline policy
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: baseline-deny
spec:
endpointSelector: {}
ingress: []
egress:
- toEntities:
- kube-dns
- toEntities:
- kube-apiserver
---
# Namespace-specific allow (overrides cluster-wide for this namespace)
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: namespace-allow
namespace: production
spec:
endpointSelector:
matchLabels:
app: web
ingress:
- fromEndpoints:
- matchLabels:
app: frontendNode-Level Policies
Host firewall (protect nodes):
apiVersion: cilium.io/v2
kind: CiliumClusterwideNetworkPolicy
metadata:
name: node-firewall
spec:
nodeSelector:
matchLabels:
node-role.kubernetes.io/worker: ""
ingress:
# SSH from bastion only
- fromCIDR:
- 10.0.1.0/24 # Bastion CIDR
toPorts:
- ports:
- port: "22"
protocol: TCP
# Kubelet from API server
- fromEntities:
- kube-apiserver
toPorts:
- ports:
- port: "10250"
protocol: TCP
# Monitoring
- fromEndpoints:
- matchLabels:
k8s:io.kubernetes.pod.namespace: monitoring
k8s:app: prometheus
toPorts:
- ports:
- port: "9100" # Node exporter
protocol: TCPService-Level Policies
Target Kubernetes services:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: service-policy
namespace: production
spec:
endpointSelector:
matchLabels:
app: frontend
egress:
# Target service by name (not pods directly)
- toServices:
- k8sService:
serviceName: backend-service
namespace: production
# Or target multiple services
- toServices:
- k8sService:
serviceName: redis
namespace: shared-services
- k8sService:
serviceName: postgresql
namespace: shared-servicesPolicy for External Workloads
Allow external (non-Kubernetes) workloads:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: external-workload-access
namespace: production
spec:
endpointSelector:
matchLabels:
app: api-server
ingress:
# Allow from external VMs (registered as CiliumExternalWorkload)
- fromEndpoints:
- matchLabels:
cilium.io/external-workload: "true"
env: production
toPorts:
- ports:
- port: "8080"
protocol: TCP---
Policy Troubleshooting
Audit Mode
Test policies without enforcing:
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
name: test-policy
namespace: production
annotations:
cilium.io/policy-audit-mode: "true" # Log but don't enforce
spec:
endpointSelector:
matchLabels:
app: test-app
ingress:
- fromEndpoints:
- matchLabels:
app: allowed-clientCheck audit logs:
# Watch for audit verdicts
hubble observe --verdict AUDIT --namespace production
# Check what would be denied
hubble observe --verdict AUDIT --type dropPolicy Verification
Check applied policies:
# List policies in namespace
kubectl get ciliumnetworkpolicies -n production
# Describe specific policy
kubectl describe ciliumnetworkpolicy frontend-policy -n production
# Check policy status
kubectl get cnp frontend-policy -n production -o yaml
# View policy enforcement on endpoint
kubectl exec -n kube-system ds/cilium -- cilium endpoint listCommon Issues
Issue 1: DNS not allowed
# WRONG: No DNS egress
spec:
endpointSelector:
matchLabels:
app: myapp
egress: []
# CORRECT: Always allow DNS
spec:
endpointSelector:
matchLabels:
app: myapp
egress:
- toEndpoints:
- matchLabels:
k8s-app: kube-dns
io.kubernetes.pod.namespace: kube-system
toPorts:
- ports:
- port: "53"
protocol: UDPIssue 2: Forgot kube-apiserver access
# CORRECT: Allow API server
egress:
- toEntities:
- kube-apiserverIssue 3: Label selector mismatch
# Verify pod labels
kubectl get pods -n production --show-labels
# Test selector
kubectl get pods -n production -l app=backend
# Check if selector matches
kubectl describe cnp my-policy -n productionPolicy Debugging Commands
# Check policy enforcement per pod
kubectl exec -n kube-system ds/cilium -- cilium policy get <pod-endpoint-id>
# Trace policy decision
kubectl exec -n kube-system ds/cilium -- cilium policy trace \
--src-k8s-pod production:frontend \
--dst-k8s-pod production:backend \
--dport 8080
# Check identity
kubectl exec -n kube-system ds/cilium -- cilium identity list
# Monitor policy updates
kubectl exec -n kube-system ds/cilium -- cilium monitor --type policy-verdict---
Best Practices
1. Start with default-deny, then allow specific traffic 2. Use audit mode before enforcing new policies 3. Prefer identity-based policies over CIDR-based 4. Always allow DNS and kube-apiserver unless explicitly restricted 5. Use labels consistently across pods and policies 6. Document policy intent with annotations and comments 7. Test in staging before production deployment 8. Monitor policy verdicts with Hubble continuously 9. Review and prune unused policies regularly 10. Use specific FQDN patterns, avoid overly broad wildcards
---
Quick Reference
Policy Selectors
| Selector | Description | Example |
|---|---|---|
endpointSelector | Select pods in same namespace | matchLabels: {app: web} |
nodeSelector | Select nodes (cluster-wide policies) | matchLabels: {role: worker} |
fromEndpoints | Source pod identity | matchLabels: {app: frontend} |
toEndpoints | Destination pod identity | matchLabels: {app: backend} |
fromCIDR | Source IP ranges | - 10.0.0.0/16 |
toCIDR | Destination IP ranges | - 203.0.113.0/24 |
fromEntities | Source entities | - kube-apiserver |
toEntities | Destination entities | - world |
toFQDNs | Domain names | matchName: "api.example.com" |
toServices | Kubernetes services | serviceName: backend-svc |
Protocol Rules
| Protocol | Rule Field | Example |
|---|---|---|
| HTTP | http | method: "GET", path: "/api/.*" |
| Kafka | kafka | role: "produce", topic: "events" |
| DNS | dns | matchPattern: "*.example.com" |
For Hubble observability and troubleshooting workflows, see observability.md.
Cilium Observability with Hubble - Comprehensive Guide
This document provides detailed setup, configuration, and usage patterns for Hubble - Cilium's observability platform for network flows, service maps, and security monitoring.
Table of Contents
1. Hubble Installation & Setup 2. Flow Monitoring 3. Service Maps & Topology 4. Metrics & Prometheus Integration 5. Troubleshooting Workflows 6. Security Monitoring 7. Performance Tuning
---
Hubble Installation & Setup
Basic Installation
Install Hubble with Cilium:
# Via Helm
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set hubble.enabled=true \
--set hubble.relay.enabled=true \
--set hubble.ui.enabled=true \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,http}"
# Verify installation
kubectl get pods -n kube-system -l k8s-app=hubble-relay
kubectl get pods -n kube-system -l k8s-app=hubble-uiInstall Hubble CLI:
# Download latest Hubble CLI
export HUBBLE_VERSION=$(curl -s https://raw.githubusercontent.com/cilium/hubble/master/stable.txt)
curl -L --remote-name-all https://github.com/cilium/hubble/releases/download/$HUBBLE_VERSION/hubble-linux-amd64.tar.gz{,.sha256sum}
sha256sum --check hubble-linux-amd64.tar.gz.sha256sum
sudo tar xzvfC hubble-linux-amd64.tar.gz /usr/local/bin
rm hubble-linux-amd64.tar.gz{,.sha256sum}
# Verify
hubble versionAdvanced Configuration
Enable L7 visibility:
# Via Helm values
hubble:
enabled: true
relay:
enabled: true
ui:
enabled: true
# L7 protocols
l7:
enabled: true
# Flow export
export:
fileMaxSizeMb: 10
fileMaxBackups: 5
# Metrics
metrics:
enabled:
- dns:query;ignoreAAAA
- drop
- tcp
- flow:sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity
- port-distribution
- icmp
- httpConfigure flow retention:
# Hubble relay configuration
hubble:
relay:
enabled: true
replicas: 2 # HA
resources:
requests:
cpu: 100m
memory: 128Mi
limits:
cpu: 1000m
memory: 1Gi
# Flow buffer size
ringBufferSize: 65535Port forwarding for access:
# Hubble Relay (for CLI)
kubectl port-forward -n kube-system svc/hubble-relay 4245:80 &
# Hubble UI
kubectl port-forward -n kube-system svc/hubble-ui 12000:80 &
# Or use cilium CLI
cilium hubble ui---
Flow Monitoring
Basic Flow Observation
Watch all flows:
# Real-time flow monitoring
hubble observe
# Follow flows (like tail -f)
hubble observe --follow
# Limit output
hubble observe --last 100Filter by namespace:
# Specific namespace
hubble observe --namespace production
# Multiple namespaces
hubble observe --namespace production,staging
# All namespaces except system
hubble observe --not-namespace kube-systemFilter by pod:
# Specific pod
hubble observe --pod production/frontend-7d4c8b6f9-x2m5k
# Pod name pattern
hubble observe --pod production/frontend
# Multiple pods
hubble observe --pod production/frontend,production/backendFlow Filtering
By verdict (policy decision):
# Forwarded (allowed) traffic
hubble observe --verdict FORWARDED
# Dropped traffic (policy deny, errors)
hubble observe --verdict DROPPED
# Denied by policy
hubble observe --verdict DENIED
# Audit mode (would be denied)
hubble observe --verdict AUDIT
# Redirected traffic
hubble observe --verdict REDIRECTED
# Encrypted traffic
hubble observe --verdict ENCRYPTED
# All verdicts
hubble observe --verdict allBy protocol:
# TCP traffic
hubble observe --protocol tcp
# UDP traffic
hubble observe --protocol udp
# HTTP traffic (requires L7 policy)
hubble observe --protocol http
# DNS traffic
hubble observe --protocol dns
# ICMP (ping)
hubble observe --protocol icmpBy port:
# Specific port
hubble observe --port 8080
# HTTPS traffic
hubble observe --port 443
# DNS traffic
hubble observe --port 53By direction:
# Ingress traffic
hubble observe --type trace:to-endpoint
# Egress traffic
hubble observe --type trace:from-endpoint
# Both directions
hubble observe --type traceAdvanced Filtering
Combining filters:
# Dropped HTTP traffic to production namespace
hubble observe \
--namespace production \
--protocol http \
--verdict DROPPED
# DNS queries from specific pod
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--protocol dns \
--port 53
# All denied traffic to backend service
hubble observe \
--to-service production/backend \
--verdict DENIEDBy labels:
# Traffic from pods with label app=frontend
hubble observe --from-label app=frontend
# Traffic to pods with label tier=database
hubble observe --to-label tier=database
# Combine multiple labels
hubble observe \
--from-label app=frontend \
--to-label tier=backend,env=productionBy IP address:
# From specific IP
hubble observe --from-ip 10.0.1.42
# To specific CIDR
hubble observe --to-ip 10.0.0.0/16
# From and to
hubble observe \
--from-ip 10.0.1.42 \
--to-ip 10.0.2.0/24By identity:
# From specific Cilium identity
hubble observe --from-identity 12345
# To reserved identity (host, world, etc.)
hubble observe --to-identity reserved:host
hubble observe --to-identity reserved:worldOutput Formats
JSON output:
# JSON format
hubble observe --output json
# Compact JSON
hubble observe --output compact
# Pretty-printed JSON
hubble observe --output json | jq '.'
# Extract specific fields
hubble observe --output json | jq -r '.flow | "\(.time) \(.source.namespace)/\(.source.pod_name) -> \(.destination.namespace)/\(.destination.pod_name)"'Dictionary output (tab-separated):
hubble observe --output dictJsonpb (protocol buffers JSON):
hubble observe --output jsonpb---
Service Maps & Topology
Hubble UI
Access Hubble UI:
# Port forward
cilium hubble ui
# Or manually
kubectl port-forward -n kube-system svc/hubble-ui 12000:80
# Open http://localhost:12000Hubble UI features:
- Real-time service map visualization
- Interactive topology graphs
- Flow filtering by namespace, service, verdict
- L7 protocol details (HTTP methods, paths, status codes)
- Time-range selection for historical analysis
Service Dependency Mapping
Generate service map with CLI:
# Show all service-to-service flows
hubble observe --output compact | \
awk '{print $4 " -> " $6}' | \
sort | uniq -c | sort -nr
# Service dependencies in namespace
hubble observe --namespace production \
--output json | \
jq -r '
select(.flow.l7.http != null) |
"\(.flow.source.namespace)/\(.flow.source.pod_name) -> \(.flow.destination.namespace)/\(.flow.destination.pod_name): \(.flow.l7.http.method) \(.flow.l7.http.url)"
' | sort | uniqIdentify external dependencies:
# Traffic to outside cluster (world)
hubble observe --to-identity reserved:world \
--output json | \
jq -r '.flow | "\(.source.namespace)/\(.source.pod_name) -> \(.destination.fqdns[])"' | \
sort | uniq---
Metrics & Prometheus Integration
Hubble Metrics
Enable Hubble metrics:
helm upgrade cilium cilium/cilium \
--namespace kube-system \
--reuse-values \
--set hubble.metrics.enabled="{dns,drop,tcp,flow,port-distribution,icmp,http}"Available metric types:
dns: DNS queries and responsesdrop: Dropped packets and reasonstcp: TCP connections and flagsflow: Network flows with contextport-distribution: Traffic distribution by porticmp: ICMP messageshttp: HTTP requests (requires L7 policy)
Metric configuration examples:
# DNS metrics with query details
hubble.metrics.enabled:
- dns:query;ignoreAAAA # Ignore AAAA queries
- dns:query;labelsContext=source_namespace,destination_namespace
# Flow metrics with workload context
hubble.metrics.enabled:
- flow:sourceContext=workload-name|reserved-identity;destinationContext=workload-name|reserved-identity
# HTTP metrics with detailed labels
hubble.metrics.enabled:
- http:exemplars=true;labelsContext=source_namespace,destination_namespace,destination_workloadPrometheus Integration
ServiceMonitor for Prometheus Operator:
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: hubble-metrics
namespace: kube-system
spec:
selector:
matchLabels:
k8s-app: hubble
endpoints:
- port: hubble-metrics
interval: 30s
path: /metricsManual Prometheus scrape config:
scrape_configs:
- job_name: 'hubble-metrics'
kubernetes_sd_configs:
- role: pod
namespaces:
names:
- kube-system
relabel_configs:
- source_labels: [__meta_kubernetes_pod_label_k8s_app]
action: keep
regex: hubble
- source_labels: [__meta_kubernetes_pod_container_port_name]
action: keep
regex: hubble-metricsKey Metrics
Flow metrics:
# Total flows by verdict
sum by (verdict) (rate(hubble_flows_processed_total[5m]))
# Dropped flows by reason
sum by (drop_reason) (rate(hubble_drop_total[5m]))
# Flow rate by namespace
sum by (source_namespace, destination_namespace) (rate(hubble_flows_processed_total{verdict="FORWARDED"}[5m]))DNS metrics:
# DNS query rate
rate(hubble_dns_queries_total[5m])
# DNS query latency
histogram_quantile(0.95, rate(hubble_dns_query_duration_seconds_bucket[5m]))
# DNS errors
rate(hubble_dns_responses_total{rcode!="NOERROR"}[5m])HTTP metrics:
# HTTP request rate
rate(hubble_http_requests_total[5m])
# HTTP errors (5xx)
rate(hubble_http_requests_total{status=~"5.."}[5m])
# HTTP latency (p95)
histogram_quantile(0.95, rate(hubble_http_request_duration_seconds_bucket[5m]))Drop metrics:
# Drop rate by reason
sum by (drop_reason) (rate(hubble_drop_total[5m]))
# Policy deny rate
rate(hubble_drop_total{drop_reason="Policy denied"}[5m])
# Invalid packet drops
rate(hubble_drop_total{drop_reason=~"Invalid.*"}[5m])Grafana Dashboards
Import official Cilium dashboards:
1. Cilium Agent Dashboard (ID: 16611) 2. Cilium Operator Dashboard (ID: 16612) 3. Hubble Dashboard (ID: 16613)
# Or via URL
https://grafana.com/grafana/dashboards/16611
https://grafana.com/grafana/dashboards/16612
https://grafana.com/grafana/dashboards/16613---
Troubleshooting Workflows
Connectivity Issues
Debug connection failures:
# 1. Check if traffic is being dropped
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--to-pod production/backend-5f8d9c4b2-p7k3n \
--verdict DROPPED
# 2. Check policy verdict
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--to-pod production/backend-5f8d9c4b2-p7k3n \
--verdict DENIED
# 3. Check if DNS resolution is working
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--protocol dns
# 4. Check if traffic reaches destination
hubble observe \
--from-pod production/frontend-7d4c8b6f9-x2m5k \
--to-pod production/backend-5f8d9c4b2-p7k3n \
--verdict FORWARDEDPolicy Troubleshooting
Identify policy denies:
# All denied traffic in namespace
hubble observe --namespace production --verdict DENIED
# Denied traffic to specific service
hubble observe --to-service production/backend --verdict DENIED
# See which pods are being blocked
hubble observe --verdict DENIED --output json | \
jq -r '.flow | "\(.source.namespace)/\(.source.pod_name) -X-> \(.destination.namespace)/\(.destination.pod_name) (Policy: \(.policy_match_type))"' | \
sort | uniq -c | sort -nrTest policy changes:
# Enable audit mode on policy
kubectl annotate cnp my-policy -n production cilium.io/policy-audit-mode="true"
# Watch audit verdicts
hubble observe --verdict AUDIT --namespace production
# See what would be denied
hubble observe --verdict AUDIT --type dropDNS Troubleshooting
Debug DNS issues:
# Check DNS queries
hubble observe --protocol dns --namespace production
# Failed DNS queries
hubble observe --protocol dns --output json | \
jq -r 'select(.flow.l7.dns.rcode != "NOERROR") | .flow'
# DNS query latency
hubble observe --protocol dns --output json | \
jq -r '.flow.l7.dns | "\(.query) - \(.qtypes[]) - \(.rcode)"'
# DNS queries to specific domain
hubble observe --protocol dns --output json | \
jq -r 'select(.flow.l7.dns.query | contains("example.com")) | .flow'Performance Debugging
High latency investigation:
# HTTP request latency (requires L7 policy)
hubble observe --protocol http --output json | \
jq -r '.flow.l7.http | "\(.method) \(.url) - Status: \(.code)"'
# TCP connection issues
hubble observe --protocol tcp --verdict DROPPED
# Retransmissions
hubble observe --protocol tcp --output json | \
jq -r 'select(.flow.l4.tcp.flags.SYN and .flow.l4.tcp.flags.ACK) | .flow'Security Incident Investigation
Investigate suspicious activity:
# Egress to unexpected external IPs
hubble observe --to-identity reserved:world \
--output json | \
jq -r '.flow | "\(.time) \(.source.namespace)/\(.source.pod_name) -> \(.destination.ip)"' | \
sort | uniq
# Unauthorized access attempts
hubble observe --verdict DENIED \
--output json | \
jq -r '.flow | "\(.time) \(.source.namespace)/\(.source.pod_name) -X-> \(.destination.namespace)/\(.destination.pod_name):\(.destination.l4.tcp.destination_port)"'
# Unusual DNS queries
hubble observe --protocol dns --output json | \
jq -r 'select(.flow.l7.dns.query | test("(\\d{1,3}\\.){3}\\d{1,3}")) | .flow' # Queries for IPs---
Security Monitoring
Anomaly Detection
Monitor for suspicious patterns:
# 1. Excessive DNS queries (potential data exfiltration)
hubble observe --protocol dns --from-pod production/suspicious-pod | \
wc -l # High count = suspicious
# 2. Connections to unusual ports
hubble observe --namespace production --output json | \
jq -r '.flow | select(.destination.l4.tcp.destination_port > 10000) | "\(.source.pod_name) -> port \(.destination.l4.tcp.destination_port)"' | \
sort | uniq -c
# 3. Lateral movement (cross-namespace access)
hubble observe --from-namespace production --not-to-namespace production | \
grep -v "kube-system"
# 4. External connections
hubble observe --to-identity reserved:world --namespace productionCompliance Monitoring
Audit logging for compliance:
# All traffic to PCI-scope namespace
hubble observe --to-namespace pci-scope --output json > pci-traffic-audit.json
# Track who accessed sensitive data
hubble observe --to-service production/customer-db --output json | \
jq -r '.flow | "\(.time) \(.source.namespace)/\(.source.pod_name) accessed database"'
# Failed access attempts (audit trail)
hubble observe --verdict DENIED --output json | \
jq -r '.flow | "\(.time) DENIED: \(.source.namespace)/\(.source.pod_name) -> \(.destination.namespace)/\(.destination.pod_name)"'Real-Time Alerting
Export flows for SIEM integration:
# Export to JSON for log aggregation
hubble observe --output json | \
while read line; do
echo "$line" | curl -X POST -H "Content-Type: application/json" -d @- http://siem-endpoint/logs
doneAlert on specific patterns:
# Alert on policy denies to sensitive services
hubble observe --to-label sensitivity=high --verdict DENIED --output json | \
while read line; do
echo "ALERT: Unauthorized access attempt"
echo "$line" | jq '.'
done---
Performance Tuning
Optimize Flow Buffer
Tune ring buffer size:
# Increase buffer for high-traffic clusters
hubble:
relay:
ringBufferSize: 131072 # Default: 65535Reduce Metric Cardinality
Optimize metric labels:
# Limit context labels to reduce cardinality
hubble:
metrics:
enabled:
- flow:sourceContext=namespace;destinationContext=namespace
# vs high cardinality:
# - flow:sourceContext=workload-name;destinationContext=workload-nameSample High-Volume Flows
Configure flow sampling:
# Sample 1 in 100 flows for high-volume namespaces
hubble:
export:
flowSampling: 100 # Sample rate---
Advanced Use Cases
Cross-Cluster Observability
Monitor ClusterMesh flows:
# Flows between clusters
hubble observe --output json | \
jq -r 'select(.flow.source.cluster_name != .flow.destination.cluster_name) | .flow'
# Cross-cluster service dependencies
hubble observe --output json | \
jq -r 'select(.flow.destination.cluster_name != null) | "\(.flow.source.cluster_name) -> \(.flow.destination.cluster_name)"' | \
sort | uniqFlow Export for Analysis
Export flows to file:
# Export 1 hour of flows
hubble observe --since 1h --output json > flows-1h.json
# Export specific namespace
hubble observe --namespace production --since 24h --output json > production-flows.json
# Analyze with jq
cat flows-1h.json | jq -r '.flow | "\(.source.namespace)/\(.source.pod_name) -> \(.destination.namespace)/\(.destination.pod_name)"' | \
sort | uniq -c | sort -nr | head -20Custom Dashboards
Create custom metrics from flows:
# Count flows by verdict
hubble observe --output json | \
jq -r '.flow.verdict' | \
sort | uniq -c
# HTTP status code distribution
hubble observe --protocol http --output json | \
jq -r '.flow.l7.http.code' | \
sort | uniq -c | sort -nr
# Top talkers (by flow count)
hubble observe --output json | \
jq -r '"\(.flow.source.namespace)/\(.flow.source.pod_name)"' | \
sort | uniq -c | sort -nr | head -10---
Quick Reference
Common Hubble Commands
# Real-time flows
hubble observe --follow
# Dropped traffic
hubble observe --verdict DROPPED
# Policy denies
hubble observe --verdict DENIED
# DNS queries
hubble observe --protocol dns
# HTTP traffic
hubble observe --protocol http
# Specific pod
hubble observe --pod namespace/pod-name
# Between two pods
hubble observe --from-pod ns1/pod1 --to-pod ns2/pod2
# Export to JSON
hubble observe --output json > flows.json
# Last 100 flows
hubble observe --last 100
# Since timestamp
hubble observe --since 2024-01-01T10:00:00Z
# UI access
cilium hubble uiVerdict Types
| Verdict | Meaning |
|---|---|
FORWARDED | Traffic allowed and forwarded |
DROPPED | Traffic dropped (policy, error, etc.) |
DENIED | Explicitly denied by policy |
AUDIT | Would be denied (audit mode) |
REDIRECTED | Redirected (proxy, service mesh) |
ENCRYPTED | Encrypted traffic |
ERROR | Processing error |
Reserved Identities
| Identity | Meaning |
|---|---|
reserved:host | Host networking |
reserved:world | External (internet) |
reserved:cluster | Cluster-local |
reserved:health | Cilium health checks |
reserved:init | Pod initialization |
reserved:remote-node | Remote cluster node |
reserved:kube-apiserver | Kubernetes API server |
For comprehensive network policy examples, see network-policies.md.