Cilium Genel Bakış & Cilium Envoy L7 Proxy & Cilium L7 Network Policy

İçindekiler
- Giriş
- Cilium Nedir? Ne Yapar?
- Networking (Ağ Oluşturma)
- Identity-aware Network Policy Enforcement (Kimliğe duyarlı Ağ Politikası Uygulaması)
- Transparent Encryption (Şeffaf Şifreleme)
- Multi Cluster Networking (Çok Kümeli Ağ Iletişimi)
- Load Balancing (Yük Dengeleme)
- Enhanced Network Observability (Gelişmiş Ağ Gözlemlenebilirliği)
- Prometheus Metrics (Prometheus Ölçümleri)
- Service Mesh (Servis Ağı)
- Install Cilium (Cilium Kurulumu)
- Sonuç
- Kaynakça
Giriş
Gelenektir öncelikle bir literatür tanımı ile başlayalım nedir bu Cilium? Kernel teknolojisi eBPF (Extended Berkeley Packet Filter) tarafından desteklenen iş yükleri arasındaki network bağlantısını sağlamaya, güvenceye almaya ve gözlemlemeye yönelik açık kaynak bir Container Network Interface (Konteyner Ağ Arayüzü - CNI) plugin
diyebiliriz.
Peki CNI plugin nedir? Kısaca özet geçelim; Kubernetes kendi içinde bir network çözümü ile gelmez. Bunun yerine
Container Network Interface (CNI)
çözümüyle gelir.Cloud Native Computing Foundation (CNCF)
projesi olanCNI
, Linux container’larda (konteynerlerde) network interface’lerini yapılandırmak için eklentiler yazılabilmesini sağlayan spesifikasyonları belirler. CNI, container network altyapısının nasıl olması gerektiği ile ilgili standartlar yayınlamıştır ve geliştiricilerin bu standarda uygun networking çözümleri oluşturabilmesine imkan sağlamıştır. Böylece bu standartlara uygun network plugin’leri yazılma imkanı doğdu. Kubernetes; CNI standardını benimsedi, Kubernetes cluster’larda bu standarda uygun olarak yazılmış ve cluster’ın network çözümüne uygun olacak bir plugin seçilmesini söyledi. Burada sık tercih edilen, OVN, SDN, Cilium, Calico gibi bir kaç CNI plugin mevcut. Kubernetes kurulumunu tamamladıktan sonra bizim kullanacağımız CNI network plugin’i de yükleyerek Kubernetes’in network yönetimini plugine bırakmasını sağlıyoruz. Örneğin bir pod oluştuktan sonra atanacak ip adresinin belirlenmesi, bunun pod’a atanması ve altyapıda ayarlanması gereken tüm işlerin tamamlanması CNI plugin’in görevidir. Böylece pod’lar farklı node’lar (düğümler) üzerinde olsalar da birbirleri ile NAT (Network Address Translation - Ağ Adresi Çevirisi) olmadan haberleşebilirler.
Peki Cilium Neler Yapıyor? Ek Olarak Neler Sağlıyor?
- K8s (kubernetes) ortamında pod’lar arasında bağlantı sağlayan bir network plugin görevi görüyor.
- Enforcing Network Policies (Zorlayıcı Ağ Politikaları) ve Transparent Encryption (Şeffaf Şifreleme) yoluyla güvenlik sağlar. Hubble adı verilen bileşeni ile de network trafiğine ilişkin ayrıntılı observability (gözlemlenebilirlik) sağlar.
- eBPF sayesinde Cilium’un network, güvenlik ve observability mantığı doğrudan çekirdeğe programlanabilirdir. Böylece Cilium ve Hubble’ın yetenekleri uygulama iş yükleri için tamamen şeffaf hale gelir.
- Cilium başlangıcından itibaren büyük ölçekli, son derece dinamik container ortamları için tasarlandığını söylüyor. Container ve Kubernetes kimliklerini native (doğal) olarak anlar ve HTTP (Hyper-Text Transfer Protocol), gRPC (g Remote Procedure Call) ve Kafka gibi API (Application Programming Interface - Uygulama Programlama Arayüzü) protokollerini ayrıştırarak geleneksel bir firewall’dan (güvenlik duvarı) hem daha basit hem de daha güçlü observability ve güvenlik sağlar.
- Daha önce de bahsettiğimiz gibi temel engine (motor- çalıştırıcı) olarak eBPF’yi kullanan Cilium, Kubernetes gibi platformlarda mikro servisleri çalıştırmak için tam olarak optimize edilmiş bir
networking stack (ağ yığını)
oluşturur. - eBPF, Linux çekirdeğinin içinde çalıştığından, Cilium Security Policies (Güvenlik Politikaları), uygulama kodunda veya container yapılandırmasında herhangi bir değişiklik yapılmadan uygulanabilir ve güncellenebilir.
Şekil 1, eBPF kernel teknolojisine ve beraberinde ek açıklamalara değinmektedir.

