Feynman Metodu ile Kubernetes: Network Policies
Selamlarrr!!! Bugünkü konumuz Network Policies (Cluster İçi Güvenlik Duvarı)!
Feynman Metodu ile Kubernetes: Network Policies
Selamlarrr!!! Bugünkü konumuz Network Policies (Cluster İçi Güvenlik Duvarı)!
Şu ana kadar kurduğumuz tüm sistemlerde varsayılan olarak şöyle bir kural geçerliydi: “Kubernetes içinde çalışan bütün podlar, farklı namespace’lerde olsalar dahi birbirleriyle hiçbir engele takılmadan, serbestçe konuşabilirler.” Buna network dilinde “Flat Network” (Düz Ağ) modeli denir. Küçük projelerde harika bir konfordur ama kurumsal bir altyapıda tam bir siber güvenlik kabusudur! Düşünün ki dış dünyaya açık, internetten herkesin erişebildiği bir frontend podunuz var. Bir de en arkada şirketin tüm kredi kartı ve müşteri verilerini tutan kozmik bir database podunuz var. Saldırganlar frontend podundaki bir açıktan yararlanıp içeri sızarlarsa, elini kolunu sallayarak veritabanına erişebilirler. Gelin, bu sinsi ağ savaşlarını engelleyeceğimiz Network Policy mimarisini Feynman usulü esnaf diliyle masaya yatıralım! 😊

