Sidecar'sız Service Mesh Nedir? Neyi Çözer, Kazanımları ve WireGuard ile Mutual Auth'lu Bir Cilium Lab'ı

Sidecar'sız service mesh'i bir Cilium lab'ıyla anlatıyorum: WireGuard ağdaki okunur HTTP'yi 6 satırdan 0'a indirdi; SPIFFE mutual auth, Hubble L7 ve GAMMA.

Yazan: Mirac Can Yılmaz 10 dk okuma
Sidecar'sız Service Mesh Nedir? Neyi Çözer, Kazanımları ve WireGuard ile Mutual Auth'lu Bir Cilium Lab'ı - platform-mühendisliği yazısının kapak görseli

Çoğu Kubernetes cluster'ında farklı node'lardaki pod'lar arasındaki trafik şifrelenmiyor. Lab cluster'ımın bir node'unda paket yakaladım ve iki pod arasındaki HTTP isteklerini düz metin olarak okudum. Bunun bilinen cevabı service mesh, service mesh de genelde her pod'a fazladan bir proxy container demek. Bu yazıda sidecar'sız service mesh'in ne olduğuna, neyi çözdüğüne ve ne kazandırdığına bakıyorum; sonra Cilium'un mesh işlerini tek bir sidecar olmadan yaptığı lab'ı gösteriyorum: şifreleme, kimlik, HTTP görünürlüğü ve traffic split. Birkaç yerde patladı; gerçek mesajlarıyla sonda.

Sidecar'sız service mesh nedir?

Service mesh, cluster'daki servisler için dört işi uygulamaların yerine üstlenen bir katman:

  • Şifreleme: servisler arası trafik ağda okunamaz.
  • Kimlik: bir servis sadece tanıdığı servislerden gelen isteği kabul eder.
  • Görünürlük: hangi servisin hangisini çağırdığını method, path ve status kodu ile görürsünüz.
  • Trafik yönetimi: trafiği sürümler arasında bölmek, header'a göre yönlendirmek.

Klasik yol (Istio, Linkerd) her uygulama container'ının yanına bir proxy sidecar container'ı koyuyor. Bütün trafik ondan geçiyor.

Sidecar'sız mesh aynı işleri pod başına değil node başına bir kez yapıyor. Cilium'da şifreleme Linux kernel'inde WireGuard ile oluyor, HTTP seviyesindeki işler node başına tek bir Envoy'dan (cilium-envoy) geçiyor, kimlik de SPIRE üzerinden SPIFFE ile geliyor. Pod'lar olduğu gibi kalıyor.

Neyi çözüyor?

Düz metin trafik. Varsayılan olarak node'lar arası pod trafiğini hiçbir şey şifrelemiyor. Ağı görebilen herkes (ele geçirilmiş bir node, aynalanmış bir switch portu, bulut ağında bir dinleme noktası) okuyabiliyor. Lab'da tek bir node'daki tek bir yakalama GET / HTTP/1.1, Host header'ı ve 200 OK'i gösterdi.

Sidecar'ın maliyeti. Sidecar her pod'da bir container daha demek: her deploy'da enjekte ediliyor, her pod'da bellek ve CPU istiyor, mesh güncellenince yeniden başlatılması gerekiyor, her kubectl exec "hangi container?" diye soruyor. Birçok ekip için mesh'i hiç açmamalarının sebebi bu maliyet.

"Kim kimi çağırdı?" Mesh olmadan ağ sadece IP ve port görüyor. Bir şey 500 döndüğünde hangi çağıranın, hangi path'in, ne kadar sürdüğünü göremiyorsunuz.

Cilium'un sidecar'sız mesh'i ne kazandırıyor?

Kazanım Pratikte anlamı Lab'da
Uygulamaya dokunmadan şifreleme Node'lar arası WireGuard, kernel'de; pod'ların haberi yok Yakalamada okunur HTTP satırı: önce 6, sonra 0
Küçük bir anahtar İki Helm değeri ve agent restart'ı Üç node'da 31 sn
Servisler arası kimlik kontrolü authentication.mode: required olan bir policy; agent'lar SPIFFE el sıkışması yapıyor Intruder pod'u zaman aşımına düştü; client ~1 sn'lik el sıkışmadan sonra 200 aldı
HTTP görünürlüğü L7 kuralı trafiği node'daki Envoy'dan geçiriyor; Hubble method, path, status gösteriyor İstek başına GET /headers → 200 2ms
Standart traffic split GAMMA: parent'ı Service olan bir Gateway API HTTPRoute'u 90/10'da 50 istek: 46 / 4
Pod başına ek bileşen yok Envoy ve SPIRE agent node başına çalışıyor 0 sidecar