Cilium, trafiği iş yükleri arasında bağlamak, bu trafiği gözlemlemek ve güvenliğini sağlamak için geniş bir özellik yelpazesine sahiptir. En sık kullanılan yeteneklerden bazılarına değinelim.
Networking (Ağ Oluşturma)
Cilium, network bağlantısı sağlayarak pod’ların ve diğer bileşenlerin (bir Kubernetes cluster’ın içinde veya dışında) iletişim kurmasına olanak tanır. Cilium, tüm uygulama container’larını birbirine bağlayan birden fazla Cluster’ı yayma becerisine sahip, basit düz bir Layer 3 (Katman 3) network uygular.
Varsayılan olarak Cilium, bir virtual network’ün (sanal ağın) tüm host’ları kapsadığı bir overlay network (örtülü ağ)
modelini destekler. Overlay networkteki trafik, farklı host’lar arasında aktarım için encapsule (kapsülleme) edilir. Bu mod, minimum altyapı ve entegrasyon gereksinimlerine sahip olduğundan ve yalnızca host’lar arasında IP bağlantısı gerektirdiğinden varsayılan olarak seçilmiştir.
Cilium ayrıca trafiği pod (veya harici) IP adreslerine yönlendirmek için her hosttaki normal routing (yönlendirme) tablosunu kullanan native routing networking (yerel yönlendirme ağı)
modeli seçeneğini de sunar. Bu mod ileri düzey kullanıcılar için oldukça kullanışlı oluyor.
Identity-aware Network Policy Enforcement (Kimliğe duyarlı Ağ Politikası Uygulaması)
Öncelikle Network Policy nedir? Kısaca değinelim. Hatta Kubernetes 🔗resmi dokümantasyonunda nasıl açıklıyor ona bakalım.
TCP (Transmission Control Protocol-İletim Kontrol Protokolü), UDP (User Datagram Protocol-Kullanıcı Datagram Protokolü) ve SCTP (Stream Control Transmission Protocol-Akış Kontrolü İletim Protokolü) protokolleri için trafik akışını IP adresi veya port’lar düzeyinde kontrol etmek istiyorsanız; cluster’daki belirli uygulamalar için Kubernetes NetworkPolicies’ı kullanmayı düşünebilirsiniz. NetworkPolicies, bir pod’un çeşitli network “objeleri” ile nasıl iletişim kurmasına izin verildiğini belirtmenize olanak tanıyan uygulama merkezli bir yapıdır.
Network policy’ler, hangi iş yüklerinin birbirleriyle iletişim kurmasına izin verildiğini tanımlar ve beklenmeyen trafiği önleyerek deployment’ları (dağıtımları) veya dağıtacağımız ortamları güvence altına alır. Cilium, hem native KubernetesNetworkPolicies
‘i hem de geliştirilmiş Cilium’a ait yeni bir obje olan CiliumNetworkPolicy
resource type’ını (kaynak türünü) kullanmamıza olanak tanır.
Hepimizin de bildiği üzere geleneksel firewall’lar, IP adreslerini ve hedef port’larını filtreleyerek çalışır. Kubernetes ortamında bu yöntemle, istenen network policy uygulanmaya çalışıldığında firewall kurallarını yeniden oluşturmak için, cluster’ın herhangi bir yerinde bir pod oluşturulduğunda tüm node’lardaki güvenlik duvarlarının (veya iptables kurallarının) manipüle edilmesi gerekir. Bu çok da ölçeklenebilir değil.
Bu durumu önlemek için Cilium, uygulama container gruplarına Kubernetes label’ları (etiketleri) gibi ilgili meta verilere dayalı bir identity-kimlik atar. Kimlik daha sonra uygulama container’ları tarafından yayılan tüm network paketleriyle ilişkilendirilir ve eBPF programlarının, herhangi bir Linux firewall kuralı kullanmadan, alıcı node’daki kimliği verimli bir şekilde doğrulamasına olanak tanır. Örneğin, bir deployment iş yüküne bağlı olarak veya tamamen keyfi olacak şekilde rastgele scale (ölçek) edildiğinde ve cluster’ın herhangi bir yerinde yeni bir pod oluşturulduğunda, yeni pod mevcut pod’larla aynı kimliği paylaşır. Böylece Nework policy’nin uygulanmasına karşılık gelen eBPF program kurallarının yeniden güncellenmesine gerek kalmaz. Çünkü onlar, pod’un kimliğini zaten biliyordur.
Şekil 2’de tam olarak bu anlatılmaktadır:

Geleneksel firewal’lar Layer 3 ve 4’te çalışırken, Cilium ayrıca REST/HTTP, gRPC ve Kafka gibi modern Layer 7 uygulama protokollerini (Layer 3 ve 4’te uygulamaya ek olarak) güvence altına alma yeteneğine de sahiptir. Aşağıdaki gibi uygulama isteklerine karşı enforce network policy yeteneği sağlar:
- GET metodu ve /public/.* path ile tüm HTTP isteklerine izin verilebilir. Diğer tüm istekleri reddedilebilir. Tüm REST çağrılarında X-Token: [0–9]+ HTTP header (başlık)’ın bulunması zorunlu kılınabilir.
Transparent Encryption (Şeffaf Şifreleme)
Biliyoruz ki artık servisler arasında in-flight data (aktarım sırasındaki veri) şifreleme, PCI veya HIPAA gibi birçok güvenlik standardına uyum için gereklidir. Cilium, kullanıyorsak eğer içimiz rahat olabilir. Herhangi bir iş yükünün yeniden yapılandırılmasına gerek kalmadan nodelar arasındaki trafiği güvence altına alan IPSec veya WireGuard kullanarak in-flight data şifrelemesi yapılır.
Multi Cluster Networking (Çok Kümeli Ağ Iletişimi)
Cilium’un Cluster Mesh özelliği ile, iş yüklerinin farklı Kubernetes cluster’larında bulunan servislerle iletişim kurmasını sağlayabiliyoruz. Bu demek oluyor ki; Servisleri farklı region’lardaki clusterlar üzerinde çalıştırarak ve bunları birbirine Cilium Cluster Mesh ile bağlayarak High Available- Yüksek Kullanılabilirlik (HA) hale getirebiliriz.
Load Balancing (Yük Dengeleme)
Cilium, container’lar ve external (harici) servisler arasındaki trafik için distributed-load balancing (dağıtık-yük dengeleme) uygular. Aslında daha ayrıntılı incelediğimizde Cilium, “kube-proxy” gibi k8s bileşenlerinin görevini üstlenerek yerini tamamen alabiliyor diyebiliriz ve ayrıca standalone (bağımsız) bir load balancer olarak da kullanılabiliyor.
Enhanced Network Observability (Gelişmiş Ağ Gözlemlenebilirliği)
En sevdiğim kısım; Network Observability
, Network observability production (üretim) ortamlarda her zaman bir ihtiyaçtır, bu uğurda ne toollar denendi, ta ki Cilium Hubble
gelene kadar…
Şekil 3’ de Hubble Arayüzü ve servisler arasındaki bağlantısının gösterimi verilmiştir.

tcpdump ve ping gibi araçları sıkça kullanıyoruzdur, aşinayızdır. Fakat bunlar Kubernetes ortamlarındaki network sorunlarımızı analiz etmede yetersiz kalıyorlar. Bu noktada Cilium, cluster network sorunlarını hızlı bir şekilde görebilmenize ve düzeltmenize olanak tanıyan observability araçları sağlıyor.
Bu amaçla Cilium, Hubble adı verilen özel bir network observability bileşeni içerir. Hubble, trafiği filtrelemeyi kolaylaştırmak için Cilium’un kimlik konseptinden yararlanıyor ve şunları sağlıyor:
- Layer3/4’te (IP adresi ve port) ve Layer 7’de (API Protokolü) network trafiğine ait visibility (görünürlük) sağlar.
Meta verilerle event monitoring (olay izleme)
: Bir paket drop edildiğinde (düştüğünde) araç yalnızca paketin kaynak ve hedef IP’sini raporlamakla kalmıyor, aynı zamanda diğer birçok bilginin yanı sıra hem gönderenin hem de alıcının tam label bilgilerini sağlar.- Prometheus metriklerini export (dışa aktarım) edebilir.
- Cluster’lar üzerinden akan network trafiğini görselleştirmek için grafiksel bir kullanıcı arayüzü sağlar.
Prometheus Metrics (Prometheus Ölçümleri)
Cilium ve Hubble, Prometheus aracılığıyla network performansı ve latency (gecikme) ile ilgili metrikleri export edebilir, böylece Cilium metriklerini var olan kullandığımız bir dashboarda (gösterge paneli) entegre edebiliyoruz.
Şekil 4’ de Grafana’ya eklenen bir Prometheus kaynağının panel ile görselleştirilmesi verilmiştir.

