← blog · 1 Eylül 2026

Kubernetes'te Sır Yönetimi: Hangi Yaklaşımı Ne Zaman Seçmeli

Kubernetes'in yerleşik Secret nesnesi şifreleme değildir. Sealed Secrets, External Secrets Operator, SOPS ve Vault injector arasında seçim yaparken hangi soruları sormanız gerektiğini anlatıyoruz.

Kubernetes'in yerleşik Secret nesnesi, adının aksine bir şifreleme mekanizması değildir. Değerler base64 ile kodlanır, o kadar. etcd'de encryption-at-rest açık değilse veri düz metne çok yakın durur; açık olsa bile doğru RBAC izniyle get secrets yapabilen herkes değeri okuyabilir. Bunu bilmeden Secret nesnesini "şifreli" sanıp içeriğini Git'e commit eden ekipler az değildir.

Sorun burada başlar: sırrı nereye koyacaksınız, kim şifreleyecek, kim çözecek ve rotasyon geldiğinde kaç yeri güncellemeniz gerekecek? Dört yaygın yaklaşım var ve dördü de farklı bir varsayımla çalışıyor.

Önce taban: etcd encryption-at-rest

Hangi yaklaşımı seçerseniz seçin, bunun altına bir taban katmanı koymak gerekir: etcd'nin kendisinde encryption-at-rest'i açmak. EncryptionConfiguration ile bir KMS provider (bulut sağlayıcının kendi KMS'i ya da yerel bir anahtar) tanımlayıp API server'a --encryption-provider-config bayrağıyla verirsiniz; bundan sonra etcd'ye yazılan Secret nesneleri diskte şifreli durur. Bu, yukarıdaki dört yaklaşımdan hiçbirinin yerini tutmaz ama hepsinin ortak zafiyetini kapatır: etcd disk yedeğinin ya da snapshot'ının çalınması durumunda düz metin sızmasını engeller. Çoğu ekip bunu atlar çünkü "sır yönetimi aracı" listesine girmez, oysa en ucuz ve en temel önlemdir.

Sealed Secrets: Git'e commit edilebilir şifreli sır

Bitnami'nin Sealed Secrets'ı basit bir fikre dayanır: sırrı cluster'ın public key'iyle şifreleyip normal bir YAML dosyası gibi Git'e commit edersiniz. Cluster içindeki controller, kendi private key'iyle bunu çözüp gerçek bir Secret nesnesine dönüştürür.

kubectl create secret generic db-creds \
  --from-literal=password=degistir-bunu \
  --dry-run=client -o yaml > secret.yaml

kubeseal --format=yaml < secret.yaml > sealed-secret.yaml
git add sealed-secret.yaml

Avantajı açık: GitOps akışına hiç zorlanmadan oturur, harici bir sisteme bağımlılık yok, şifreli dosya deponuzda güvenle durur. Dezavantajı da aynı basitlikten geliyor. Private key yalnızca o cluster'da yaşar; yedeğini almazsanız cluster'ı kaybettiğinizde şifrelenmiş tüm sırlar da kaybolur, çünkü onları çözecek anahtar da gitmiştir. Rotasyon da elle yapılır: bir sırrı değiştirmek yeni bir kubeseal çalıştırıp yeni commit atmak demektir, otomatik bir tetikleyici yoktur.

External Secrets Operator: sırrın gerçek evi cluster dışında

External Secrets Operator (ESO), sırrı hiç Git'e koymaz. Vault, AWS Secrets Manager, Azure Key Vault ya da GCP Secret Manager gibi harici bir kaynaktan çeker ve düzenli aralıklarla senkronize ederek cluster içinde bir Secret nesnesi üretir.

apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
  name: db-creds
spec:
  refreshInterval: 1h
  secretStoreRef:
    name: vault-backend
    kind: SecretStore
  target:
    name: db-creds
  data:
    - secretKey: password
      remoteRef:
        key: secret/db
        property: password

Bunun gücü, sırrın tek gerçek kaynağının cluster dışında, merkezi bir sistemde olması. Çoklu cluster'ınız varsa hepsi aynı kaynaktan beslenir, rotasyon merkezi sistemde yapılır ve refreshInterval süresi içinde tüm cluster'lara yayılır. Ama dikkat: ESO sonunda yine bir Kubernetes Secret nesnesi üretir. Yani etcd'deki maruziyet problemi çözülmüş olmaz, sadece sırrın kaynağı ve rotasyonu merkezileşir. refreshInterval'i çok geniş bırakırsanız rotasyon beklediğinizden yavaş yayılır; env variable olarak inject edilen sırlar da pod restart olmadan güncellenmez, yalnızca volume mount edilenler canlı güncellenir.

SOPS: diff'i okunabilir tutan şifreleme

Mozilla'nın SOPS'u, YAML ya da JSON dosyalarındaki değerleri anahtar bazında şifreler; dosyanın yapısı ve anahtar isimleri düz metin kalır, yalnızca değerler şifrelenir. age ya da PGP ile çalışır, Flux'a native destek olarak gömülüdür, Argo CD için de eklenti (KSOPS gibi) mevcuttur.

Buradaki fark diff okunabilirliği: bir PR'da hangi anahtarın değiştiğini görürsünüz, değerini göremezsiniz ama yapıyı görürsünüz. Küçük ekiplerde bu, code review sürecine sırrı sokabilmenin en pratik yolu. Tuzağı .sops.yaml içindeki path regex'lerinde: bir dosya deseni yanlış yazılırsa o dosya şifrelenmeden commit edilir ve fark ancak birisi Git geçmişini tarayınca anlaşılır. Ayrıca anahtar rotasyonu, o anahtarla şifrelenmiş her dosyanın yeniden şifrelenmesini gerektirir; unutulan bir dosya eski anahtarla kilitli kalır.

Vault Agent Injector: sırrın hiç Secret nesnesine dönüşmediği yol

Bu dördü içinde en farklı yaklaşım budur. Vault'un injector'ü, pod'a bir mutating webhook üzerinden sidecar container ekler; bu sidecar Vault'tan sırrı çeker ve pod'un dosya sistemine (/vault/secrets/ altına) yazar. Sır hiçbir zaman bir Kubernetes Secret nesnesine dönüşmez, etcd'ye hiç uğramaz.

annotations:
  vault.hashicorp.com/agent-inject: "true"
  vault.hashicorp.com/role: "app"
  vault.hashicorp.com/agent-inject-secret-config: "secret/data/app/config"

Bunun karşılığı en iyi denetim izidir: her okuma Vault audit log'una düşer, kimin ne zaman hangi sırra eriştiği kayıt altındadır. Bedeli de var: her pod'a bir sidecar eklenir, pod başlatma süresi Vault'a bağımlı hale gelir, mutating webhook'un namespace selector'ı doğru daraltılmazsa ilgisiz pod'lara da enjeksiyon denenebilir ve o pod'lar Vault erişimi olmadan crash loop'a girer. Ayrıca Vault'un kendisi de bir sistemdir: unseal süreci, HA yapılandırması ve yedekleme stratejisi gerektirir. Sır yönetimi için bir bağımlılık daha eklemiş olursunuz.

Sidecar'ın getirdiği başlatma gecikmesini istemiyorsanız Secrets Store CSI Driver bir orta yol sunar. Aynı fikri, ayrı bir sidecar container yerine bir CSI volume üzerinden uygular: sır, pod başlarken bir tmpfs volume'e mount edilir, provider olarak Vault, AWS, Azure ya da GCP eklenebilir. İsterseniz secretObjects alanıyla aynı değeri bir Kubernetes Secret nesnesine de senkronize edebilirsiniz, ama bu adımı atlarsanız sır yine etcd'ye hiç uğramamış olur. Sidecar olmadığı için kaynak tüketimi Vault Agent Injector'a göre daha hafiftir, bedeli ise volume'ün pod'un container'ları arasında paylaşılan bir dosya sistemi olması: aynı node'daki başka bir pod'un aynı volume'e erişemediğinden emin olmak için hostPath değil CSI ephemeral volume kullanıldığından mutlaka emin olun.

Hangisi nerede

Tek cluster'lık, küçük bir ekip GitOps akışı kullanıyorsa Sealed Secrets ya da SOPS yeterlidir; harici bir sistem kurup işletmenin maliyeti kazandırdığından fazladır. Private key'in ya da SOPS'ta kullandığınız age anahtarının yedeğini almayı unutmayın, bu iki yaklaşımın da en sık düşülen tuzağı budur.

Çoklu cluster'ınız varsa ve zaten bir secret manager işletiyorsanız (Vault, bulut sağlayıcının kendi servisi), External Secrets Operator doğal seçimdir. Sırrı tek yerde tutup birden fazla cluster'a dağıtma ihtiyacı tam olarak bunun için var.

Denetim izi zorunluluğunuz varsa, ya da sırrın etcd'ye hiç uğramaması gerekiyorsa (finans, sağlık gibi düzenlemeye tabi ortamlar) Vault Agent Injector'ü ya da Secrets Store CSI Driver'ı değerlendirin. Ama bunu kurmadan önce Vault'u kim işletecek, unseal sürecini kim yönetecek sorularının cevabını verin; sır yönetimini basitleştirmek için kurduğunuz sistem, kendisi yönetilmesi gereken ayrı bir sisteme dönüşmemeli.

Hiçbiri tek başına "en iyi" değil. Sorulması gereken üç soru şu: rotasyonu kim tetikleyecek, cluster'ı kaybederseniz sırlarınız da kaybolacak mı, ve her okumanın kaydını tutmanız gerekiyor mu? Bu üç sorunun cevabı, dördü arasından hangisinin sizin için doğru olduğunu belirler.