Kubernetes Hardening
- CIS kurallarına göre hardening parametreleri
https://github.com/kubernetes-sigs/kubespray/blob/master/docs/operations/hardening.md
Bir deployment veya pod oluşturulmaya çalışılırsa aşağıdaki hatayı verecektir
Error from server (Forbidden): pods "test" is forbidden: violates PodSecurity "restricted:v1.27": allowPrivilegeEscalation != false (container "test" must set securityContext.allowPrivilegeEscalation=false), unrestricted capabilities (container "test" must set securityContext.capabilities.drop=["ALL"]), runAsNonRoot != true (pod or container "test" must set securityContext.runAsNonRoot=true), seccompProfile (pod or container "test" must set securityContext.seccompProfile.type to "RuntimeDefault" or "Localhost")
how to make exception
- Default hardening kurallarına uygun deployment tanımı
- bu kurallar için uygun imajında root kullanıcısı ile çalışmıyor olması gerekir. Yoksa öyle bir hata verecektir.
kubectl describe pod secure-deployment
Warning Failed 12s (x8 over 98s) kubelet Error: container has runAsNonRoot and image will run as root (pod: "secure-deployment-85c9947bdc-kgtk6_test(9e6a9b9f-aa47-4625-9bd6-ad519e03f127)", container: secure-container)
apiVersion: apps/v1
kind: Deployment
metadata:
name: secure-deployment
labels:
app: secure-app
spec:
replicas: 1
selector:
matchLabels:
app: secure-app
template:
metadata:
labels:
app: secure-app
spec:
containers:
- name: secure-container
image: nginxinc/nginx-unprivileged:latest
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
runAsNonRoot: true
seccompProfile:
type: RuntimeDefault
- istisnalar sadece ns düzeyinde yaratılabilir. tekil pod/deployment için çalışmaz
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: loy
pod-security.kubernetes.io/audit: baseline
pod-security.kubernetes.io/enforce: baseline
pod-security.kubernetes.io/exempt: "true"
pod-security.kubernetes.io/warn: baseline
name: istisna-ns
Hardening aktif ise
- Kubespray hardening config’i bileşen bazında şu değişiklikleri getiriyor:
kube-apiserver
authorization_modes: ['Node', 'RBAC']— zaten default, ama açıkça sabitleniyorkube_apiserver_request_timeout: 120skube_apiserver_service_account_lookup: true— token’ın hâlâ geçerli bir SA’ya ait olup olmadığını kontrol eder- Audit logging açılır —
/var/log/kube-apiserver-log.json, 30 gün / 10 backup / 100MB - TLS minimum TLS 1.2, kısıtlı cipher suite listesi
- Secrets encryption at rest —
secretboxalgoritmasıyla, veriler etcd’ye yazılmadan önce şifrelenir - Admission plugin’leri:
EventRateLimit,AlwaysPullImages,ServiceAccount,NamespaceLifecycle,NodeRestriction,LimitRanger,ResourceQuota,MutatingAdmissionWebhook,ValidatingAdmissionWebhook,PodSecurity
Operasyonel etkisi:
AlwaysPullImages— private registry kullanan ortamlarda her pod başlangıcında image pull yapılır, bu gecikmeye ve registry bağımlılığına neden olurEventRateLimit— ek configmap gerektirir, eksik olursa apiserver başlamaz- Secrets encryption at rest açıldıktan sonra mevcut secret’ları şifrelemek için
kubectl get secrets --all-namespaces -o json | kubectl replace -f -çalıştırmak gerekir
kubelet
kubelet_authorization_mode_webhook: truevekubelet_authentication_token_webhook: truekube_read_only_port: 0— read-only port kapatılır (default 10255)kubelet_rotate_server_certificates: truevekubelet_rotate_certificates: truekubelet_protect_kernel_defaults: truekubelet_event_record_qps: 1kubelet_streaming_connection_idle_timeout: "5m"kubelet_seccomp_default: truekubelet_systemd_hardening: true— node üzerinde minimal iptables firewall kurar,kubelet_secure_addressesile birlikte çalışır
Operasyonel etkisi:
kubelet_rotate_server_certificates: trueaçılırsa kurulum sonrasıkubectl get csrile pending CSR’ları approve etmek gerekir, aksi halde node’lar NotReady kalırkubelet_systemd_hardeningile birliktekubelet_secure_addressesdoğru set edilmezse node’lar birbirini veya apiserver’ı göremeyebilirkubelet_protect_kernel_defaults: true— node’un kernel parametreleri kubelet’in beklentisiyle uyuşmuyorsa kubelet başlamayı reddeder
etcd
etcd_deployment_type: host— etcd container yerine doğrudan host process olarak çalışır
Bu özellikle mevcut bir cluster’da sonradan değiştirilemez, kurulum zamanı kararıdır.
scheduler ve controller-manager
Her ikisinin de bind_address 127.0.0.1‘e çekilir, yani dışarıdan erişilemez hale gelir.
Prometheus gibi dışarıdan scrape eden bir monitoring stack varsa bunu dikkate almak gerekir.
Özet: En çok dikkat gerektiren noktalar
| Alan | Risk |
|---|---|
AlwaysPullImages | Registry erişimi kesilirse pod’lar ayağa kalkmaz |
kubelet_rotate_server_certificates | Kurulum sonrası CSR approve adımı unutulursa node’lar NotReady |
kubelet_systemd_hardening + kubelet_secure_addresses | Yanlış IP konfigürasyonu cluster iletişimini keser |
| Secrets encryption at rest | Mevcut secret’lar retroactive şifrelenmez, manuel adım gerekir |
etcd_deployment_type: host | Yeni kurulumda karar verilmeli, sonradan değiştirmek cluster rebuild gerektirir |
Kaynaklar
- https://kubernetes.io/docs/concepts/security/pod-security-admission/
- https://kubernetes.io/docs/tasks/configure-pod-container/enforce-standards-namespace-labels/