Service Mesh (Servis Ağı)
Cilium’un, tümü Kubernetes servis mesh’in özellikleri olan servisler arasında load balancing, “application layer visibility (uygulama katmanı görünürlüğü)” ve güvenlik ile ilgili çeşitli özellikleri desteklediğinden bahsettik. Cilium ayrıca, hem Kubernetes Ingress’i hem de Gateway API’sini destekler ve her pod’a eklenecek olan sidecar (sepet) container iş yüküne gerek kalmaz.
Install Cilium (Cilium Kurulumu)
Elimizi taşın altına koyalım yavaş yavaş…
Cilium’un bir Kubernetes ortamına kurulumunu yapacağız. Ardından Cilium mimarisini inceleyerek Kubernetes’te enhanced network connectivity (gelişmiş ağ bağlantısı), observability ve güvenlik sağlamak için bileşenlerin birlikte nasıl çalıştığını inceleyeceğiz.
Cilium iki kurulum yöntemini destekliyor:
- Cilium CLI tool
- Helm chart
Biz Cilium CLI aracını kullanarak kurulum yapacağız.
Cilium bir CNI plugin ve kurulumu yapacağımız ortam network plugin’i yapılandırılmamış bir k8s ortamı olmalı, CNI yüklemeye hazır bir k8s ortamına kurulum işlemlerimizi yapıyor olacağız.

Yukarıda da görüldüğü üzere 1 master, 2 worker node’dan oluşan bir kubernetes clusterımız var, fakat default bir CNI olmadığından node’lar “Not Ready” durumdalar.
🔗Bu adresten işletim sistemimize uygun Cilium CLI tool’u yüklediğimizi varsayıyoruz.
"cilium version"
komutuyla kontrol edelim. Hazırladığımız Kubernetes cluster’a default Cilium imajını yükleyeceğiz. CLI aracı zaten bize clusterda henüz bir Cilium kurulu olmadığını söylüyor.

"cilium install"
komutuyla başlayalım.

Kurulum işleminin tamamlanması birkaç dakika sürebiliyor. Başka bir terminalde, Cilium’un tamamen kurulmasını ve çalışır duruma gelmesini izleyebiliriz.

Cilium’un en sevdiğimiz yanlarından bir tanesi Star Wars🛸
temasını içeriklerinde konu alması Star wars hayranlarının gönlünü çaldı diyebiliriz.
Yapacağımız demo’da, Star Wars’tan ilham alan üç tane mikroservis uygulaması bulunuyor: Deathstar, Tiefighter ve Xwing.
- deathstar: org=empire, class=deathstar
- Imperial TIE fighter: org=empire, class=tiefighter
- Rebel X-Wing: org=alliance, class=xwing
Uygulama aynı zamanda org=empire, class=deathstar label’larıyla tüm pod’lara giden trafiği load balance eden bir deathstar servisini de içeriyor.
Aşağıdaki repoda bulunan http-sw-app.yaml dosyasını kullanarak uygulamayı deploy edelim:
1
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/minikube/http-sw-app.yaml

Oluşturduğumuz objelere bakalım!

Her pod aynı zamanda Cilium tarafında bir Endpoint olarak temsil ediliyor. Cilium tarafından yönetilen endpoint’lerin listesini almak için Cilium Endpoint (veya cep) resource kullanılabilir:

Test etmek için curl kullanarak basit API çağrıları gerçekleştireceğiz. Aşağıdaki komutu çalıştırarak TIE fighter’ı, Death Star’a indirip indiremeyeceğimizi test edelim:
1
2
kubectl exec tiefighter -- \
curl -s -XPOST deathstar.default.svc.cluster.local/v1/request-landing

Yukarıdaki komut, tiefighter
pod üzerinde bir shell almamıza ve iniş talebinde bulunmak için deathstar
servise bir HTTP POST isteği çalıştırmamızı sağlıyor.
Seriyi izleyenler bilir. TIE fighter ve Death Star galaktik savaşçıların (yani kötü adamların) tarafında olduğundan, komut başarılı çalışmalıdır.
Şimdi X-wings (yani iyi adamları) için aynı testi yapalım.

Testlere baktığımızda DeathStar’a gelen tüm erişimlere izin verilmiş görünüyor. Bu, isyancı ittifakı için iyi (DeathStar’a sınırsız erişim) ama buna izin verilmemiş olmalı.
Death Star’a erişim taleplerini yalnızca org=empire label’ına sahip gemilerle sınırlandıran basit bir policy yazarak erişimi engelleyelim.
Ne yapmamız gerektiğini Şekil 5’ deki akış yardımıyla düşünelim.

