Kubernetes’te Erişim Kontrolü: RBAC ile Yetki Yönetimi

Kubernetes cluster’ınızı kurdunuz, uygulamalarınız çalışıyor, her şey harika görünüyor. Peki kim neye erişebiliyor? Geliştirici takımınızdaki bir junior developer production namespace’ine pod silebiliyor mu? DevOps mühendisleriniz tüm cluster’a tam yetkiyle erişiyor mu? Eğer bu sorulara net cevap veremiyorsanız, RBAC konusunu ciddiye almanın tam zamanı.

Kubernetes’te Role-Based Access Control (RBAC), kullanıcıların ve servislerin cluster kaynakları üzerinde ne yapabileceğini tanımlayan yetki yönetim sistemidir. Doğru yapılandırılmış bir RBAC mimarisi, hem güvenlik açıklarını kapatır hem de ekiplerin kendi sorumluluk alanlarında rahatça çalışmasını sağlar. Bu yazıda gerçek dünya senaryolarıyla RBAC’ı A’dan Z’ye ele alacağız.

RBAC Nedir ve Neden Önemlidir?

Kubernetes 1.8 sürümünden itibaren varsayılan olarak aktif olan RBAC, “kim, neyi, nerede yapabilir?” sorusunu yanıtlar. Üç temel bileşenden oluşur:

  • Subject (Özne): Kim? Kullanıcılar, gruplar veya servis hesapları
  • Resource (Kaynak): Ne? Pod’lar, deployment’lar, secret’lar, node’lar
  • Verb (Eylem): Ne yapabilir? get, list, create, delete, update, patch, watch

RBAC olmadan veya kötü yapılandırılmış bir RBAC ile karşılaşabileceğiniz senaryolar şunlardır:

  • Bir geliştirici yanlışlıkla production secret’larını görüntüler
  • CI/CD pipeline’ı gereksiz yere cluster-admin yetkisiyle çalışır
  • Bir namespace’teki servis hesabı başka namespace’lerin kaynaklarına erişir
  • Stajyer hesabından kritik deployment silinir

Bu senaryoların her biri gerçek olaylardan ilham almıştır. RBAC bu riskleri minimize etmenin en etkili yoludur.

Temel Kavramlar: Role, ClusterRole, RoleBinding, ClusterRoleBinding

Role ve ClusterRole

Role, belirli bir namespace içinde geçerlidir. ClusterRole ise tüm cluster genelinde veya namespace bazlı kullanılabilir. Farkı şöyle düşünebilirsiniz: Role bir binadaki belirli bir odanın anahtarı, ClusterRole ise tüm binanın ana anahtarıdır.

# Mevcut role'leri listele
kubectl get roles -n development

# Mevcut clusterrole'leri listele
kubectl get clusterroles

# Bir role'ün detaylarını gör
kubectl describe role pod-reader -n development

RoleBinding ve ClusterRoleBinding

Role tanımlamak yetmez, bu rolleri öznelere bağlamanız gerekir. RoleBinding bir Role veya ClusterRole’ü belirli bir namespace içinde bir özneye bağlar. ClusterRoleBinding ise cluster genelinde bağlama yapar.

# Mevcut rolebinding'leri listele
kubectl get rolebindings -n development

# ClusterRoleBinding'leri listele
kubectl get clusterrolebindings

# Detaylı inceleme
kubectl describe rolebinding dev-pod-reader -n development

İlk RBAC Yapılandırması: Geliştirici Rolü Oluşturma

Gelin pratik bir senaryo üzerinden gidelim. Bir e-ticaret platformu yönetiyorsunuz ve şu namespace yapınız var: development, staging, production. Geliştirici ekibinizin development namespace’inde tam yetkiye, staging’de sadece okuma yetkisine, production’da ise hiçbir erişimi olmamasını istiyorsunuz.

Development Namespace için Role

# dev-full-access-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: development
  name: developer-full-access
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "pods/exec", "services", "configmaps"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "statefulsets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get", "list"]
kubectl apply -f dev-full-access-role.yaml

Dikkat edin: Secret’lar için sadece get ve list verdik, create veya delete vermedik. Geliştirici secret içeriğini görebilir ama yeni secret oluşturamaz veya mevcut olanı silemez. Bu pratikte çok işe yarayan bir ayrıntıdır.

Staging Namespace için ReadOnly Role

