Kubernetes Cluster Nedir?
Kubernetes, konteynerli uygulamların dağıtımını, ölçeklenmesini ve yönetimini otomatize hale getirmek için geliştirilen açık kaynak kodlu bir konteyner orkestrasyon aracıdır.
Çalışan bir kubernetes ortamına “cluster” denir. Cluster, içerisinde çalışan containerları barındırır.
A working Kubernetes deployment is called a cluster, which is a group of hosts running containers.
Kubernetes cluster’ı temelde 2 farklı bileşenden oluşmaktadır:
- Control Plane: Cluster’ın global ölçekte yönetimini yapar. Cluster’da gerçekleşen olayları takip ederek değişikliklere göre cluster içerisinde değişiklik yapar. Örneğin bir dağıtımın (deployment) replica sayısı sağlanmıyorsa yeni pod’lar ayağa kaldırır.
- Node’lar: İçerisinde container’ları barındıran podları çalıştıran, sanal ya da fiziksel makinelerde koşturabildiğimiz işlem parçacağıdır.
Kubrnetes YML Dosyalarındaki Güvenlik Açıkları - Secure Coding
Deployment, Kubernetes’te bir uygulamanın (pod’ların) istenen durumda çalışmasını sağlayan bir kontrol nesnesidir (controller). YML kullanarak farklı deployment’lar oluşturabiliriz.
Örneğin aşağıda 3 farklı podda, 80 portundan Nginx çalıştıran bir deployment örneği verilmiştir.
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
labels:
app: nginx
spec:
replicas: 3
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx:1.14.2
ports:
- containerPort: 80
spec.replicas=3
olarak tanımlandığı için, kubernetes bu deployment için 3 pod ayağa kaldırır ve onları sürekli takip eder. Eğer biri çökerse yeniden ayağa kaldırır.
Kubernetes’de uygulama ayağa kaldırmak istediğimizde yukarıdaki gibi farklı YML tanımlamaları yaparak farklı nesneler oluşturabiliriz. Oluşturduğumuz YML dosyaları, kubectl ile kubernetes ortamında hangi kaynakların nasıl kullanılacağını tanımlar. Dolayısıyla bizim burada yazacağımız hatalı kodlar, çeşitli güvenlik açıklarını beraberinde getirir. Şimdi gelin bu güvenlik açıklarından bazılarına değinelim.
Missing Security Context
Bir pod tanımlarken Security Context tanımlanmazsa, default ayarlar kullanılır. Bu sebeple container tanımı yapılırken SecurityContext belirtilmesi best-practice’dir. Örneğin aşağıdaki YML dosyasında pod seviyesinde bir SecurityContext tanımı yapılmamıştır.
apiVersion: v1
kind: Pod
...
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
Default olarak container’lar root user ile çalışacağı için burada securityContext içerisinde RunAsUser tanımı yapılmadığından güvenlik riski oluşur. Bu durumu gidermek adına aşağıdaki şekilde container’a sadece gerekli yetkiler verilerek Security Context tanımlanmalıdır.
apiVersion: v1
kind: Pod
...
spec:
containers:
- name: web
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
securityContext:
readOnlyRootFilesystem: true
runAsNonRoot: true
Security Context Misconfiguration
Security Context’in olmaması bir bad-practice dedik, olması da tek başına sistemi güvenli hale getirmez. Eğer bir container’a ihtiyacından fazla yetki veriyorsak container “capability”leri sayesinde saldırganlar “container escape” saldırıları yapabilir.
- Privileged Container:
securityContext:
privileged: false # secure
Yukarıdaki örnekte olduğu gibi eğer security context, privileged=true
olarak ayarlandıysa bu durum “container escape” saldırılarının önüne açar. Bu sebeple kontrollü ilerlenmelidir.
- Missing “readOnlyRootFilesystem: true” in Security Context
securityContext:
readOnlyRootFilesystem: true # secure
Security context tanımında readOnlyRootFilesystem=true
kullanımı, container’ın root path üstünde yazma hakkını elinde alır. Container içinde çalışan process’ler /bin, /etc
gibi dizinlere yazamaz. Eğer /tmp gibi dizinlere yazma gereksinimimiz varsa, emptyDir
tanımı yaparak gerekli dizinlere izin verilebilir.
- Allowing Privilege Escalation
securityContext:
allowPrivilegeEscalation: false # secure
allowPrivilegeEscalation, default olarak true durumdadır. Yani eğer biz Security context içerisinde allowPrivilegeEscalation=false
**tanımı yapmazsak, container içinde çalışan process’lerin, parent process’inden daha fazla yetki kazanmasına izin vermiş oluruz.
- Excessive Linux Capabilities
Linux capability’leri sayesinde, container’a root kullanıcı yetkisi vermeden sadece gerekli olan yetkileri tanımlayarak “at least” yaklaşımını uygulayabiliriz. Örneğin bir poda/container’a aşağıdaki şekilde NET_ADMIN ve SYS_TIME capability’lerini verebiliriz.
securityContext:
capabilities:
add: ["NET_ADMIN", "SYS_TIME"]
Öte yandan, tüm caability’lerin verilmesi güvenlik riskini beraberinde getireceği için bad-practice’dir. Tüm capability’leri drop edip sadece ihtiyaç duyulan capability’lerin eklenmesi daha güvenli bir yaklaşımdır.
securityContext:
capabilities:
drop:
- ALL
add:
- NET_BIND_SERVICE
Kubernetes ile ilgili diğer detaylara ve ek güvenlik tekniklerini ilişkin bilgiler için Burak Akdoğan’ın Kubernetes Security yazısını okuyabilirsiniz.
Referanslar: