Kubernetes Security - Security Context

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.

KubernetesArch

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:

Written by

Resul Bozburun