Karar vermeden önce neyi almadığınızı da bilin:

İhtiyaç Cilium 1.20
Retry, timeout, circuit breaking Sadece ham Envoy konfigürasyonu ile (CiliumEnvoyConfig), az doğrulama
Pod içinde sertifika (uygulama seviyesinde mTLS) Yok. Şifreleme node'da oluyor; pod hiç sertifika görmüyor
Cluster'lar arası kimlik Yok. Mutual auth 1.20'de Cluster Mesh ile çalışmıyor
Uzun vadede mutual auth 1.20'de deprecated, 1.21'de kaldırıldı. Upgrade notları yerine ztunnel transparent encryption'ı gösteriyor

Mutual auth'u yine de gösteriyorum, çünkü policy modeli (authentication.mode: required) yerine gelen yapıda da karşınıza çıkacak.

Nasıl çalışıyor?

Diyagram: solda her pod'da bir proxy container'ı olan sidecar mesh; sağda düz uygulama pod'ları ve altında kernel'de WireGuard, cilium-envoy ve SPIRE agent'tan oluşan tek bir node katmanı olan Cilium. Altta lab sonuçlarıyla dört mesh işi: şifreleme 6'dan 0 okunur satıra, kimlik: intruder zaman aşımı, görünürlük: GET /headers 200, traffic split 50'nin 46'sı v1'e

  • Şifreleme: her Cilium agent bir WireGuard arayüzü (cilium_wg0) açıyor ve public key'ini Kubernetes üzerinden paylaşıyor. Başka bir node'a giden pod trafiği bu arayüzden, şifreli olarak, UDP 51871 portunda gidiyor.
  • Kimlik: Cilium her pod grubuna label'larından türeyen sayısal bir kimlik veriyor zaten. Mutual auth açıkken operator bu kimlikleri SPIRE'a kaydediyor; iki kimlik arasındaki ilk paket geçmeden önce iki taraftaki agent'lar birbirinin SPIFFE sertifikasını kontrol ediyor.
  • Görünürlük ve traffic split: bir L7 kuralı ya da bir HTTPRoute trafiği node'daki cilium-envoy'dan geçiriyor; Envoy her isteği Hubble'a bildiriyor, ağırlık ve header eşleşmelerini uyguluyor.

Lab: ne kurdum

Her şey bir MacBook'ta kind üzerinde (Colima, 4 CPU / 8 GB, WireGuard modüllü 6.8 kernel): Kubernetes 1.37, Cilium 1.20.2, Cilium chart'ından SPIRE 1.15.3, Gateway API v1.6.1. İki podinfo sürümü bir worker node'da; client ve intruder pod'ları diğerinde, böylece trafikleri node'lar arasından geçmek zorunda. Aynı node'daki pod'lar hiç WireGuard'dan geçmiyor. Lab'ın tamamı son koşuda yaklaşık 4 dakika sürdü.

Adım 1: Trafiği oku, sonra şifrele

Önce şifresiz yakalama. podinfo node'unda tcpdump'lı küçük bir hostNetwork pod'u, client üç istek gönderirken eth0'ı dinledi. 80 paketin içinde 6 okunur HTTP satırı vardı: istek satırı, Host ve User-Agent header'ları ve cevap status'u.

Şifresiz node'da tcpdump: 8472 portunda VXLAN paketleri, içlerinde okunur GET / HTTP/1.1, Host podinfo:9898, User-Agent curl ve HTTP/1.1 200 OK; 80 pakette 6 HTTP satırı

Sonra iki Helm değeri (encryption.enabled: true, encryption.type: wireguard) ve Cilium agent'larının restart'ı. 31 saniye sonra her agent, diğer her node için birer tane olmak üzere 2 peer ile WireGuard bildirdi.

make encrypt: üç Cilium agent'ı da cilium_wg0 üzerinde Encryption Wireguard, port 51871, peers 2 bildiriyor