Mahalleler ve Kuryeler Benzetmesi
Kubernetes ağ yapısını kafanızda kusursuz oturtmak için kodları bir kenara bırakalım ve iki farklı mahalle hayal edelim:
**frontendMahallesi: Bu mahallede yaşayan Web-Frontend** adında bir kuryemiz var (Dış dünyaya açık pod).**coreMahallesi: Bu mahallede yaşayan Ödeme-Backend** adında çok gizli bir bankacımız var (İçerideki hassas pod).- Network Policy (NetPol): Bu mahallelerin girişine ve evlerin kapısına diktiğimiz “Özel Güvenlik Fedaileridir”. Hangi kuryenin, hangi kapıdan, hangi mektup türüyle girebileceğini denetlerler.
İki Temel Trafik Yönü: Ingress ve Egress
Network Policy yazarken dünyayı ikiye ayırırız:
- Ingress (Giriş Trafiği): Benim koruduğum evin kapısına “Dışarıdan kimler gelebilir?” sorusunun cevabıdır. (Örn: Veritabanına sadece Backend gelebilsin).
- Egress (Çıkış Trafiği): Benim koruduğum evden çıkan biri “Dışarıdaki kimlerin evine gidebilir?” sorusunun cevabıdır. (Örn: Veritabanı podu internete çıkamasın, sadece iç log sunucusuna gitsin).
Default Deny
Kubernetes’te bir podun etrafında hiçbir Network Policy tanımlı değilse, o pod “Herkese Açık” (Non-Isolated) moddadır. Önüne gelenle konuşur. Fakat… Siz o podun etiketini hedef alan tek bir Network Policy yazdığınız an, o pod saniyeler içinde “Katı İzolasyon” (Isolated) moduna geçer. Kubernetes o an fedailere şu emri verir: “Hop! Bu pod için resmi bir kural yazıldı. Artık bu kural dosyasında adı açık açık GEÇMEYEN diğer tüm podlar, servisler ve IP’ler bu pod için DÜŞMAN sayılacaktır ve onların tüm trafiği şak diye engellenecektir!”
Gelin, core namespace'indeki veritabani poduna sadece backend etiketli podların 5432 (PostgreSQL) portundan erişmesine izin veren o temel kalkanı yazalım:
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: db-firewall
namespace: core # Sadece bu mahalledeki podları koruyoruz
spec:
podSelector:
matchLabels:
app: veritabani # Kalkanı takacağımız hedef pod!
policyTypes:
- Ingress # Sadece GİRİŞ trafiğini denetleyeceğimizi belirttik
ingress:
- from:
- podSelector:
matchLabels:
app: backend # Sadece bu etikete sahip podlara kapıyı aç!
ports:
- protocol: TCP
port: 5432 # Sadece bu porttan girmelerine izin ver!
🚨 Vaka 1:
Kriz: Yukarıdaki o harika db-firewall kuralını canlıya aldık. Her şey çok güzel; frontend podu veritabanına erişemiyor, backend podu ise sorunsuz bağlanıyor. Ancak bir süre sonra alarm çalıyor: Veritabanı podu cluster içindeki hiçbir servisin adını çözemiyor (DNS Resolution patladı), dış dünyadaki yedekleme sunucularına gidemiyor ve log fırlatamıyor! Kendi kurduğumuz duvarda boğuluyor!
🕵️♂️ Teşhis ve Perde Arkası:
Bir Kubernetes podunun başka bir yerle konuşabilmesi için önce cluster’ın rehberi olan CoreDNS poduna gidip isim çözlemesi yapması gerekir. CoreDNS podları ise cluster’da varsayılan olarak kube-system adındaki bambaşka bir namespace içinde yaşarlar. Biz veritabanının önüne o katı Ingress kuralını koyduğumuz an, Kubernetes’in o katı “Default Deny” motoru devreye girdi ve kuralda açıkça yazmadığımız için CoreDNS’ten dönen cevap paketlerini düşman sayıp şak diye çöpe attı!
🛠️ Doğru Operasyon:
Veritabanının hem backend’den istek almasını sağlamalı, hem de kube-system namespace'indeki CoreDNS podlarına (53 numaralı UDP portundan) gitmesine açıkça izin vermeliyiz:
spec:
podSelector:
matchLabels:
app: veritabani
policyTypes:
- Ingress
- Egress # Çıkışı da kontrol altına alıyoruz
ingress:
- from:
- podSelector:
matchLabels:
app: backend
egress:
# CAN SİMİDİ: CoreDNS tünelini açıyoruz!
- to:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: kube-system
podSelector:
matchLabels:
k8s-app: kube-dns
ports:
- protocol: UDP
port: 53
🚨 Vaka 2:
Kriz: Bir yazılım mimarı sepet podunu korumak istiyor. Amacı şu: “Bu sepet poduna sadece ve sadece marketing namespace'i içerisinden gelen VE üzerinde app: kampanya etiketi olan podlar erişebilsin (VE / AND mantığı)." Mimar gidip kuralı şöyle yazıyor:
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: marketing
- podSelector: # <- SİNSİ ÇİZGİ!
matchLabels:
app: kampanya
Kuralı uyguluyor ama bir bakıyor ki duvar delinmiş! production namespace'indeki alakasız bir pod da içeri sızıyor, marketing namespace'indeki tamamen farklı bir frontend podu da sızıyor! Sistem VE yerine VEYA mantığına dönmüş!
🕵️♂️ Teşhes ve Perde Arkası:
YAML dilinde satırın başına koyduğunuz o küçük çizgi (-), listenin yeni ve bağımsız bir maddesi demektir. Siz iki seçicinin de başına çizgi koyarsanız Kubernetes iki ayrı kapı açar (VEYA der):
- Kapı 1:
marketingnamespace'indeki herkes gelebilir. - Kapı 2: Hangi namespace’te olursa olsun üzerinde
app: kampanyayazan herkes gelebilir.
🛠️ Doğru Operasyon:
Eğer kuralların VE (AND) mantığıyla çalışmasını, yani hem o mahallede hem de o etikette olmasını istiyorsanız, ikinci kuralın başındaki çizgiyi sileceksiniz ve özellikleri aynı bloğun içinde alt alta hizalayacaksınız:
ingress:
- from:
- namespaceSelector:
matchLabels:
kubernetes.io/metadata.name: marketing
podSelector: # <- Çizgi silindi! Artık burası tek bir kapı ve iki kilit!
matchLabels:
app: kampanya
🚨 Vaka 3
Kriz: Farklı bir namespace’teki web-frontend podumuz, bizim koruduğumuz ödeme podunun önündeki Service (ClusterIP) adresine (10.96.0.100) istek atıyor ama istek Timeout yiyerek düşüyor. NetworkPolicy kuralında frontend poduna açıkça izin verilmesine rağmen trafik neden engelleniyor?
🕵️♂️ Teşhes ve Perde Arkası:
Kubernetes’te paketler Service IP’sine göre süzülmez. Paket yoldayken Kube-Proxy devreye girer, Service IP’sini siler ve paketi doğrudan Gerçek Pod IP’sine yönlendirir. Paket kapıya geldiğinde NetworkPolicy motoru paketin hangi mahalleden geldiğini anlamak için karşı namespace’in etiketine (Label) bakar. Eğer siz o namespace’i yaratırken ona bir etiket tanımlamadıysanız, bizim akıllı firewall karşı mahallenin ismini okuyamaz ve paketi düşman sayıp çöpe atar!
🛠️ Doğru Operasyon:
İç iletişimin kör olmaması için karşı namespace’in girişine mutlaka ismini yazan o tabelayı (etiketi) asmalısınız:
kubectl label namespace frontend kubernetes.io/metadata.name=frontend
Tabela asıldığı salisede firewall karşı mahallenin adını okur ve kapıyı açar!
Eğer bir podun cluster dışındaki bir IP’ye gitmesini sağlarken cluster içindeki kendi arkadaş podlarından kopmamasını istiyorsanız, tüm cluster’ı tek hamlede serbest bırakan o sihirli boş süslü parantez hilesini kullanabilirsiniz:
egress:
- to:
- ipBlock:
cidr: 192.168.1.50/32 # Dışarıdaki log sunucusu
- to:
- podSelector: {} # SİHİRLİ SATIR! Cluster içindeki tüm podlarla konuşabilsin!
Takipte kalın bol kodlu günlerr🎊
메타데이터
- post_id
- 5fa72f4ea116
- slug
- feynman-metodu-ile-kubernetes-network-policies-5fa72f4ea116
- url
- https://medium.com/@minekrmaci/feynman-metodu-ile-kubernetes-network-policies-5fa72f4ea116
- canonical_url
- https://medium.com/@minekrmaci/feynman-metodu-ile-kubernetes-network-policies-5fa72f4ea116
- author_url
- https://medium.com/@minekrmaci
- status
- ok
- fetched_at
- 2026-08-26 17:15:19