Tek kişilik bir kümede herkes cluster-admin olur ve kimse fark etmez. Ama ekibe üçüncü kişi katıldığı gün, staging ortamında test yapan biri yanlışlıkla üretim namespace'indeki bir Deployment'ı sildiğinde işler değişir. Kubernetes namespace ve RBAC, tam olarak bu anı önlemek için var: namespace kaynakları mantıksal olarak ayırır, RBAC ise kimin hangi namespace'te ne yapabileceğini tanımlar.
İki mekanizma sık sık birbirine karıştırılıyor. Namespace tek başına bir güvenlik sınırı değildir — sadece isim alanıdır; kubectl get pods -n uretim yazan herkes o pod'ları görür, RBAC engellemedikçe. RBAC ise namespace olmadan da çalışır ama pratikte anlamlı bir yetki modeli kurmak için ikisi birlikte kullanılır. Bu rehberde önce namespace'i kaynak kotalarıyla birlikte kuracağız, sonra bir geliştiriciye yalnızca kendi namespace'inde çalışma yetkisi veren eksiksiz bir RBAC yapılandırması yazacağız ve bunu doğrulayacağız.
Namespace Tam Olarak Neyi Ayırır#
Namespace, kümedeki adlandırılmış kaynakları (Pod, Service, Deployment, ConfigMap, Secret, PVC ve benzerleri) gruplayan bir kapsayıcıdır. Aynı isimde iki Deployment farklı namespace'lerde sorunsuz yaşayabilir. DNS de bu ayrımı izler: uretim namespace'indeki api servisine staging namespace'inden erişmek için api.uretim.svc.cluster.local yazman gerekir, sadece api yazarsan kendi namespace'inde arar.
Ama namespace'in ayırmadığı şeyler de var ve bunları bilmemek yanlış bir güvenlik hissi yaratıyor. Düğümler, PersistentVolume'lar, StorageClass'lar, ClusterRole'lar ve CustomResourceDefinition'lar namespace'e ait değildir; küme genelindedir. Ağ trafiği de varsayılan olarak namespace tanımaz — staging içindeki bir pod, uretim içindeki bir pod'un IP'sine doğrudan bağlanabilir. Bunu engellemek için NetworkPolicy yazman gerekir. Docker tarafında ağ izolasyonunun nasıl kurulduğunu gördüysen mantık tanıdık gelecektir; ayrıntılar Docker network yapılandırma yazısında.
| Kaynak | Namespace'e ait mi | Not |
|---|---|---|
| Pod, Deployment, Service | Evet | Namespace başına ayrı isim alanı |
| ConfigMap, Secret, PVC | Evet | Namespace dışından okunamaz |
| Role, RoleBinding | Evet | Yalnızca kendi namespace'inde geçerli |
| Node, PersistentVolume | Hayır | Küme geneli |
| ClusterRole, ClusterRoleBinding | Hayır | Tüm namespace'leri kapsar |
| StorageClass, CRD | Hayır | Küme geneli |
Namespace'e ait olan kaynakların listesini kendi kümene sorabilirsin:
# Namespace'e ait kaynak tiplerini listele
kubectl api-resources --namespaced=true | head -20
# Küme geneli olanlar
kubectl api-resources --namespaced=false | head -20
Namespace Oluşturma ve Kaynak Kotası Koyma#
Namespace oluşturmak tek komut, ama üretimde onu kotasız bırakmak hata. Kotasız bir namespace'te tek bir hatalı manifest (örneğin maxReplicas: 500 yazılmış bir HPA) tüm kümenin CPU'sunu tüketebilir. Bu yüzden namespace'i her zaman bir ResourceQuota ve bir LimitRange ile birlikte kur.
# Namespace oluştur
kubectl create namespace staging
# Etiketle (NetworkPolicy ve araçlar için işe yarar)
kubectl label namespace staging ortam=staging
# staging-kota.yaml
apiVersion: v1
kind: ResourceQuota
metadata:
name: staging-kota
namespace: staging
spec:
hard:
requests.cpu: "4" # namespace toplamı 4 çekirdek isteyebilir
requests.memory: 8Gi
limits.cpu: "8"
limits.memory: 16Gi
pods: "40"
persistentvolumeclaims: "10"
---
apiVersion: v1
kind: LimitRange
metadata:
name: staging-varsayilan
namespace: staging
spec:
limits:
- type: Container
default: # limit yazılmamış container'a uygulanır
cpu: 500m
memory: 512Mi
defaultRequest: # request yazılmamış container'a uygulanır
cpu: 100m
memory: 128Mi
LimitRange özellikle önemlidir çünkü ResourceQuota içinde requests.cpu tanımlıysa, request'i olmayan bir pod hiç kabul edilmez — deploy "failed quota" hatasıyla reddedilir. LimitRange bu boşluğu varsayılan değerle doldurur ve ekibin her manifestte request yazmayı unutması üretimi durdurmaz. Kotanın ne kadarını kullandığını görmek için:
kubectl describe resourcequota staging-kota -n staging
# Name: staging-kota
# Resource Used Hard
# requests.cpu 1200m 4
# requests.memory 2Gi 8Gi
# pods 7 40
Kota değerlerinin HPA ile otomatik ölçekleme tavanını da sınırladığını unutma: maxReplicas: 20 yazsan bile kota dolduğunda yeni pod açılmaz.
RBAC'ın Dört Nesnesi#
RBAC yalnızca dört nesne tipinden oluşur ve mantığı bir kez oturduğunda çok basittir. Role ve ClusterRole ne yapılabileceğini tanımlar; RoleBinding ve ClusterRoleBinding bu yetkiyi kime verdiğini söyler. Tek başına bir Role hiçbir şey yapmaz; mutlaka bir binding ile birine bağlanması gerekir.
| Nesne | Kapsamı | Tipik kullanım |
|---|---|---|
| Role | Tek namespace | Ekibin kendi namespace'indeki yetkileri |
| ClusterRole | Küme geneli | Node okuma, CRD yönetimi, ortak şablon |
| RoleBinding | Tek namespace | Role veya ClusterRole'ü bir namespace'e bağlar |
| ClusterRoleBinding | Küme geneli | Küme yöneticisi yetkisi |
Kafa karıştıran nokta şudur: bir RoleBinding, bir ClusterRole'ü referans alabilir. Bu son derece kullanışlı bir kalıptır — yetki şablonunu bir kez ClusterRole olarak yazarsın, sonra her namespace'te bir RoleBinding ile bağlarsın ve yetki sadece o namespace içinde geçerli olur. Tersi geçerli değildir: ClusterRoleBinding bir Role'ü referans alamaz.
Kubernetes kurulumla birlikte hazır gelen dört ClusterRole'ü de bilmen işini kısaltır: cluster-admin (her şey), admin (namespace içinde her şey artı RoleBinding yönetimi), edit (kaynak oluşturup silebilir ama RBAC'e dokunamaz), view (yalnızca okur, Secret'ları okuyamaz). Çoğu ekip için sıfırdan Role yazmak yerine bunları bağlamak yeterlidir.
# Hazır rolleri listele
kubectl get clusterroles | grep -E '^(admin|edit|view|cluster-admin)'
# Bir rolün içinde ne olduğunu gör
kubectl describe clusterrole view | head -30
Bir Geliştiriciye Namespace Yetkisi Vermek#
Şimdi somut bir senaryo kuralım: staging namespace'inde çalışacak bir CI hesabı istiyorsun. Bu hesap Deployment'ları güncelleyebilsin, pod loglarını okuyabilsin, ama Secret'ları okuyamasın ve başka namespace'e dokunamasın. Önce ServiceAccount'u oluştur:
kubectl create serviceaccount ci-deploy -n staging
Sonra yetkiyi tanımla. Burada hazır edit rolü Secret okumaya da izin verdiği için kendi Role'ümüzü yazıyoruz:
# staging-ci-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: ci-deploy
namespace: staging
rules:
- apiGroups: ["apps"]
resources: ["deployments", "replicasets", "statefulsets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: [""] # çekirdek API grubu
resources: ["pods", "pods/log", "services", "configmaps"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["events"]
verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: ci-deploy
namespace: staging
subjects:
- kind: ServiceAccount
name: ci-deploy
namespace: staging
roleRef:
kind: Role
name: ci-deploy
apiGroup: rbac.authorization.k8s.io
Dikkat edilecek üç ayrıntı var. Birincisi, apiGroups: [""] boş dize çekirdek API grubunu (Pod, Service, ConfigMap) temsil eder; apps ise Deployment ve StatefulSet'in bulunduğu gruptur. Yanlış gruba yazılan bir kural sessizce hiçbir işe yaramaz. İkincisi, pods/log ayrı bir alt kaynaktır; pods yetkisi vermek log okuma yetkisi vermez. Üçüncüsü, RBAC yalnızca izin verir, hiçbir zaman yasaklamaz — "şunu yapamasın" diye bir kural yazamazsın, sadece o fiili listeye koymazsın.
Hesap için bir token üretip kubeconfig hazırlamak:
# Kısa ömürlü token üret (modern Kubernetes sürümlerinde)
kubectl create token ci-deploy -n staging --duration=8760h
Yetkileri Doğrulamak#
RBAC yazmanın en riskli tarafı, yanlış yazdığını ancak üretimde fark etmendir. Neyse ki Kubernetes yetkileri simüle etmen için hazır bir komut sunuyor ve bunu her RBAC değişikliğinden sonra çalıştırma alışkanlığı edinmeni öneririm:
# Kendi yetkini sorgula
kubectl auth can-i create deployments -n staging
# Başka bir kimliğin yetkisini simüle et
kubectl auth can-i delete pods -n uretim \
--as=system:serviceaccount:staging:ci-deploy
# Çıktı: no
kubectl auth can-i get pods/log -n staging \
--as=system:serviceaccount:staging:ci-deploy
# Çıktı: yes
# Bir kimliğin bir namespace'te yapabildiği HER ŞEYİ listele
kubectl auth can-i --list -n staging \
--as=system:serviceaccount:staging:ci-deploy
Son komut, RBAC hata ayıklamasının en değerli aracıdır: beklediğinden fazla satır görüyorsan bir yerde gereğinden geniş bir binding var demektir. Kim hangi role bağlı diye tersten bakmak istersen:
# Bir namespace'teki tüm binding'leri özetle
kubectl get rolebindings,clusterrolebindings -A \
-o custom-columns='NS:.metadata.namespace,AD:.metadata.name,ROL:.roleRef.name' | grep staging
Bu komutları CI hattına bir doğrulama adımı olarak koymak, RBAC'in zamanla sessizce genişlemesini engeller. GitHub Actions veya GitLab CI hattında deploy adımından önce kubectl auth can-i --list çalıştırıp çıktıyı beklenen listeyle karşılaştırmak beş satırlık bir iş, ama ilerideki bir yetki kaymasını anında yakalar.
Pod İçinden API'ye Erişim ve ServiceAccount#
Her pod, belirtmezsen namespace'in default ServiceAccount'uyla çalışır ve bu hesabın token'ı container içine /var/run/secrets/kubernetes.io/serviceaccount/token yolunda otomatik bağlanır. Uygulaman Kubernetes API'sini hiç kullanmıyorsa bu token gereksiz bir risktir: container'a sızan biri, o hesabın yetkisi kadar kümede iş yapabilir.
İki basit önlem var. Birincisi, API'ye ihtiyacı olmayan iş yüklerinde token bağlamayı kapatmak:
spec:
template:
spec:
automountServiceAccountToken: false # token container'a hiç girmesin
containers:
- name: web
image: nginx:stable
İkincisi, API'ye gerçekten ihtiyacı olan pod'lara default yerine kendi ServiceAccount'unu vermek ve o hesabın Role'ünü minimum tutmak:
spec:
template:
spec:
serviceAccountName: konfig-okuyucu
Pod içinden yetkiyi test etmek istersen container'a girip API'yi doğrudan çağırabilirsin — container içine exec ile bağlanma alışkanlığın burada da işe yarıyor:
kubectl exec -it deploy/web -n staging -- sh -lc '
TOKEN=$(cat /var/run/secrets/kubernetes.io/serviceaccount/token)
curl -sk -H "Authorization: Bearer $TOKEN" \
https://kubernetes.default.svc/api/v1/namespaces/staging/pods | head -5'
Sık Yapılan Hatalar ve Tuzaklar#
Herkese cluster-admin bağlamak. "Şimdilik çalışsın, sonra daraltırız" diye kurulan ClusterRoleBinding hiçbir zaman daraltılmaz. Başlangıçta bile edit rolünü tek bir namespace'e RoleBinding ile bağlamak neredeyse aynı hızda kurulur ve blast radius'u küme genelinden tek namespace'e indirir.
namespace alanını binding'in subject bölümünde unutmak. RoleBinding içindeki subjects listesinde ServiceAccount tanımlarken namespace alanı zorunludur; yazmazsan binding'in kendi namespace'i varsayılır ve farklı namespace'teki bir hesabı bağlamaya çalışıyorsan sessizce yanlış hesabı bağlarsın. Hata mesajı çıkmaz, sadece yetki çalışmaz.
Namespace'i güvenlik sınırı sanmak. Namespace ağ trafiğini ayırmaz. staging içindeki bir pod, uretim içindeki veritabanı servisine erişebilir. Gerçek izolasyon için NetworkPolicy tanımlaman ve kümede bunu uygulayan bir CNI eklentisi bulunması gerekir.
Secret okuma yetkisini fark etmeden vermek. Hazır edit ve admin rolleri, bulundukları namespace'teki Secret'ları okuyabilir. Veritabanı şifresi orada duruyorsa, edit verdiğin kişiye aslında üretim şifresini vermiş olursun. Secret erişimini ayrı bir Role'de tutup yalnızca gerekli hesaplara bağlamak daha sağlıklıdır.
Namespace'i silerken içindekileri unutmak. kubectl delete namespace komutu içindeki tüm kaynakları da siler ve geri alınamaz. Namespace'i silmeden önce içindeki PVC'leri listelemek ve gerekiyorsa yedeklemek iyi bir alışkanlıktır; kalıcı veri stratejisi için Docker volume veri yönetimi yazısındaki mantık Kubernetes PVC'leri için de geçerlidir.
Sıkça Sorulan Sorular#
Namespace tek başına güvenlik sağlar mı#
Hayır. Namespace bir isim alanıdır, güvenlik sınırı değildir. RBAC ile kısıtlanmamış bir kullanıcı -n bayrağını değiştirerek başka namespace'lerdeki kaynakları görebilir ve değiştirebilir. Ayrıca namespace ağ trafiğini de ayırmaz; pod'lar varsayılan olarak birbirine erişir. Gerçek izolasyon için namespace, RBAC ve NetworkPolicy üçünün birlikte kurulması gerekir.
Role ile ClusterRole arasındaki fark nedir#
Role yalnızca tanımlandığı namespace içinde geçerlidir; ClusterRole ise küme genelinde tanımlıdır ve namespace'e ait olmayan kaynaklara (Node, PersistentVolume gibi) yetki verebilir. Pratikte yaygın kalıp, yetki şablonunu bir kez ClusterRole olarak yazıp her namespace'te bir RoleBinding ile bağlamaktır — böylece yetki tek namespace'le sınırlı kalır ama şablonu bir kez tanımlarsın.
Bir kullanıcının yetkisini nasıl kontrol ederim#
kubectl auth can-i komutu bunun için var. Tek bir eylemi test etmek için kubectl auth can-i delete pods -n uretim --as=system:serviceaccount:staging:ci-deploy yazarsın, cevap yes veya no olur. Bir kimliğin bir namespace'te yapabildiği her şeyi görmek içinse kubectl auth can-i --list -n staging --as=... komutunu kullan; RBAC hata ayıklamasında en çok işe yarayan komut budur.
RBAC ile bir eylemi yasaklayabilir miyim#
Hayır, Kubernetes RBAC yalnızca izin verir. "Bu kişi Secret silmesin" şeklinde bir reddetme kuralı yazamazsın; yapman gereken, delete fiilini secrets kaynağı için hiç vermemektir. Bir kimlik birden fazla binding'e sahipse yetkiler birleşir, yani geniş olan kazanır. Bu yüzden fazladan bir binding bırakmak, dar yazdığın Role'ü tamamen anlamsız kılabilir.
Namespace silinince içindeki veriler ne olur#
Namespace silindiğinde içindeki tüm namespace'e ait kaynaklar silinir: Deployment'lar, Service'ler, ConfigMap'ler, Secret'lar ve PersistentVolumeClaim'ler. PVC silindiğinde arkasındaki PersistentVolume'un ne olacağını StorageClass'ın reclaimPolicy ayarı belirler; Delete ise disk de silinir, Retain ise volume kalır ama serbest duruma geçer. Silmeden önce kalıcı verileri yedeklemek şart.
Kaç namespace kullanmalıyım#
Yaygın ve iyi işleyen model, her ortam için bir namespace (uretim, staging, test) veya her ekip için bir namespace açmaktır. Uygulama başına ayrı namespace açmak küçük kümelerde gereksiz yönetim yükü yaratır; onlarca namespace'in her birine ayrı kota, RBAC ve NetworkPolicy yazmak zorunda kalırsın. Ayrımı, gerçekten farklı yetki veya kota isteyen sınırlara göre çiz.
Kapanış#
Namespace ve RBAC'i doğru kurmanın özeti şu dört alışkanlıkta: her namespace'i bir ResourceQuota ve LimitRange ile birlikte oluştur, hazır edit ve view rollerini sıfırdan Role yazmadan önce değerlendir, her RBAC değişikliğinden sonra kubectl auth can-i --list ile sonucu doğrula ve API'ye ihtiyacı olmayan pod'larda automountServiceAccountToken: false ayarını kullan. Bu dördü yerindeyse kümen büyüdükçe yetki modeli dağılmaz.
Kubernetes kümesini kendi donanımında çalıştırmak istiyorsan kontrol düzlemi ve düğümler için tam root erişimli VDS veya ihtiyaca göre büyüyen bulut sunucu paketlerimiz uygun bir başlangıç. Küme kurulumu, güncellemeleri ve yetki modelinin bakımıyla uğraşmak istemiyorsan sunucu yönetimi hizmetimiz bu işi sizin yerinize üstlenir; hesap parolalarını üretmek için de şifre üretici aracımızı kullanabilirsin.