Aynı yakalama bundan sonra: sadece 51871 portunda UDP paketleri, 80 pakette 0 okunur HTTP satırı. Uygulamalar değişmedi, Cilium agent'ları dışında hiçbir pod yeniden başlamadı.

WireGuard açıkken aynı yakalama: node'lar arasında 51871 portunda UDP paketleri, okunur HTTP yok, 80 pakette 0 satır

Adım 2: Kimlik yoksa giriş yok

SPIRE, Cilium chart'ıyla geliyor. Server sağlıklıydı, üç node agent'ı da doğrulanmıştı ve operator podinfo'nun Cilium kimliğini bir SPIFFE ID olarak kaydetmişti.

make spire: server healthy, 3 doğrulanmış agent ve podinfo'nun 18935 kimliği için spiffe://spiffe.cilium/identity/18935 SPIFFE ID'li, parent'ı cilium-operator olan bir kayıt

Sonra podinfo'ya bir policy: client'ı kabul et ve kimlik doğrulaması iste. Policy'nin izin vermediği intruder zaman aşımına düştü. Client 200 aldı, ama ilk istek yaklaşık bir saniye sürdü: bu iki agent arasındaki el sıkışma. Hubble düşürülen SYN paketlerini Authentication required ile gösterdi, geçen akışlarda da auth_type: SPIRE vardı.

authentication.mode required: intruder 000 exit 28 zaman aşımı; client 1,04 sn ve 1,01 sn'de 200; Hubble podinfo-v1 ve podinfo-v2 için Authentication required DROPPED ve geçen 2 akışta auth_type SPIRE gösteriyor

İki istek, iki kez birer saniye bekleme: podinfo v1 ve v2 farklı label'lar taşıyor, yani iki ayrı kimlik ve her biri kendi ilk el sıkışmasını ödüyor. Tek bir Deployment'ın on replikası tek kimlik, tek el sıkışma olurdu.

Adım 3: Sidecar olmadan HTTP'yi gör

9898 portunda tüm HTTP'ye izin veren bir L7 kuralı, o trafiği node'daki Envoy'dan geçirmeye yetiyor. Bundan sonra Hubble her isteği method, URL, status ve süre ile gösterdi.

L7 kuralı ile Hubble: podinfo-v1 ve podinfo-v2 için http-request GET http://podinfo:9898/headers ve 0 ile 2 ms arası http-response HTTP/1.1 200

Adım 4: GAMMA ile cluster içinde traffic split

GAMMA, Gateway API'nin cluster içi trafik için olan kısmı: parent'ı Gateway yerine bir Service olan HTTPRoute. 90 ve 10 ağırlıkla 50 isteğin 46'sı v1'e, 4'ü v2'ye gitti (önceki koşularda 44/6 ve 45/5). İkinci bir kuralla x-canary: true header'lı istekler v2'ye gitti.

GAMMA: HTTPRoute Accepted ve ResolvedRefs; 50 istek 46 v1 ve 4 v2 sayıldı; x-canary header'ı ile cevap v2, header'sız v1

Son kontrol

make verify: Cilium ve Envoy DaemonSet OK; üç agent da WireGuard'da; iki policy de geçerli; HTTPRoute ve ondan üretilen CiliumEnvoyConfig var; header kuralı hâlâ yerinde olduğu için 20 isteğin hepsi v1'e

Nerede patladı: 3 gerçek hata

1. SPIRE server 1/2'de kaldı: Starting Server APIs'ten hemen sonra Stopping Server APIs

