Kubernetes Güvenliği: RBAC, Pod Güvenlik Standartları ve OPA Ağ Geçidi Bekçisi
Varsayılan ve şaşırtıcı derecede güvenli olmayan bir Kubernetes kümesi: kapsayıcılar çalışabilir kök olarak, ana bilgisayar düğümü dosya sistemini bağlayın, belirteci ile sunucu API'sine erişin Geniş izinlere sahip ServiceAccount. 2025'te ortamlardaki güvenlik olaylarının %68'i konteynerleştirilmiş, güvenlik açıklarından ziyade yapılandırma hatalarından kaynaklanıyordu yazılım (kaynak: Sysdig Container Security Report 2025). İyi haber: Kubernetes bu riskli kurulumları ortadan kaldırmak için güçlü araçlar sunar.
Bu makale tam bir küme sağlamlaştırmayı kapsar: RBAC kontrol etmek Kubernetes API ile kim ne yapabilir? Pod Güvenlik Standartları önlemek için ayrıcalıklı kapsayıcılar ve riskli yapılandırmalar, e OPA Bekçisi için "Tüm görseller nereden gelmeli" gibi özel şirket politikaları uygulayın dahili kayıt defteri" veya "kaynak sınırlaması olmadan dağıtım yok".
Ne Öğreneceksiniz
- Kubernetes yetkilendirme modeli: RBAC, fiiller, kaynaklar, kapsam
- En Az Ayrıcalık İlkesi: Rol, ClusterRole, RoleBinding uygulandı
- ServiceAccount: Otomatik olarak eklenen belirteçleri sınırlama ve IRSA/Workload Identity'yi kullanma
- Pod Güvenlik Standartları: Ayrıcalıklı, Temel, Kısıtlı ve ad alanına göre uygulama
- OPA Gatekeeper: Kurulum, Rego'da Kısıtlama Şablonu, Kısıtlama
- Ortak politikalar: Onaylanmış kayıt görüntüleri, zorunlu kaynak sınırları, kök yok
- Denetim günlüğü: Kümede kimin ne yaptığını izleyin
- Tam sertleştirme kontrol listesi
RBAC: Rol Tabanlı Erişim Kontrolü
RBAC (Rol Tabanlı Erişim Kontrolü), Kubernetes'in temel yetkilendirme mekanizmasıdır. Tanımlar DSÖ (Konu: Kullanıcı, Grup, Hizmet Hesabı) çalıştırılabilir hangi eylem (fiil: al, listele, izle, oluştur, güncelle, yama yap, sil) yukarı hangi kaynak (Kaynak: bölmeler, dağıtımlar, sırlar) hangi kapsam (Role/RoleBinding içeren ad alanı veya kümenin tamamı ClusterRole/ClusterRoleBinding).
Geliştirme Ekibi için Rol ve Rol Bağlama
# rbac-developer-role.yaml
# Un ruolo per i developer: possono vedere e modificare
# deployment/pod/service nel loro namespace, ma non secrets
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
name: developer
namespace: team-alpha
rules:
# Deployment: lettura + scaling
- apiGroups: ["apps"]
resources: ["deployments", "replicasets"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
# Pod: lettura + exec + logs
- apiGroups: [""]
resources: ["pods"]
verbs: ["get", "list", "watch"]
- apiGroups: [""]
resources: ["pods/log"]
verbs: ["get", "list"]
- apiGroups: [""]
resources: ["pods/exec"]
verbs: ["create"]
# Service e ConfigMap: accesso completo
- apiGroups: [""]
resources: ["services", "configmaps", "endpoints"]
verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
# HPA
- apiGroups: ["autoscaling"]
resources: ["horizontalpodautoscalers"]
verbs: ["get", "list", "watch"]
# Ingress
- apiGroups: ["networking.k8s.io"]
resources: ["ingresses"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
name: team-alpha-developers
namespace: team-alpha
subjects:
# Gruppo di utenti (gestito da OIDC/SSO)
- kind: Group
name: "team-alpha-devs"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: Role
name: developer
apiGroup: rbac.authorization.k8s.io
Sınırlı Kapsamlı SRE/Yönetici için ClusterRole
# rbac-sre-clusterrole.yaml
# SRE: accesso in lettura a tutto il cluster, write solo su namespace specifici
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: cluster-reader
rules:
- apiGroups: ["*"]
resources: ["*"]
verbs: ["get", "list", "watch"]
# Nega esplicita: non puo leggere i secrets (sovrascritta da DENY)
# NOTA: in RBAC Kubernetes non esiste DENY esplicita - usa Gatekeeper per questo
---
# SRE: read su tutto + write limitato ai namespace di produzione
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: sre-cluster-reader
subjects:
- kind: Group
name: "platform-sre"
apiGroup: rbac.authorization.k8s.io
roleRef:
kind: ClusterRole
name: cluster-reader
apiGroup: rbac.authorization.k8s.io
# Verifica i permessi di un utente/serviceaccount
kubectl auth can-i create pods --as=system:serviceaccount:production:api-server-sa
kubectl auth can-i delete secrets --as=developer-user -n production
kubectl auth can-i '*' '*' --as=alice # lista tutto quello che alice puo fare
ServiceAccount: Otomatik Belirteçleri Sınırlayın
Varsayılan olarak her Kapsül otomatik olarak geçerli bir ServiceAccount belirtecini bağlar. Pod'larda ki Kubernetes API'sini çağırmazlar, bu belirteç işe yaramaz ancak saldırı yüzeyini artırır:
# serviceaccount-minimal.yaml
# ServiceAccount dedicata per ogni applicazione (mai usare default)
apiVersion: v1
kind: ServiceAccount
metadata:
name: api-server-sa
namespace: production
annotations:
# Su AWS EKS: delega i permessi IAM tramite IRSA
eks.amazonaws.com/role-arn: "arn:aws:iam::123456789:role/ApiServerRole"
automountServiceAccountToken: false # non montare il token automaticamente
---
# Deployment che usa la ServiceAccount
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
namespace: production
spec:
template:
spec:
serviceAccountName: api-server-sa
automountServiceAccountToken: false # ridondante ma esplicito
containers:
- name: api-server
image: my-registry/api-server:1.2.0
---
# Se il Pod deve chiamare l'API K8s, usa un token proiettato con scadenza
# invece del token auto-mounted (che non scade mai)
apiVersion: v1
kind: Pod
spec:
serviceAccountName: api-server-sa
volumes:
- name: api-token
projected:
sources:
- serviceAccountToken:
path: token
expirationSeconds: 3600 # scade ogni ora
audience: kubernetes.default.svc
containers:
- name: api-server
volumeMounts:
- name: api-token
mountPath: /var/run/secrets/kubernetes.io/serviceaccount
readOnly: true
Pod Güvenlik Standartları (PSS)
Pod Güvenlik Standartları, kullanımdan kaldırılan PodSecurityPolicies'in yerini alır (K8s 1.25'te kaldırılmıştır). Etiketler aracılığıyla ad alanı düzeyinde geçerli olan üç güvenlik düzeyini tanımlarlar:
- Ayrıcalıklı: kısıtlama yok (yalnızca kube-system gibi sistem ad alanları için)
- Temel çizgiler: En bilinen ve riskli yapılandırmaları engeller (ayrıcalıklı konteynerler, hostPath, hostNetwork)
- Sınırlı: Maksimum güvenlik için mevcut en iyi uygulamalar (root dışı, ikincil bilgi, yetenek düşüşü)
Her seviyenin üç modu vardır: enforce (Pod'u engeller), audit
(günlüğe kaydeder ancak engellemez), warn (kullanıcıya bir uyarı gösterir).
Pod Güvenlik Standartlarını Ad Alanlarına Uygulayın
# Applica PSS al namespace tramite label
kubectl label namespace production \
pod-security.kubernetes.io/enforce=restricted \
pod-security.kubernetes.io/enforce-version=latest \
pod-security.kubernetes.io/audit=restricted \
pod-security.kubernetes.io/audit-version=latest \
pod-security.kubernetes.io/warn=restricted \
pod-security.kubernetes.io/warn-version=latest
# Per namespace di sistema che richiedono pod privilegiati
kubectl label namespace kube-system \
pod-security.kubernetes.io/enforce=privileged
# Testa cosa succederebbe se applicassi restricted a un namespace esistente
kubectl label --dry-run=server --overwrite namespace production \
pod-security.kubernetes.io/enforce=restricted
Kısıtlı Seviyeyle Uyumlu Kapsül
# pod-restricted-compliant.yaml
# Un Pod che rispetta tutte le regole del livello Restricted
apiVersion: v1
kind: Pod
metadata:
name: secure-pod
namespace: production
spec:
securityContext:
runAsNonRoot: true # non girare come root
runAsUser: 1000 # UID non-root
runAsGroup: 3000
fsGroup: 2000
seccompProfile:
type: RuntimeDefault # profilo seccomp di default
supplementalGroups: [1000]
containers:
- name: app
image: my-registry/api-server:1.2.0
securityContext:
allowPrivilegeEscalation: false # fondamentale: previene sudo
readOnlyRootFilesystem: true # filesystem immutabile
capabilities:
drop:
- ALL # rimuovi tutte le Linux capabilities
# add: [] - non aggiungere nessuna capability
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
resources:
requests:
cpu: "100m"
memory: "128Mi"
limits:
cpu: "500m"
memory: "512Mi"
volumeMounts:
- name: tmp
mountPath: /tmp # se l'app scrive su /tmp, monta un volume
- name: cache
mountPath: /app/cache
volumes:
- name: tmp
emptyDir: {}
- name: cache
emptyDir: {}
automountServiceAccountToken: false
OPA Gatekeeper: Kubernetes için Politika Motoru
Pod Güvenlik Standartları sabit bir dizi kontrolü kapsar. OPA Ağ Geçidi Bekçisi izin verir kullanarak özel politikaları tanımlamak için RegoOPA'nın dili. API sunucusuna yapılan her isteği engelleyen bir Giriş Web Kancası olarak uygulanır. ve tanımlanmış politikalara göre geçerlidir.
OPA Ağ Geçidi Yöneticisi kurulumu
# Installa Gatekeeper con Helm
helm repo add gatekeeper https://open-policy-agent.github.io/gatekeeper/charts
helm repo update
helm install gatekeeper gatekeeper/gatekeeper \
--namespace gatekeeper-system \
--create-namespace \
--version 3.17.0 \
--set auditInterval=30 \
--set constraintViolationsLimit=100 \
--set logLevel=INFO
# Verifica installazione
kubectl get pods -n gatekeeper-system
ConstraintTemplate: Yalnızca Onaylı Tescilden Alınan Görüntüler
# constraint-template-registry.yaml
# Il template definisce lo schema e la logica in Rego
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8sallowedrepos
annotations:
description: "Richiede che le immagini provengano solo da registry approvati"
spec:
crd:
spec:
names:
kind: K8sAllowedRepos
validation:
openAPIV3Schema:
type: object
properties:
repos:
type: array
items:
type: string
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8sallowedrepos
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not starts_with_allowed(container.image)
msg := sprintf("Il container '%v' usa l'immagine '%v' che non proviene da un registry approvato", [container.name, container.image])
}
violation[{"msg": msg}] {
container := input.review.object.spec.initContainers[_]
not starts_with_allowed(container.image)
msg := sprintf("L'initContainer '%v' usa l'immagine '%v' non approvata", [container.name, container.image])
}
starts_with_allowed(image) {
repo := input.parameters.repos[_]
startswith(image, repo)
}
---
# Constraint: applica la policy con i parametri specifici
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sAllowedRepos
metadata:
name: require-approved-registry
spec:
enforcementAction: deny # deny|warn|dryrun
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces:
- kube-system
- gatekeeper-system
- monitoring
parameters:
repos:
- "registry.company.internal/"
- "gcr.io/company-project/"
- "public.ecr.aws/company/"
ConstraintTemplate: Zorunlu Kaynak Sınırları
# constraint-template-resource-limits.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8srequiredresources
spec:
crd:
spec:
names:
kind: K8sRequiredResources
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8srequiredresources
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.cpu
msg := sprintf("Container '%v': cpu limit obbligatorio ma mancante", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.limits.memory
msg := sprintf("Container '%v': memory limit obbligatorio ma mancante", [container.name])
}
violation[{"msg": msg}] {
container := input.review.object.spec.containers[_]
not container.resources.requests.cpu
msg := sprintf("Container '%v': cpu request obbligatoria ma mancante", [container.name])
}
---
apiVersion: constraints.gatekeeper.sh/v1beta1
kind: K8sRequiredResources
metadata:
name: require-resource-limits
spec:
enforcementAction: deny
match:
kinds:
- apiGroups: [""]
kinds: ["Pod"]
excludedNamespaces:
- kube-system
- gatekeeper-system
ConstraintTemplate: Konteyner Kökü Yok
# constraint-template-no-root.yaml
apiVersion: templates.gatekeeper.sh/v1
kind: ConstraintTemplate
metadata:
name: k8spsphostnamespace
spec:
crd:
spec:
names:
kind: K8sPSPHostNamespace
targets:
- target: admission.k8s.gatekeeper.sh
rego: |
package k8spsphostnamespace
violation[{"msg": msg}] {
input.review.object.spec.hostPID == true
msg := "hostPID non e consentito"
}
violation[{"msg": msg}] {
input.review.object.spec.hostIPC == true
msg := "hostIPC non e consentito"
}
violation[{"msg": msg}] {
input.review.object.spec.hostNetwork == true
not input.review.object.metadata.annotations["policy.company.internal/exempt-hostnetwork"]
msg := "hostNetwork non e consentito senza annotation di esenzione"
}
# Verifica violazioni esistenti nel cluster
kubectl get constraints
kubectl describe k8srequiredresources require-resource-limits
# Nella sezione Status.Violations vedrai tutti i Pod non conformi
Denetim Günlüğü
Kubernetes, API sunucusuna yapılan her isteği yapılandırılmış bir denetim günlüğüne kaydedebilir. Uyumluluk ve olay soruşturması için gereklidir.
# audit-policy.yaml - configurazione dell'audit log
apiVersion: audit.k8s.io/v1
kind: Policy
rules:
# Registra tutto sui Secrets a livello RequestResponse (incluso il contenuto)
- level: RequestResponse
resources:
- group: ""
resources: ["secrets"]
# Registra le modifiche a RBAC
- level: RequestResponse
resources:
- group: "rbac.authorization.k8s.io"
resources: ["roles", "clusterroles", "rolebindings", "clusterrolebindings"]
# Registra exec nei Pod (potenziale accesso malevolo)
- level: Request
resources:
- group: ""
resources: ["pods/exec", "pods/portforward", "pods/proxy"]
# Per tutto il resto: registra solo i metadata (chi ha fatto cosa, quando)
- level: Metadata
omitStages:
- RequestReceived
# Kube-apiserver config (aggiungi all'avvio di kube-apiserver):
# --audit-log-path=/var/log/kubernetes/audit.log
# --audit-log-maxage=30
# --audit-log-maxbackup=10
# --audit-log-maxsize=100
# --audit-policy-file=/etc/kubernetes/audit-policy.yaml
Kubernetes'i Güçlendirme Kontrol Listesi
Güvenlik Güçlendirme Kontrol Listesi
- RBAC: Her ServiceAccount ve kullanıcı grubu için en az ayrıcalık ilkesi
- Hizmet Hesabı:
automountServiceAccountToken: falsesunucu API'sini çağırmayan tüm Pod'larda - Jeton geçerlilik süresi: ile yansıtılan jetonları kullanın
expirationSecondskalıcı jetonlar yerine - Pod Güvenlik Standartları:
restrictedtüm üretim ad alanlarında,baselinesahnelemede - Kök yok:
runAsNonRoot: trueeallowPrivilegeEscalation: falsetüm kaplarda - Değişmez dosya sistemi:
readOnlyRootFilesystem: true+ /tmp ve /cache için hacim boşDir - Kaynak sınırları: Tüm kapsayıcılarda CPU ve bellek sınırları (uygulama için Gatekeeper)
- Onaylanan kayıtlar: Yetkisiz kayıtlardan gelen görüntüleri engelleyen ağ geçidi denetleyicisi kısıtlaması
- Ağ Politikası: tüm üretim ad alanlarında varsayılan reddetme (bkz. Madde 1)
- Sırlar: Gizli Kubernetes düzlüğü yerine harici gizli yönetici (AWS Secrets Manager, Vault) kullanın
- Denetim günlükleri: bir SIEM veya günlük toplayıcıda etkinleştirilir ve merkezileştirilir
- vb: şifreleme yapılandırmasıyla hareketsiz durumda şifrelenmiş
- Sunucu API'leri: anonim erişim devre dışı bırakıldı, giriş denetleyicileri etkinleştirildi
Yaygın Güvenlik Hataları
- İş yükleri için varsayılan ad alanı: varsayılan ad alanı varsayılan olarak izin veren RBAC'ye sahiptir; İş yükleriniz için her zaman özel ad alanları kullanın
- CI/CD işlem hatları için ClusterAdmin: GitOps ardışık düzenlerinin küme yöneticisine ihtiyacı yoktur; Hedef ad alanı için gereken minimum izinlere sahip bir ServiceAccount oluşturun
- Ortam değişkenleri olarak sır: ortam değişkenleri görülebilir
kubectl describe podve günlüklerde; Secret'lar veya harici gizli dizi yöneticileri tarafından oluşturulan dosyaları kullanın - Resimlerdeki en son etiketler: en son etiket değişebilir; Tekrarlanabilirliği ve güvenliği sağlamak için her zaman SHA256 özetini veya değişmez etiketleri kullanın
- Temel görüntü CVE'lerini yoksay: Trivy, Snyk veya Grype ile görüntüleri düzenli olarak tarayın; Kritik CVE'lere sahip bir Ubuntu temel görüntüsü, küme sağlamlaştırma çalışmasını iptal eder
Sonuçlar ve Sonraki Adımlar
Kubernetes kümesinin güvenliği katmanlı bir süreçtir: RBAC erişimi kontrol eder API'ye eklenen Pod Güvenlik Standartları, Pod düzeyinde riskli yapılandırmaları önler, ve OPA Gatekeeper, şirket politikalarını sürümlendirilmiş kod olarak kodlamanıza olanak tanır ve denetlenebilir. Bu araçların hiçbiri tek başına yeterli değildir; birlikte bir tane oluştururlar Saldırı yüzeyini büyük ölçüde azaltan derinlemesine savunma.
Güvenliği daha da güçlendirmek ve bir sistem uygulamak için bir sonraki adım Konteyner sistemi çağrılarını gerçek zamanlı olarak izleyen Falco gibi çalışma zamanı güvenlik araçları ve anormal davranış konusunda uyarı (üretim sırasında bir kapta açılan kabuk, okuma kimlik bilgisi dosyaları, beklenmeyen ağ bağlantıları).
Kubernetes at Scale Serisinde Yaklaşan Makaleler
Önceki Makaleler
İlgili Seriler
- DevSecOps — kod olarak politika, CI/CD işlem hatlarında güvenlik taraması
- Kubernetes Ağı — İş yüklerini yalıtmaya yönelik Ağ Politikası
- Platform Mühendisliği — ekipler için otomatik korkuluklar gibi güvenlik