# staging-readonly-role.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: staging
  name: developer-readonly
rules:
- apiGroups: [""]
  resources: ["pods", "pods/log", "services", "configmaps", "endpoints"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "replicasets", "statefulsets"]
  verbs: ["get", "list", "watch"]
- apiGroups: [""]
  resources: ["events"]
  verbs: ["get", "list", "watch"]
kubectl apply -f staging-readonly-role.yaml

RoleBinding ile Kullanıcıya Atama

# dev-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ahmet-dev-access
  namespace: development
subjects:
- kind: User
  name: [email protected]
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-full-access
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: ahmet-staging-access
  namespace: staging
subjects:
- kind: User
  name: [email protected]
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-readonly
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f dev-rolebinding.yaml

# Ahmet'in yetkilerini doğrula
kubectl auth can-i create pods --namespace=development [email protected]
kubectl auth can-i delete secrets --namespace=development [email protected]
kubectl auth can-i create deployments --namespace=staging [email protected]
kubectl auth can-i get pods --namespace=production [email protected]

kubectl auth can-i komutu RBAC yapılandırmanızı test etmenin en hızlı yoludur. Bu komutu sık kullanın.

Servis Hesapları ve RBAC

Gerçek dünyada RBAC sadece insan kullanıcılar için değil, aynı zamanda pod’ların kullandığı servis hesapları için de kritiktir. Özellikle CI/CD araçları, monitoring sistemleri ve operatörler bu hesapları kullanır.

CI/CD Pipeline için Servis Hesabı

Bir Jenkins veya GitLab CI pipeline’ının deployment yapabilmesi için gereken minimum yetkiyi tanımlayalım:

# cicd-serviceaccount.yaml
apiVersion: v1
kind: ServiceAccount
metadata:
  name: cicd-deployer
  namespace: production