Yalnızca empire gemilerinden erişime izin vereceğiz, dolayısıyla şu label’la eşleşmemiz gerekiyor:
1
2
3
4
5
6
spec:
description: "L3-L4 policy to restrict deathstar access to empire ships only"
endpointSelector:
matchLabels:
org: empire
class: deathstar
Ayrıca, empire label’ına sahip endpoint’lerden girişin TCP 80 portuna izin vermeliyiz.
1
2
3
4
5
6
7
8
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
Temel olarak yazmamız gereken policy’e ait isterleri çıkardık, bu basitti. Ama her zaman bu kadar basit policy’ler kullanmıyoruz, oldukça karmaşık policy’ler ihtiyaç olduğu zaman oluşturmak ve anlamak zorlaşıyor. Cilium’un bunun için bir çözümü var: 🔗 Network Policy Editor adı verilen bir çözümü bulunuyor. Policy’nin ne yaptığını anlamak ve görsel etkileşim için oldukça kullanışlı. Pratik yapmak için oldukça kullanışlı Şekil 6’ da görüldüğü gibi public bir UI da sunuyor.
Şekil 6’ da;
- Diyagramın orta kısmı Network Policy Selector’ü temsil ediyor:
- Sağında ve solunda ise sırasıyla bu iş yükü için hangi giriş ve çıkışlara izin verildiğini gösteriliyor.

Son durumda isterlere uygun CiliumNetworkPolicy
objemiz aşağıdaki gibi:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "L3-L4 policy to restrict deathstar access to empire ships only"
endpointSelector:
matchLabels:
org: empire
class: deathstar
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
1
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/minikube/sw_l3_l4_policy.yaml
Şimdi deathstar’a http testlerimizi tekrar gerçekleştirelim.

Farkettiyseniz ikinci komut yani xwing’den atılan istekler başarısız oldu, bu NetworkPolicy başarılı çalışıyor demektir. Fakat tiefighter pod’undan yapılan istekler hala başarılı, çünkü empire
label’ına sahip.

Yine Star Wars hikayesinden devam edelim. İmparatorluğa ait binlerce savaş uçağı ve savaş pilotu var. Tüm imparatorluğun binlerce savaş uçağı pilotuna güvenemeyiz.
Mikroservisler arasında en güçlü güvenliği sağlamalıyız (yani en az ayrıcalıklı izolasyonu uygulamalıyız): deathstar’ın API’sini çağıran her servis, ihtiyaç duyulan HTTP isteklerini yapmakla sınırlı olmalıdır. Şekil 7’ de en az ayrıcalıklı izolasyona ait yapmamız gerekenler akış olarak verilmektedir.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "L7 policy to restrict access to specific HTTP call"
endpointSelector:
matchLabels:
org: empire
class: deathstar
ingress:
- fromEndpoints:
- matchLabels:
org: empire
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "POST"
path: "/v1/request-landing"
Yeni policy objemiz artık yukarıdaki gibi. Farkettiyseniz bu artık HTTP API filtresini içeren bir L7 policy
objesi. Bu policy objesini uygulayalım.
1
kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/HEAD/examples/minikube/sw_l3_l4_l7_policy.yaml