Chart varsayılanlarıyla SPIRE server hiç hazır olmadı, node agent'ları Init:Error'da bekledi. Log'da gerçek bir hata yoktu. Sebep: server uid 1000 ile çalışıyor, ama socket klasörü root olarak oluşturulan bir host path, bu yüzden socket'i bağlamak sessizce başarısız oluyor (cilium/cilium#40533). Lab'ın values dosyasındaki çözüm server'ı root olarak çalıştırmak (securityContext.runAsUser: 0); chart SPIRE 1.9'dan önce böyle davranıyordu.

İlk deneme: spire-server-0 readiness probe reddedilerek 1/2'de, agent'lar Init:Error'da; log Starting Server APIs sonra Stopping Server APIs ve Notifier failed; sebep uid 1000 ile root socket yolu, çözüm runAsUser 0

2. Ayar açık diyor, agent'lar Encryption: Disabled diyor

Şifreleme açık helm upgrade STATUS: deployed döndü, Cilium ConfigMap'i de enable-wireguard: true diyordu. Üç agent da hâlâ Disabled diyordu. Helm sadece konfigürasyonu yeniden yazıyor; agent'lar onu açılırken okuyor. cilium DaemonSet'ini yeniden başlattıktan sonra (27 sn) üçü de WireGuard'daydı. Hiçbir şey uyarmıyor. Agent'lara bakmazsanız trafiğin şifreli olduğunu sanıyorsunuz, oysa değil.

Şifreleme açık helm upgrade: STATUS deployed, ConfigMap enable-wireguard true, ama üç agent da Encryption Disabled; 27 sn'lik rollout restart'tan sonra üçü de 2 peer ile Wireguard

3. failed to get certificate for local identity: auth testi çok erken koştu

İlk seferinde auth policy'sini SPIRE açılır açılmaz uyguladım, client da zaman aşımına düştü. Operator kimlikleri SPIRE'a kendi takvimiyle kaydediyor ve o anda podinfo'nun kaydı henüz yoktu (Found 0 entries). Üç dakika sonra aynı test geçti. Policy'yi suçlamadan önce SPIRE kaydını kontrol edin.

Bir pratik not: kind node image'ında tcpdump yok. Lab yakalamayı node'a sabitlenmiş, hostNetwork'lü bir nicolaka/netshoot pod'undan yapıyor; o pod aynı eth0'ı görüyor.

Ne zaman kullanılır, ne zaman kullanılmaz

Durum Tercih
Cilium zaten network plugin'iniz; node'lar arası şifreleme, HTTP görünürlüğü ve basit split istiyorsunuz Cilium'un sidecar'sız mesh'i. Pod başına yeni bileşen yok.
Retry, timeout, fault injection ya da outlier detection her gün lazım Istio ambient (o da sidecar'sız: node başına ztunnel, L7 için waypoint proxy).
Regülasyon uygulamanın içinde sertifika istiyor (uçtan uca mTLS) Uygulama seviyesinde mTLS olan bir mesh; Cilium node'da şifreliyor.
Uzun vadede servis kimliği lazım ztunnel'i planlayın; Cilium'un SPIFFE mutual auth'u 1.20'de deprecated, 1.21'de kaldırıldı.

Özet

  • Sidecar'sız service mesh şifreleme, kimlik, görünürlük ve trafik yönetimini pod başına değil node başına bir kez yapıyor.
  • Cilium ile WireGuard ağdaki okunur HTTP'yi 31 saniyede, uygulamalara dokunmadan 6 satırdan 0'a indirdi.
  • SPIFFE mutual auth izni olmayan bir pod'u engelledi; bedeli kimlik başına ilk istekte yaklaşık bir saniye, ve 1.20'de deprecated.
  • Bir L7 kuralı Hubble'da HTTP görünürlüğü verdi, GAMMA cluster içi trafiği 90/10'da 46/4 böldü.
  • helm upgrade'den sonra agent'ları mutlaka kontrol edin: ayar açık görünürken şifreleme kapalı olabilir.

Kaynaklar: Cilium dokümanı Transparent Encryption (WireGuard), Mutual Authentication (Beta), Layer 7 Protocol Visibility ve Gateway API GAMMA support; Cilium 1.20 upgrade notları; cilium/cilium#40533 ve #47132; Gateway API GAMMA girişimi.

Seride sıradaki

Bu, Cilium Uçtan Uca serisinin beşinci yazısı. Sonraki: Cilium Cluster Mesh: kind'da İki Cluster, Global Service ve Cluster'lar Arası Policy. Önceki yazı: Cilium Gateway API Nedir? Neyi Çözer, Kazanımları ve Ayrı Ingress Controller Olmadan Bir Lab.

Bu lab'ın kodu (kind yapılandırması, SPIRE düzeltmeli mesh ve şifreleme values'ları, podinfo/client/intruder manifest'i, iki policy, iki GAMMA route'u, yakalama ve auth script'leri ve Makefile) Buy Me a Coffee'deki Lab Access üyeleriyle paylaşılıyor; üye olduktan sonra repo daveti e-postayla geliyor: https://buymeacoffee.com/miraccanyilmaz/membership

Hayatta en hakiki mürşit ilimdir.
Mustafa Kemal Atatürk