---
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: production
  name: deployer-role
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "update", "patch"]
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["replicasets"]
  verbs: ["get", "list", "watch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: cicd-deployer-binding
  namespace: production
subjects:
- kind: ServiceAccount
  name: cicd-deployer
  namespace: production
roleRef:
  kind: Role
  name: deployer-role
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f cicd-serviceaccount.yaml

# Servis hesabının tokenını al (Kubernetes 1.24 ve sonrası için)
kubectl create token cicd-deployer -n production --duration=8h

Bu yapılandırmayla CI/CD pipeline’ınız sadece deployment’ları güncelleyebilir, başka hiçbir şeye dokunamaz. “En az yetki prensibi” (principle of least privilege) budur.

ClusterRole ile Cluster Geneli Yetki Yönetimi

Monitoring ve logging sistemleri genellikle tüm namespace’lerdeki kaynaklara okuma yetkisi ister. Prometheus, Grafana Agent, Datadog gibi araçlar için ClusterRole kullanmak kaçınılmazdır.

# monitoring-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: monitoring-reader
rules:
- apiGroups: [""]
  resources: ["nodes", "nodes/metrics", "pods", "services", "endpoints", "namespaces"]
  verbs: ["get", "list", "watch"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets"]
  verbs: ["get", "list", "watch"]
- nonResourceURLs: ["/metrics", "/healthz", "/readyz"]
  verbs: ["get"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: prometheus-monitoring
subjects:
- kind: ServiceAccount
  name: prometheus
  namespace: monitoring
roleRef:
  kind: ClusterRole
  name: monitoring-reader
  apiGroup: rbac.authorization.k8s.io
kubectl apply -f monitoring-clusterrole.yaml

# Tüm cluster'da yetkileri doğrula
kubectl auth can-i list pods --all-namespaces --as=system:serviceaccount:monitoring:prometheus

Grup Bazlı Yetki Yönetimi

Büyük ekiplerde her kullanıcı için ayrı RoleBinding oluşturmak sürdürülemez hale gelir. OIDC veya LDAP entegrasyonuyla grup bazlı yetki yönetimi hayatı kolaylaştırır.

# group-rolebinding.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: backend-team-dev
  namespace: development
subjects:
- kind: Group
  name: backend-developers
  apiGroup: rbac.authorization.k8s.io
- kind: Group
  name: senior-developers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role
  name: developer-full-access
  apiGroup: rbac.authorization.k8s.io
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: devops-team-admin
subjects:
- kind: Group
  name: devops-engineers
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: cluster-admin
  apiGroup: rbac.authorization.k8s.io

Grup bazlı yönetimde dikkat edilmesi gereken nokta: cluster-admin rolünü gruba vermeden önce iki kez düşünün. Gerçekten tüm DevOps mühendislerinin cluster-admin olması gerekiyor mu? Çoğu durumda cevap hayırdır.

RBAC Audit ve Sorun Giderme

Mevcut Yetkileri Keşfetme

# Bir kullanıcının tüm yetkilerini listele
kubectl auth can-i --list [email protected] -n development

# Belirli bir servis hesabının yetkilerini kontrol et
kubectl auth can-i --list --as=system:serviceaccount:production:cicd-deployer -n production

# Tüm rolebinding'leri belirli bir kullanıcı için bul
kubectl get rolebindings,clusterrolebindings -A -o json | 
  jq '.items[] | select(.subjects[]?.name=="[email protected]") | .metadata.name'

API Server Audit Log ile RBAC İzleme

Production ortamında audit log etkinleştirmek RBAC sorunlarını tespit etmek için şarttır. API server’a şu parametreleri ekleyin:

# /etc/kubernetes/manifests/kube-apiserver.yaml içine eklenecek argümanlar
--audit-log-path=/var/log/kubernetes/audit/audit.log
--audit-log-maxage=30
--audit-log-maxbackup=10
--audit-log-maxsize=100
--audit-policy-file=/etc/kubernetes/audit-policy.yaml

Audit policy dosyası:

# audit-policy.yaml
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
- level: RequestResponse
  users: ["system:anonymous"]
  verbs: ["create", "update", "patch", "delete"]
- level: Metadata
  resources:
  - group: ""
    resources: ["secrets", "configmaps"]
- level: Request
  verbs: ["create", "update", "patch", "delete"]
  resources:
  - group: "apps"
    resources: ["deployments"]
- level: None
  verbs: ["get", "list", "watch"]
  resources:
  - group: ""
    resources: ["pods"]

Yaygın Hatalar ve Bunlardan Kaçınma Yolları

Üretim ortamlarında defalarca karşılaştığım hataları paylaşayım:

Wildcards Kullanımı

# YANLIS - Bunu yapmayın
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

# DOGRU - Açıkça tanımlayın
rules:
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["get", "list", "update", "patch"]

Wildcard kullanımı güvenlik açığı kapısı açar. “Şimdilik çalışıyor” dediğiniz şey ileride büyük sorun haline gelir.

Default Servis Hesabı Sorunları

Her namespace’te otomatik oluşan default servis hesabına herhangi bir yetki vermeyin. Pod’larınız için özel servis hesapları oluşturun:

# Her namespace'te automounting'i devre dışı bırak
kubectl patch serviceaccount default -n production -p '{"automountServiceAccountToken": false}'

# Yeni pod'lar için aynı ayarı varsayılan yap
# deployment yaml'ında:
# spec.template.spec.automountServiceAccountToken: false

ClusterRole ile Namespace Karışıklığı

# Bir ClusterRole, RoleBinding ile namespace'e özgü hale getirilebilir
# Bu yaygın ama gözden kaçan bir detay

# cluster-admin ClusterRole'ünü sadece development namespace'ine bağla
kubectl create rolebinding temp-admin 
  --clusterrole=cluster-admin 
  [email protected] 
  --namespace=development

Bu yaklaşım hem esneklik sağlar hem de ClusterRoleBinding’in tam cluster erişiminden kaçınmanıza yardımcı olur.

Gerçek Dünya Senaryo: Çok Ekipli Platform Yönetimi

Bir fintech şirketinde çalıştığınızı düşünün. Backend, Frontend, Data, SRE olmak üzere dört ekibiniz var. Her ekibin kendi namespace’i mevcut ve şu ihtiyaçları var:

  • Backend ekibi: Kendi namespace’inde tam yetki
  • Frontend ekibi: Kendi namespace’inde tam yetki, ama backend namespace’ini göremez
  • Data ekibi: Tüm namespace’lerde pod log’larını okuyabilir
  • SRE ekibi: Tüm cluster yönetimi yetkisi, ama node silme yetkisi yok
# sre-clusterrole.yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: sre-engineer
rules:
- apiGroups: [""]
  resources: ["nodes"]
  verbs: ["get", "list", "watch", "patch", "update"]
- apiGroups: [""]
  resources: ["namespaces", "pods", "services", "configmaps", "secrets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["apps"]
  resources: ["deployments", "statefulsets", "daemonsets", "replicasets"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
- apiGroups: ["networking.k8s.io"]
  resources: ["ingresses", "networkpolicies"]
  verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# Node silme yetkisi kasıtlı olarak dışarıda bırakıldı
kubectl apply -f sre-clusterrole.yaml

# SRE grubuna bağla
kubectl create clusterrolebinding sre-team-binding 
  --clusterrole=sre-engineer 
  --group=sre-engineers

# Test et - node silme olmamalı
kubectl auth can-i delete nodes --as-group=sre-engineers --as=test-user

Data ekibi için cross-namespace log okuma:

# Data ekibi için ClusterRole oluştur
kubectl create clusterrole data-log-reader 
  --verb=get,list,watch 
  --resource=pods,pods/log

# Data grubuna bağla
kubectl create clusterrolebinding data-team-logs 
  --clusterrole=data-log-reader 
  --group=data-engineers

RBAC Güvenlik Kontrolleri için Araçlar

Manuel kontroller yetersiz kalır. Birkaç araç sürecinizi otomatize etmenize yardımcı olur:

  • kubectl-who-can: Belirli bir kaynak üzerinde kim ne yapabilir sorusunu yanıtlar
  • rbac-lookup: Kullanıcı veya servis hesabı bazında yetki özeti çıkarır
  • kube-bench: CIS Kubernetes benchmark kontrolü yapar, RBAC ayarlarını da denetler
  • Polaris: Deployment konfigürasyonlarını tarar, RBAC best practice ihlallerini işaretler
# kubectl-who-can kurulumu ve kullanımı
kubectl krew install who-can
kubectl who-can delete pods -n production
kubectl who-can create secrets -n production

# Tüm cluster'da secret oluşturabilecekleri bul
kubectl who-can create secrets --all-namespaces

Bu komutun çıktısı genellikle şok edicidir. Production’da ilk çalıştırdığınızda beklenmedik kullanıcı ve servis hesaplarının hassas kaynaklara erişebildiğini görebilirsiniz.

RBAC Politika Belgeleme ve Sürdürülebilirlik

RBAC yapılandırmalarını Git’te tutmak ve her değişikliği pull request sürecinden geçirmek altın standarttır. Önerilen repo yapısı:

  • rbac/roles/ klasörü altında namespace bazlı Role dosyaları
  • rbac/clusterroles/ altında ClusterRole tanımlamaları
  • rbac/bindings/ altında tüm binding dosyaları
  • Her dosyada # Son güncelleme, # Güncellemeyi yapan, # Neden yorumları

Ayrıca RBAC değişikliklerini otomatik denetlemek için CI pipeline’ınıza şunu ekleyin:

# RBAC diff kontrolü - PR öncesi çalıştır
kubectl diff -f rbac/ -R

# Dry-run ile güvenli uygulama
kubectl apply -f rbac/ -R --dry-run=server

Sonuç

RBAC, Kubernetes güvenliğinin temel taşıdır ve doğru yapılandırılmadığında cluster’ınız ciddi risk altında demektir. Bu yazıda ele aldığımız konuları özetlersek:

  • Role ve ClusterRole arasındaki farkı ve ne zaman hangisini kullanacağınızı artık biliyorsunuz
  • En az yetki prensibi her yapılandırmada rehberiniz olmalı
  • Servis hesapları insan kullanıcılar kadar önemli, onları da RBAC kapsamına alın
  • kubectl auth can-i komutu en iyi arkadaşınız, sık kullanın
  • Wildcard yetki tanımlarından kesinlikle kaçının
  • Değişiklikleri Git’te takip edin, review sürecinden geçirin
  • kubectl-who-can gibi araçlarla periyodik denetim yapın

RBAC bir kez kurulup unutulan bir şey değildir. Ekip büyüdükçe, yeni servisler eklendikçe ve organizasyon yapısı değiştikçe RBAC yapılandırmanızı gözden geçirmeniz gerekir. Altı ayda bir kapsamlı bir RBAC audit yapma alışkanlığı edinin. Prodüksiyon’da “kim neye erişebilir?” sorusunu her zaman yanıtlayabilmek, hem güvenlik hem de compliance açısından hayat kurtarır.

Yorum yapın