İmparatorluk güvende! Tiefighter’ın deathstar üzerinde sadece gerekli API kaynaklarına erişimini kısıtlayabildik, böylece mikroservisler arasındaki iletişim için "least privilege"
security yaklaşımını uygulamış olduk.
Yalnızca HTTP trafiğine izin verdik ve yalnızca isteğin POST yöntemini kullanması ve /v1/request-landing path’ini hedeflemesi durumunda izin verdik.
Layer 7 network policy’ler, L7 proxy’si olarak Envoy kullanılarak uygulanır. Cilium, Envoy’u bu güvenlik kurallarını uygulayacak şekilde dinamik olarak programlar.
Envoy; yüksek performanslı bir Layer 7 (Uygulama Katmanı) proxy’sidir. Servisler arası iletişimde gelişmiş trafik yönlendirme, yük dengeleme, güvenlik ve metrik toplama gibi görevleri üstlenir. Genelde service mesh mimarilerinde kullanılır.
Hubble observe kullanarak logları inceleyebiliriz.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
hubble observe \
--from-pod default/tiefighter \
--to-pod default/deathstar
Aug 25 16:25:23.846: default/tiefighter (ID:40238) <> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) post-xlate-fwd TRANSLATED (TCP)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-overlay FORWARDED (TCP Flags: SYN)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) policy-verdict:L3-L4 INGRESS ALLOWED (TCP Flags: SYN)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-overlay FORWARDED (TCP Flags: ACK)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-overlay FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:25:23.846: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:25:23.847: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-overlay FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:25:23.847: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:25:23.847: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) http-request DROPPED (HTTP/1.1 PUT http://deathstar.default.svc.cluster.local/v1/exhaust-port)
Aug 25 16:25:23.847: default/tiefighter:54876 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-overlay FORWARDED (TCP Flags: ACK)
Tie Fighter ve the Death Star arasındaki bağlantının adımlarını inceleyelim:
- Kernel içi eBPF programı, L3/L4 Network Policy kuralına göre bağlantıya izin verdiğinde,
INGRESS ALLOWED
olarak işaretlenmiş birpolicy-verdict:L3-L4
trace (iz-işaret) - Envoy proxy’sine gönderilen trafiğe karşılık gelen,
FORWARDED
olarakto-proxy
traceler (SYN, ACK ve ACK, PSH traceler) - Envoy isteğe, engellenen HTTP isteğinin ayrıntılarıyla birlikte
Access denied
response (cevap) verdiğinde,DROPPED
olarak işaretlenen birhttp-request
trace - Son olarak, TCP connection (bağlantı) sonlandıran
ACK, FIN
adımı için başka birto-proxy
trace
Hubble observe kullanarak Envoy proxy üzerinden yönlendirilen trafiği kontrol edelim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
hubble observe --type trace:to-proxy
Aug 25 16:39:37.516: default/tiefighter:51182 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:37.516: default/tiefighter:51182 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:37.516: default/tiefighter:51182 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:37.517: default/tiefighter:51182 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:38.611: default/tiefighter:51190 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:38.611: default/tiefighter:51190 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:38.611: default/tiefighter:51190 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:38.612: default/tiefighter:51190 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:39.705: default/tiefighter:51194 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:39.705: default/tiefighter:51194 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:39.705: default/tiefighter:51194 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:39.706: default/tiefighter:51194 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:40.800: default/tiefighter:51200 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:40.800: default/tiefighter:51200 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:40.800: default/tiefighter:51200 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:40.801: default/tiefighter:51200 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:41.898: default/tiefighter:57638 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:41.898: default/tiefighter:57638 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:41.898: default/tiefighter:57638 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:41.899: default/tiefighter:57638 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:42.990: default/tiefighter:57654 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:42.990: default/tiefighter:57654 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:42.990: default/tiefighter:57654 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:42.991: default/tiefighter:57654 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:44.083: default/tiefighter:57660 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:44.083: default/tiefighter:57660 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:44.083: default/tiefighter:57660 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:44.085: default/tiefighter:57660 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:45.178: default/tiefighter:56764 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:45.179: default/tiefighter:56764 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:45.179: default/tiefighter:56764 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:45.180: default/tiefighter:56764 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:46.275: default/tiefighter:56766 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:46.275: default/tiefighter:56766 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:46.275: default/tiefighter:56766 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:46.276: default/tiefighter:56766 (ID:40238) -> default/deathstar-b4b8ccfb5-bsd8s:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Aug 25 16:39:47.366: default/tiefighter:42598 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: SYN)
Aug 25 16:39:47.367: default/tiefighter:42598 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK)
Aug 25 16:39:47.367: default/tiefighter:42598 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, PSH)
Aug 25 16:39:47.368: default/tiefighter:42598 (ID:40238) -> default/deathstar-b4b8ccfb5-wl47m:80 (ID:39571) to-proxy FORWARDED (TCP Flags: ACK, FIN)
Trace: to-proxy filtresi, proxy üzerinden geçen tüm akışları gösterir. Genelde bu, Envoy veya Cilium DNS proxy’si olabilir. Ancak henüz bir DNS Network Policy deploy etmediğimizden şu anda yalnızca Envoy ile ilgili akışları görüyoruz.
Standart Kubernetes Network Policy’leri ile trafiği 3. ve 4. katmanda filtreleyebiliyoruz.
- Layer 3, kimliklerin (IP adreslerinin) kullandıkları port’lardan ve değiştirdikleri içerikten bağımsız olarak iletişim kurmasına olanak tanır. Yani yalnızca IP filtreleyebiliriz.
- Layer 4, port’lara filtreleme ekler (örn. TCP/80), ancak yine de içeriği filtrelemez.
Cilium, Layer 7’deki trafiği filtreleyebilmek için Envoy L7 proxy kullanır. Bu HTTP path, headers vb. gibi uygulamaların paylaştığı bilgi türlerini de filtreleyebileceğimiz anlamına geliyor.
Protokole (örneğin, HTTP) ve kaynak pod’a (örneğin, Tie Fighter) dayalı olarak tüm akış bilgilerini çıkaralım, ardından sonucu JSON output (çıktı) olarak export edelim ve son olarak yalnızca .flow.l7 alanını görmek için jq ile filtreleyelim. Bu bize L7 trafiğinden ayrıştırılan metod ve headers gibi belirli ayrıntıları da gösterecektir:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
hubble observe --protocol http --from-pod default/tiefighter -o jsonpb | \
head -n 1 | jq '.flow.l7'
{
"type": "REQUEST",
"http": {
"method": "POST",
"url": "http://deathstar.default.svc.cluster.local/v1/request-landing",
"protocol": "HTTP/1.1",
"headers": [
{
"key": ":scheme",
"value": "http"
},
{
"key": "Accept",
"value": "*/*"
},
{
"key": "User-Agent",
"value": "curl/7.88.1"
},
{
"key": "X-Envoy-Internal",
"value": "true"
},
{
"key": "X-Request-Id",
"value": "11e5619d-1fcf-43c9-90bc-68c36bba3584"
}
]
}
}
Yularıdaki çıktıdan elde ettiğimiz Envoy’a ait header’lar:
- X-Envoy-Upstream-Service-Time
- X-Request-Id
Şimdi aşağıdaki komutla HTTP egress (çıkış) trafiğe bakalım.
1
hubble observe --protocol http --traffic-direction egress
Hiç bir sonuç döndürmedi, çünkü tüm akışlar ingress (giriş) trafikti.
Bir request’i (istek) ve response’u (cevap) eşleştirmek için X-Request_Id
header’ı kullanabiliriz. Öncelikle Tie Fighter’dan gelen egress trafiğinin Envoy tarafından yakalandığından emin olmamız gerekecek, dolayısıyla bunun için bir L7 CNP’ye (Cilium Network Policy) ihtiyacımız olacak.
Ancak bir egress CNP’si uygularsak, bu aynı zamanda egress trafiği olan DNS isteklerini de kesecektir, dolayısıyla bir DNS policy de eklememiz gerekiyor:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
apiVersion: cilium.io/v2
kind: CiliumNetworkPolicy
metadata:
namespace: default
name: dns
spec:
endpointSelector: {}
egress:
- toEndpoints:
- matchLabels:
io.kubernetes.pod.namespace: kube-system
k8s-app: kube-dns
toPorts:
- ports:
- port: "53"
protocol: ANY
rules:
dns:
- matchPattern: "*"
1
kubectl apply -f dns.yaml
Şimdi tekrar egress trafiği kontrol edelim:
1
hubble observe --protocol http --traffic-direction egress
Artık Tie Fighter’dan gelen egress request’lerin Death Star’a iletildiğini ve Death Star’dan dönen response’ları görebiliyoruz.
1
2
3
4
5
6
7
8
9
10
Aug 26 17:50:49.197: default/tiefighter:43736 (ID:23000) -> default/deathstar-b4b8ccfb5-hqr5f:80 (ID:30442) http-request FORWARDED (HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Aug 26 17:50:49.198: default/tiefighter:43736 (ID:23000) <- default/deathstar-b4b8ccfb5-hqr5f:80 (ID:30442) http-response FORWARDED (HTTP/1.1 200 0ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
Aug 26 17:50:50.299: default/tiefighter:53696 (ID:23000) -> default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-request FORWARDED (HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Aug 26 17:50:50.301: default/tiefighter:53696 (ID:23000) <- default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-response FORWARDED (HTTP/1.1 200 1ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
Aug 26 17:50:51.405: default/tiefighter:43744 (ID:23000) -> default/deathstar-b4b8ccfb5-hqr5f:80 (ID:30442) http-request FORWARDED (HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Aug 26 17:50:51.406: default/tiefighter:43744 (ID:23000) <- default/deathstar-b4b8ccfb5-hqr5f:80 (ID:30442) http-response FORWARDED (HTTP/1.1 200 0ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
Aug 26 17:50:52.505: default/tiefighter:53702 (ID:23000) -> default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-request FORWARDED (HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Aug 26 17:50:52.507: default/tiefighter:53702 (ID:23000) <- default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-response FORWARDED (HTTP/1.1 200 1ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
Aug 26 17:50:53.603: default/tiefighter:53714 (ID:23000) -> default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-request FORWARDED (HTTP/1.1 POST http://deathstar.default.svc.cluster.local/v1/request-landing)
Aug 26 17:50:53.605: default/tiefighter:53714 (ID:23000) <- default/deathstar-b4b8ccfb5-dwc2g:80 (ID:30442) http-response FORWARDED (HTTP/1.1 200 1ms (POST http://deathstar.default.svc.cluster.local/v1/request-landing))
Kubernetes Network Policy kullanırken response’lara otomatik olarak izin verilir ve bir rule (kural) gerekmez. Bu nedenle Death Star’ın Tie Fighter’a verdiği response’a karşılık gelen egress trafiğine, bunun için bir egress policy olmasa da izin verilir.
Şimdi request ID’leri eşleştirebiliriz. Hubble HTTP akışlarını bir dosyaya kaydetmek için aşağıdaki gibi komut çalıştıralım.
1
hubble observe --namespace default --protocol http -o jsonpb > flows.json
Dosyadaki ilk egress akışını bulup ID’sini alalım.
1
2
3
4
REQUEST_ID=$(cat flows.json | jq -r '.flow | select(.source.labels[0]=="k8s:app.kubernetes.io/name=tiefighter" and .traffic_direction=="EGRESS") .l7.http.headers[] | select(.key=="X-Request-Id") .value' | head -n1)
echo $REQUEST_ID
bf39c9a5-cacc-4cd3-a3d6-3b52d7156997
Daha sonra dosyada bu request ID’ye sahip tüm akışları bulalım ve source ID’leri görüntüleyelim:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
cat flows.json | \
jq 'select(.flow.l7.http.headers[] | .value == "'$REQUEST_ID'") .flow | {src_label: .source.labels[0], dst_label: .destination.labels[0], traffic_direction, type: .l7.type, time}'
{
"src_label": "k8s:app.kubernetes.io/name=tiefighter",
"dst_label": "k8s:app.kubernetes.io/name=deathstar",
"traffic_direction": "EGRESS",
"type": "REQUEST",
"time": "2024-08-26T17:57:31.081515967Z"
}
{
"src_label": "k8s:app.kubernetes.io/name=tiefighter",
"dst_label": "k8s:app.kubernetes.io/name=deathstar",
"traffic_direction": "INGRESS",
"type": "REQUEST",
"time": "2024-08-26T17:57:31.082386689Z"
}
{
"src_label": "k8s:app.kubernetes.io/name=deathstar",
"dst_label": "k8s:app.kubernetes.io/name=tiefighter",
"traffic_direction": "INGRESS",
"type": "RESPONSE",
"time": "2024-08-26T17:57:31.082777989Z"
}
{
"src_label": "k8s:app.kubernetes.io/name=deathstar",
"dst_label": "k8s:app.kubernetes.io/name=tiefighter",
"traffic_direction": "EGRESS",
"type": "RESPONSE",
"time": "2024-08-26T17:57:31.082999422Z"
}
4 adet resource görüyoruz:
- orijinal request’e karşılık gelen,
tiefighter'dan
deathstar'a
biregress
akış proxy'den
deathstar'a
iletilen aynı request içiningress
akışdeathstar
pod’undantiefighter'a
karşılık geleningress
akışdeathstar'dan
tiefighter'a
respone içinegress
akış
Şekil 8’ de yer alan Hubble arayüzünden trafiği inceleyelim:

Artık TCP lable’a ek olarak HTTP bilgilerini de görüyoruz.
En alttaki akışlar Envoy tarafından sağlanan HTTP ayrıntılarını da bize veriyor.
Hubble ile Envoy’u kullanarak Prometheus aracılığıyla export edilebilen L7 metriklerini toplayabiliriz.
Şekil 9, Cilium ile Grafana’yı entegre edebileceğimizi daha doğrusu metriklerin, logların ve trace’lerin toplanabilir olduğunu ve bu verilerin Grafana’da görselleştirilebileceğini göstermektedir.

Sonuç
Cilium modern Kubernetes ağ iletişimini basitleştiren ve güvenliği üst düzeye taşıyan güçlü bir ağ çözümü olarak karşımıza çıkmaktadır. eBPF gibi yenilikçi kernel teknolojilerden faydalanarak, düşük gecikme süreleriyle yüksek performans sağlarken mikro servisler arasındaki trafiği etkili bir şekilde yönetir. Cilium Network Policies, sadece L3/L4 seviyesinde değil, aynı zamanda L7 seviyesinde de detaylı kontrol sunarak hem güvenlik hem de esneklik açısından önemli avantajlar sağlar. Ayrıca, Envoy tabanlı L7 proxy, API çağrıları ve veri akışı üzerinde detaylı gözlem ve denetim imkanı tanıyarak modern bulut yerel uygulamaların ihtiyaçlarını karşılamaktadır. Cilium’un sunduğu bu yetenekler, geliştiricilere ve operasyon ekiplerine dinamik bir altyapı üzerinde güvenli, hızlı ve ölçeklenebilir çözümler sunarak Kubernetes ekosistemindeki kritik bir ihtiyaca yanıt verir. Cilium’un sunduğu geniş özelliklere değindik. Cilium Network Policy’ler, L7 Envoy Proxy, Hubble observe üzerine pratikler yaptık. Umarım faydalı olmuştur.
Yazımızın teknik gözden geçirmesi için Ayşegül ÖZKAYA EREN’e, editör desteği için ise Kübra ERTÜRK’e teşekkür ederiz.
Kaynakça