GKE Binary Authorization ile Güvenli Dağıtım
Selamlar, bu yazımda GKE'nin Binary Authorization özelliğine bir göz atalım. Konu basit görünüyor ama altında ciddi bir tehdit modeli var: container supply chain saldırıları artık 'olur mu öyle bir şey' kategorisinden çıkalı epey oldu, SolarWinds'ten bu yana herkes bu konuyu biraz daha ciddiye alıyor. Hadi başlayalım.
Binary Authorization nedir?
Binary Authorization (Türkçe karşılığıyla ikili yetkilendirme), GKE cluster'ınıza deploy edilen her container imajının önceden tanımladığınız güvenilir bir otorite tarafından imzalanmış olmasını şart koşan bir deploy-time güvenlik kontrolü. Yani imzasız ya da yanlış imzalı bir image cluster'a girmek istediğinde admission controller onu kapıdan çevirir, log'a yazar ve pod hiç ayağa kalkmaz.
Mantık şu: build pipeline'ınız sonunda image'ı bir KMS anahtarıyla imzalıyor (buna 'attestation' deniyor), sonra GKE deploy sırasında bu attestation'ın varlığını ve geçerliliğini kontrol ediyor. Geçerse pod ayağa kalkar, geçmezse denied by Binary Authorization hatası alırsınız.
Hangi senaryoyu engelliyor?
Şahsi kanaatim, Binary Authorization'ın değerini anlamak için somut bir saldırı senaryosu üzerinden gitmek lazım. Şöyle bir durum düşünün:
- Saldırgan Artifact Registry hesabınıza bir şekilde push hakkı kazandı (sızdırılmış service account, ele geçirilmiş bir CI runner, fark etmez).
my-app:latesttag'ini kendi hazırladığı, içinde reverse shell olan bir image'a yönlendirdi.- Sıradaki HPA scale-up event'inde ya da rolling restart'ta yeni pod'lar bu image'ı çekiyor.
Binary Authorization olmadan bu senaryo sessizce çalışır. Cluster'da hiçbir alarm çalmaz çünkü teknik olarak image registry'den çekildi, deploy başarılı oldu, pod Running durumda. Binary Authorization devredeyse, saldırganın push'ladığı image attestation'a sahip olmadığı için admission aşamasında reddedilir. Pod ayağa kalkmaz, audit log'da kaydı görülür.
Politika nasıl görünür?
Bir Binary Authorization politikası kabaca şu yapıda:
admissionWhitelistPatterns:
- namePattern: gcr.io/google_containers/*
- namePattern: gke.gcr.io/*
defaultAdmissionRule:
evaluationMode: REQUIRE_ATTESTATION
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
requireAttestationsBy:
- projects/<ProjId>/attestors/build-attestor
clusterAdmissionRules:
us-central1-a.dev-cluster:
evaluationMode: ALWAYS_ALLOW
enforcementMode: ENFORCED_BLOCK_AND_AUDIT_LOG
Burada defaultAdmissionRule üretim için sıkı: her image build attestor tarafından imzalanmış olacak. Dev cluster'a ALWAYS_ALLOW koyduk çünkü geliştiricilerin local image'ları ile deneme yapması lazım. admissionWhitelistPatterns ise Google'ın kendi sistem image'larına bypass tanıyor - kube-proxy, metrics-server gibi şeylerin imzalı gelmesini bekleyemezsiniz.
Pipeline'a attestation eklemek
Cloud Build içinde attestation üretmek için tek satırlık bir komut var aslında:
gcloud container binauthz attestations sign-and-create \
--artifact-url='${RegImg}@${ImgDigest}' \
--attestor='build-attestor' \
--keyversion-keyring='binary-auth-keyring' \
--keyversion-key='attestor-key' \
--keyversion=1
Burada kritik nokta ${ImgDigest}. Tag değil, digest kullanmak zorundasınız. latest tag'i zamanla farklı digest'lere yönelebilir; ama sha256:... immutable. Attestation digest'e bağlanır, dolayısıyla aynı tag farklı bir image'a yönlense bile eski attestation yeni image'ı kapsamaz.
Geliştirici sürtünmesi - işin diğer yüzü
Açıkçası Binary Authorization'ı production'a sokmadan önce ekibe iyi anlatmak lazım çünkü hayatı bir miktar zorlaştırıyor. Geliştirici eskiden kubectl apply ile birkaç dakika içinde test image'ını cluster'a atarken, artık önce CI'dan geçirmek, attestation üretmek, sonra deploy etmek zorunda. 'Hızlıca bir şey deneyeceğim' refleksi kırılıyor.
Bana sorarsanız bu sürtünmenin çoğu doğru cluster ayrımıyla yönetilir: dev cluster'larında politika gevşek, staging'de orta, production'da sıkı. Geliştirici dev'de istediği gibi denesin, production'a sadece pipeline'dan imzalı image gitsin. Bu ayrımı yapmazsanız ekip ya breakglass annotation'ını sürekli kullanır (ki o zaman politika anlamını yitirir) ya da Binary Authorization'ı kapatmanız için baskı yapmaya başlar.
Sık karşılaşılan tuzaklar
- Tag ile attestation üretmeye çalışmak: Attestation digest'e bağlıdır.
:latestile attest edemezsiniz,gclouddigest'i kendisi çözmez; image'ı önce push edin, digest'i alın, ona attest edin. - Breakglass annotation'ı normal akışa sokmak:
alpha.image-policy.k8s.io/break-glass: 'true'gerçekten acil durum içindir. Pipeline'da kullanmaya başladığınız anda Binary Authorization süs olur. Audit log'da görünür ve denetim sırasında utanırsınız. - KMS key rotation'ı planlamamak: Attestor key'leri rotate edilmezse uzun vadede risk birikir. Yeni key version'ı eklediğinizde eskisini hemen silmeyin; eski attestation'lar geçerliliğini korusun.
- Dev cluster'ı whitelist'e almayı unutmak: Geliştirici local'den
kubectl applyile bir nginx pod'u atamayınca ortalık karışır. Dev cluster'ıALWAYS_ALLOWile başlatın.
Doğrulama
Politikanın gerçekten çalıştığını görmek için iki basit test:
kubectl run test-attested \
--image='${RegImg}@sha256:<AttestedDg>' \
--restart=Never
kubectl run test-unattested \
--image='${RegImg}@sha256:<RandomDg>' \
--restart=Never
İlki başarılı olmalı, ikincisinde denied by Binary Authorization cluster admission rule hatası dönmeli. İkinci komut hata vermiyorsa cluster üzerinde Binary Authorization aktif değil demektir; gcloud container clusters describe ile binaryAuthorization.evaluationMode değerini kontrol edin.
Kapanış
Binary Authorization, supply chain'inize sıkı bir kapı kuruyor: imzasız hiçbir image cluster'ınıza giremiyor. Bence orta-büyük ölçekli bir GKE kurulumunda artık opsiyonel sayılmaz, hele ki birden fazla ekibin aynı registry'ye push ettiği ortamlarda. Geliştirici sürtünmesini doğru cluster politikalarıyla yönetirseniz ek yük neredeyse görünmez olur, kazanç ise net. Umarım faydalı olur, bir sonraki yazıda görüşmek üzere.
