NSA Kubernetes Hardening Notları - 3. Bölüm

August 28, 2021

Merhaba, önceki bölümde ağırlıklı olarak Network Policies kavramına ve Control Plane bileşenlerine değinmiştik. Bu bölümde ise Authentication ve Authorization konularıyla başlayıp Logging ile devam edeceğiz.

İlk olarak Authentication ve Authorization kalıplarının farkını açıklamakta fayda var. Authentication, yani kimlik doğrulama kısaca bir kullanıcının belirli bir kaynağa erişimi sırasındaki kimlik doğrulanması işlemidir. Authorization, yani yetkilendirme ise söz konusu kullanıcının hedef kaynak üzerindeki yetkilerini tanımlar.

Kubernetes dünyasında da bu iki kavram, kullanıcıların cluster erişimlerine yönelik birincil mekanizma olarak mimaride yerini alır. İlk iki bölümde de verdiğim örneklerde saldırganların bilindik API port’larına, etcd’ye yönelik tarama eylemleri yaptığından bahsetmiştim. Bu tarz saldırıları engellemek adına bazı Kubernetes bileşenlerinin nasıl yapılandırılabileceğini de inceledik. Bu bölümde ise aynı bakış açısıyla kullanıcı yetkilendirmelerine değineceğiz.

Authentication

Cluster yapısında iki tip kullanıcı bulunur:

  • Servis kullanıcıları (Service Accounts)
  • Normal kullanıcılar

Servis kullanıcıları, Pod’lar için gelen API isteklerini işleyebilir. Bu noktada yetkilendirme ServiceAccount Admission Controller ve buna bağlı bir token vasıtasıyla ilerler.

Token’lar Pod’lara mount edilir ki buna da önceki yazıda Secret alt başlığında değinmiştik. Secret güvenliğinin sağlanmasında bunun kullanıcı tarafındaki implementasyonlarından birisi de birazdan bahsedeceğimiz RBAC fonksiyonunu kullanmaktır.

Authentication için kullanılabilecek farklı yöntemler bulunur:

  • Token’lar
  • X509 Sertifikaları
  • Authentication Plugin’leri
  • OpenID
  • Dosya bazlı parola yetkilendirmesi

vs.

Elbette bulunduğunuz senaryoya göre yöntemlerin birbirlerine karşı avantajları ve dezavantajları mevcut. Mesela herhangi bir durumda dosya bazlı parola yetkilendirilmesinin kullanılması önerilmez, zira olası bir saldırıda görece daha kolay bypass edilebilir.

Bunun Minikube ile bir örneği şu şekildedir:

  • Bir .csv dosyasına kullanıcı adı ve parola bilgileri girilir.
  • minikube --extra-config=apiserver.Authentication.PasswordFile.BasicAuthFile=/pass.csv start komutuyla yetkilendirme bilgilerinin olduğu dosya işaret edilerek cluster oluşturulur.
  • 8443 port’undan API’a (…/api/v1/namespaces) curl isteği atıldığında normal şartlarda 401 hatası alınır ancak saldırganın bir şekilde açık text olarak yazılmış bu dosyaya erişimi olması durumunda curl üzerinden authentication sağlanarak API ile etkileşime girilebilir.

Anonim İstekler (Anonymous Requests)

Anonim istekler, herhangi bir kullanıcıya veya Pod’a bağlı değildir. Kubernetes’in 1.16 sürümüyle birlikte varsayılan olarak aktif olarak gelir ve etkin olduğunda yapılandırılmış diğer authentication yöntemleri tarafından reddedilmeyen istekler, anonim istek olarak işlenerek, ABAC veya RBAC olması durumunda kullanıcı adı olarak system:anonymous ve grup olarak da system:unauthenticated atanır.

Test ortamına yönelik veya bir başka geçerli nedeniniz yoksa, API Server güvenliği için —anonymous-auth parametresinin false olarak ayarlanması önerilmektedir ki ikinci yazıda bu konudan bahsetmiştik.

Rol Bazlı Erişim Kontrolü (Role-Based Access Control | RBAC)

RBAC, Kubernetes için en popüler rol bazlı cluster erişim mekanizmalarından birisidir. 1.16 sürümüyle birlikte varsayılan olarak aktif halde gelir. RBAC’in cluster’ınızda aktif olup olmadığını görmek için:

kubectl api-versions

komutunu kullanabilirsiniz. .rbac.authorization.k8s.io/v1 listede olmalıdır.

1c

Eğer RBAC’i aktif etmek isterseniz, API Server’a aşağıdaki parametreyi ekleyerek yeniden başlatabilirsiniz:

--authorization-mode=RBAC

RBAC iki türde izin desteklemektedir:

  • Roles
  • ClusterRoles

Roles, spesifik bir namespace’i hedef alırken, ClusterRoles namespace’den bağımsız olarak tüm cluster yapısını ele alır. İki tip de sadece yetki ekleme mantığıyla çalışır, yani yetki alma gibi bir opsiyon yoktur. RBAC’in aktif olduğu bir cluster’da anonim erişimi pasif durumdaysa, API Server izinleri reddedecektir. Roles ve ClusterRoles sayesinde bir kullanıcı veya grup, namespace düzeyinde kısıtlandırılabilir. Kısıtlama işlemi yapılırken şu sorular sorulur:

  • Kim?
  • Neyi?
  • Nasıl?

Örnek vermek gerekirse; “Bir X kullanıcısı, bir Pod üzerinde listeleme işlemi yapabilmeli mi?” gibi.

Örnek bir RBAC yapılandırması:

apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  namespace: default
  name: pod-reader
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "watch", "list"]

Bu örnekte hedef olarak Pod’lar seçilmiştir, Pod bilgilerinin listelenmesi ve izlenmesine izin verilmiştir.

get ile şu şekilde bir API sorgusu atılabilir:

GET /apis/apps/v1/namespaces/{namespace}/deployments/{name}

list ile aşağıdaki API sorguları yapılabilir:

GET /apis/apps/v1/namespaces/{namespace}/deployments
GET /apis/apps/v1/deployments

watch ile aşağıdaki API sorguları yapılabilir:

GET /apis/apps/v1/deployments?watch=true
GET /apis/apps/v1/watch/namespaces/{namespace}/deployments?watch=true

Oluşturduğumuz örnek RBAC kuralını etkinleştirelim:

kubectl apply -f rbac.yaml

Şimdi de bir ClusterRole uygulaması yapalım.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: secret-read-cluster
rules:
- apiGroups: [""]
  resources: ["services", "endpoints", "pods"]
  verbs: ["get", "list", "watch"]

Aynı şekilde aktif edelim.

kubectl apply -f clusterrole.yaml

Role ve ClusterRole oluşturulan kuralları bir kullanıcıya tanımlamaz. Bu eylem için RoleBindings ve ClusterRoleBindings tanımlamaları kullanılır, bu şekilde oluşturulan kurallar kullanıcı, grup ve servis kullanıcısı (service account) düzeyinde tanımlanabilir. RoleBindings, bu işlemi bir namespace düzeyinde gerçekleştirirken, ClusterRoleBindings bunu tüm cluster seviyesinde yapar.

apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: pod-read
  namespace: default
subjects:
- kind: User
  name: deniz
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: Role 
  name: pod-reader
  apiGroup: rbac.authorization.k8s.io

Oluşturduğumuz RoleBinding’i aktif edelim.

kubectl apply -f rolebinding.yaml

Bir de ClusterRoleBinding oluşturalım.

apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: secret-read
subjects:
- kind: Group
  name: manager
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: secret-read-cluster
  apiGroup: rbac.authorization.k8s.io

Mesela, get ve(ya) list eylemini kısıtlayıp bir kullanıcıya atadığımızda, artık bu kullanıcının hedef bileşenleri listeleyememesi gerekir. Node ve Pod listelemesi yapmaya çalışan bir kullanıcı, aşağıdaki gibi hata alacaktır.

8c

Roles ve ClusterRoles oluşturulduğunda veya güncellendiğinde, hedef kullanıcı yeni rol için gerekli yetkilere aynı kapsam düzeyinde sahip olmalıdır. Kullanıcı veya gruba bir atama işlemi yapıldığında, mevcut yetki üzerinde değişiklik yapılamaz, şayet yeni bir yetki yapılandırması isteniyorsa öncelikle söz konusu yetki atamasının silinmesi gerekir.

Güvenlik açısından baktığımızda, diğer birçok platformda olduğu gibi, burada da izin düzeyi değiştirilecek olan bir kullanıcı, grup ya da servis kullanıcısının ‘minimum yetki’ yaklaşımıyla yapılandırılması gerekir. Varsayılan olarak bir servis kullanıcısı API erişimi için her bir namespace için oluşturulur. RBAC kuralları, servis kullanıcılarının namespace düzeyinde yapabilecekleri eylemleri de özelleştirebilir.

Şayet yönetimsel anlamda kullanıcıların RBAC erişimini özelleştirmek istiyorsanız, bu amaca yönelik hazırlamış olduğum RBAC Controller scriptine de göz atabilirsiniz.

RBAC Controller

Bunun haricinde yine RBAC için işleri yönetmede kolaylık sağlayacak bazı araçlar:

RBAC Tool RBAC Manager RBAC Audit

Logging

Loglama konusu, önceki başlıklar gibi doğrudan bir güvenlik önlemi sağlıyor olmasa da, yazılım dünyasındaki hemen her platformda olduğu gibi neyin ne zaman nasıl olduğuyla ilgili fikir vermesi açısından son derece önemli bir konudur. Kubernetes özelinde sadece spesifik bir bileşenin veya event’ların loglanması, resmin bütününü görebilmek açısından yeterli olmayacaktır. Bu noktada cluster’ın çalıştığı yapı veya yapıların ve aynı şekilde cluster’ın sahip olduğu servislerin de loglanması işin içine dahil olmaktadır. Yani, sadece host veya uygulama özelinde değil, şayet bir sanallaştırma platformu üzerinde çalışılıyorsa veya bir cloud sağlayıcısı kullanılıyorsa aynı şekilde bu yapıların da loglanması önemlidir.

Kubernetes ortamında şu eylemler monitor edilebilir / loglanabilir:

  • API istek geçmişi
  • Performans metrikleri
  • Deployment’lar
  • Kaynak tüketimi
  • İşletim sistemi çağrıları (syscalls)
  • Protokoller
  • Yetki değişiklikleri
  • Ağ trafiği
  • Pod ölçeklendirmesi

En ufak birim üzerinden düşünecek olursak, bir Pod oluşturulduğunda veya güncellendiğinde mevcut log mekanizmasının gelen-giden istekleri, response zamanını, performans metriklerini ve ağ trafiğinin gözlemlenmesi gerekir. Anonim isteklerin kısıtlanması gerektiğinden bahsettik, lakin bu durum olası bir anomali durumunu takip edebilmek adına loglama mekanizmasında anonim kullanıcıları da kapsamaya devam etmelidir.

RBAC ile oluşturulan yetkilendirmelerin belirli periyotlarla izlenmesi ve bir auditing işleminden geçmesi önerilir. Zira geçen süre içerisinde eklenen - çıkarılan kullanıcılar ve(ya) güncellenen yetkilendirmeler olabilir.

Audit denetimleri, mevcut loglarda var olan metriklerin ve her türlü cluster içi faaliyetlerdeki ölçümlerin değişimlerini ve karşılaştırmalarını içermelidir. Burada verilebilecek en temel örneklerden birisi; kaynak kullanımına ait metriklerin beklenmedik bir anda tepe noktasına çıkması -spike- gibi bir senaryonun yaşanmasıdır. Mesela yazının önceki bölümlerinde de bahsettiğimiz cryptojacking saldırılarında Pod’ların kaynak kullanımlarının arttığını ve bir anomali oluşturduğunu biliyoruz. Bu durumda sadece RAM veya CPU kullanımı değil, aynı zamanda tüm trafiğin de aynı şekilde loglanması önemlidir.

Logging işlemi, cluster’ın bulunduğu sistem veya sistemler haricinde dış bir kaynağa da aktarılabilir ki yüksek erişilebilirlik (high availability) penceresinden baktığımızda logging mekanizmasının bir başka kaynakta tutulması genel itibariyle daha mantıklı bir yaklaşım olacaktır. Çünkü iş sadece tüm cluster’ı loglamakla da bitmiyor, merkezi bir logging sunucusu olması durumunda elbette bu sunucunun da periyodik olarak bakımdan geçmesi ve aynı şekilde güvenlik denetimlerinin yapılması mühimdir. Mesela ELK gibi bir yapı kullanıldığında, işin içine bir de performans iyileştirmeleri girebilir ki yanlış bir yapılandırma mevcut verilerin kaybına yol açabilir ve aynı zamanda logların aktarımının minimum TLS 1.2 kullanılarak yapılması beklenir. Logging tarafındaki temel önlemleri özetlemek gerekirse:

  • Mümkünse harici bir kaynak kullanılmalıdır.
  • Log trafiği TLS üzerinden gerçekleşmelidir.
  • Yanlış bir yapılandırma durumuna karşı log aktarımı sadece salt okunur (read-only) modunda yapılmalıdır.

Logging yapılandırması

kube-apiserver’ın iç ve dış API isteklerini işlediğini söylemiştik. Her bir API isteği ki bu bir kullanıcı, uygulama veya servis vasıtasıyla oluşturulmuş olabilir, her bir aşamada bir audit olayı oluşturur. Bu şekilde bir audit olayı oluşturulduğunda, API Server bir audit policy’si veya uygulanabilir bir kural olup olmadığını kontrol eder. Burada bir eşleşme olursa loglama gerçekleşir. Varsayılan olarak Kubernetes’te audit mekanizması aktif değildir.

Bir audit eyleminin loglanması için bir audit policy’si oluşturularak kural veya kuralların aktif edilmesi gerekir. Söz konusu policy dosyasıyla yapılacak eşleşme sonradan kube-apiserver’a iletilir. Bir kuralın geçerli olabilmesi için şu dört audit düzeyinden birisini belirtmesi gerekir:

  • None: Loglama yapılmaz.
  • Metadata: Response veya request body gereksinimi olmadan, sadece metadata’ya (kullanıcı, timestamp, kaynak vs.) bakılır.
  • Request: Metadata ve request body işlenir, response body dahil edilmez.
  • RequestResponse: Metadata, request ve response body dahil edilir.

Tüm audit olaylarını en yüksek seviyede loglamak için gerekli Policy en basit haliyle şu şekildedir:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: RequestResponse

Burada da özelleştirme yapılabilir. Mesela:

apiVersion: audit.k8s.io/v1
kind: Policy
rules:
  - level: RequestResponse
    resources:
    - group: ""
      resources: ["pods"]
  - level: Metadata
    resources:
    - group: ""
      resources: ["pods/log", "pods/status"]

İki ayrı düzey aynı Policy için kullanılmış, fakat resource tanımlarındaki metadata seviyeleri özelleştirilmiştir.

Bir diğer konu da oluşturulan bu Policy’lerin API Server’da tanımlanmasıdır. Master node üzerinde /etc/kubernetes/manifests/kube-apiserver.yaml dosyasını herhangi bir metin editörüyle açalım.

Bir önceki yazıda ekstra güvenlik önlemleri adına burada tanımlanabilecek parametrelerden söz etmiştik. Aynı şekilde Policy dosyasını tanımlamak için de —audit-policy-file parametresini kullanacağız. Mesela ben /root/ altında my-policy.yaml dosyasını oluşturdum. Audit loglarının yazılacağı dosyayı da —audit-log-path parametresiyle belirliyoruz.

Opsiyonel olarak logların ne kadar süreyle tutulacağını belirlemek, retain policy’sini düzenlemek için de —audit-log-maxage parametresini kullanabiliriz. Burada iki kullanım daha mümkündür:

  • —audit-log-maxsize: Bir Audit log dosyasının maksimum boyutunu belirler. Set edilmiş boyuttan sonra yeni dosya oluşturulur.
  • —audit-log-maxbackup: Retain edilmeden önce maksimum log dosyası sayısını belirler.

Log dosyaları varsayılan olarak JSON formatında tutulur.

Şayet API Server bir Pod olarak çalıştırılıyorsa, Policy ve log dosyaları bir volume üzerinden hostPath kullanılarak mount edilmelidir. Bir örneği şu şekildedir:

volumeMounts:
  - mountPath: /etc/kubernetes/audit-policy.yaml
    name: audit
    readOnly: true
  - mountPath: /var/log/audit.log
    name: audit-log
    readOnly: false
volumes:
  - name: audit
    hostPath:
      path: /etc/kubernetes/audit-policy.yaml
      type: File
  - name: audit-log
    hostPath:
      path: /var/log/audit.log
      type: FileOrCreate

Worker node ve container loglanması

Kubernetes mimarisinde logging yapılandırmalarının farklı yöntemleri vardır. kubelet, her bir node üzerindeki logging eylemlerini yönetir ve komut satırı aracılığıyla kontrol edilebilir.

Spesifik bir Pod özelinde bir container’ın logları:

kubectl logs -f -p pod_adı -c container_adı

komutuyla görüntülenebilir. Şayet loglar akmaya devam ediyorsa ‘-f’ parametresi kullanılır, mevcut Pod üzerinde birden çok container bulunması durumunda da ‘-c’ parametresiyle container adı seçilebilir. Container, Pod veya node düzeyinde bir hata olması ve bu hata nedeniyle de logların kesilmesi durumunda Kubernetes herhangi bir built-in çözüm sunmamaktadır, yani böyle bir senaryoda mevcut loglar da kaybedilebilir. O yüzden NSA ve CISA merkezi bir loglama sunucusunun yapılandırılmasını önermektedir ki ben de bu görüşe katılmaktayım.

Bu aşamada dört opsiyon sunulur.

1. seçenek: Her bir node üzerinde logların bir backend’e aktarılması için bir agent kullanılır. Bu şekilde node içerisinde yaşanacak bir problemin minimum hataya yol açması hedeflenir.

Bu senaryonun implementasyonunda ise bağımsız bir container oluşturularak, agent’ın da bu container üzerinde çalışması, her bir node’un log dosyalarına erişiminin olması hedeflenir. Böylelikle loglar bir SIEM ürününe veya farklı bir logging mekanizmasına iletilebilir.

2. seçenek: Her bir Pod üzerinde bir sidecar container’ı oluşturulur. Şayet farklı formatlarda aynı anda birden çok log dosyası yazılıyorsa, bu seçeneğin kullanılması önerilir. Aynı şekilde sidecar container vasıtasıyla loglar dış kaynağa aktarılacaktır.

3. seçenek: Her bir Pod’da sidecar agent’ı kullanılır. Node düzeyindeki loglamadan ziyade daha fazla esneklik gerekirse bu seçenek önerilir. Her bir Pod konfigüre edilerek logların backend’e aktarılması sağlanır. Daha çok 3. parti logging agent’larının implementasyonunda kullanılır.

4. seçenek: Bir uygulama vasıtasıyla loglar doğrudan backend’e gönderilir. Uygulama loglarının toplanmasında Kubernetes doğrudan bir seçenek sunmadığı için aynı şekilde üçüncü parti bir uygulama konfigüre edilerek log aktarımı sağlanır.

Logları bir dosyaya veya bir backend kaynağına aktarabilmesi haricinde, sidecar container‘lar bir proxy olarak da konfigüre edilebilir.

Logging bileşenleri Kubernetes ortamında genellikle DaemonSet‘ler aracılığıyla yürütülür, bu şekilde her bir node için logging agent’larının bir kopyasının tutulması sağlanır.

Seccomp

Node ve container tabanlı loglamanın haricinde, sistem çağrılarının loglanması da önemlidir. Bunun için Kubernetes ile entegre çalışan seccomp modülü kullanılabilir. Varsayılan olarak pasif durumdadır.

Seccomp, audit profil dosyaları aracılığıyla sistem çağrılarını loglayabilir. Profil dosyaları özelleştirilerek, hangi sistem çağrılarına izin verilip verilmeyeceği belirtilebilir. Profillerin Pod üzerinden kullanılabilmesi için, seccompProfile parametresi tanımlanır ve bu parametre iki argümana sahiptir:

  • Type
  • localhostProfile

Şimdi bununla ilgili bir uygulama yapalım.

İlk olarak yeni bir dizin oluşturarak Kubernetes’in örnek olarak verdiği 3 profil dosyasını oluşturalım.

mkdir /home/deniz/profiles

İlk dosya audit.json:

{
"defaultAction": "SCMP_ACT_LOG"
}

İkinci dosya violation.json:

{
"defaultAction": "SCMP_ACT_ERRNO"
}

Üçüncü dosya fine-grained.json:

{
"defaultAction": "SCMP_ACT_ERRNO",
"architectures": [
"SCMP_ARCH_X86_64",
"SCMP_ARCH_X86",
"SCMP_ARCH_X32"
],
"syscalls": [
{
"names": [
"accept4",
"epoll_wait",
"pselect6",
"futex",
"madvise",
"epoll_ctl",
"getsockname",
"setsockopt",
"vfork",
"mmap",
"read",
"write",
"close",
"arch_prctl",
"sched_getaffinity",
"munmap",
"brk",
"rt_sigaction",
"rt_sigprocmask",
"sigaltstack",
"gettid",
"clone",
"bind",
"socket",
"openat",
"readlinkat",
"exit_group",
"epoll_create1",
"listen",
"rt_sigreturn",
"sched_yield",
"clock_gettime",
"connect",
"dup2",
"epoll_pwait",
"execve",
"exit",
"fcntl",
"getpid",
"getuid",
"ioctl",
"mprotect",
"nanosleep",
"open",
"poll",
"recvfrom",
"sendto",
"set_tid_address",
"setitimer",
"writev"
],
"action": "SCMP_ACT_ALLOW"
}
]
}

Şimdi kind ile yeni bir cluster oluşturalım. kind, Docker container node’larını kullanarak local bir Kubernetes cluster’ı oluşturmayı sağlamaktadır. Binary formatında basitçe kurabilirsiniz:

curl -Lo ./kind "https://kind.sigs.k8s.io/dl/v0.11.1/kind-$(uname)-amd64"
chmod +x ./kind
mv kind /usr/bin

Şimdi, seccomp profillerini de tanımlayacak şekilde tek node’lu bir cluster kuralım.

apiVersion: kind.x-k8s.io/v1alpha4
kind: Cluster
nodes:
- role: control-plane
  extraMounts:
    - hostPath: "/home/deniz/profiles"
      containerPath: "/var/lib/kubelet/seccomp/profiles"

Not: Ben profiles dizinini kullanıcının ev dizini altında oluşturdum, hostPath‘i uygun şekilde değiştirdiğinize dikkat edin.

kind create cluster --config=kind.yaml

2

Cluster’ın çalıştığını docker ps ile kontrol edebiliriz.

3

containerPath parametresiyle profiles/ dizinini container’a bağladığımız için, oluşturduğumuz profil dosyalarını /var/lib/kubelet/seccomp/profiles altında görmemiz gerekmektedir, kontrol edelim.

4

Şu ana kadar herhangi bir problemle karşılaşmadık. Şimdi, bir Pod özelinde tüm sistem çağrılarını loglayacak şekilde yeni bir Pod oluşturalım.

apiVersion: v1
kind: Pod
metadata:
  name: sec-pod
  labels:
    app: sec-pod
spec:
  securityContext:
    seccompProfile:
      type: Localhost
      localhostProfile: profiles/audit.json
  containers:
  - name: test-container
    image: hashicorp/http-echo:0.2.3
    args:
    - "-text=sistem çağrısı yapıldı!"
    securityContext:
      allowPrivilegeEscalation: false

k apply -f sec-pod.yaml

Mevcut profil herhangi bir sistem çağrısını kısıtlamadığı için, Pod’un sorunsuz bir şekilde başlaması gerekmektedir. kubectl get po ile kontrol sağlayabilirsiniz.

Bu container’la etkileşime girebilmek için bir NodePort servisi oluşturalım.

kubectl expose pod/sec-pod --type NodePort --port 5678

5c

Benim ortamımda 32344 port’una bind etti. curl ile deneme yapalım:

docker exec 741 curl -s localhost:32344

6c

Sistem çağrısının yapıldığını görebildik.

syslog kayıtları kontrol edildiğinde, syscall logları hakkında daha detaylı bilgi edinebilirsiniz.

Syslog

Syslog, Linux dağıtımları üzerinde olan biten eylemlerin kayıtlarının tutulmasını sağlayan bir yapıdır.

Kubernetes ortamında varsayılan olarak kubelet ve CR logları journald servisine yazılır. Bunun yanısıra toplanan logların syslog servisine aktarılması da mümkündür. Syslog kayıtları şu bilgileri taşıyan bir header’a sahiptir:

  • Zaman damgası (timestamp)
  • Host adı (hostname)
  • Uygulama adı
  • Süreç ID’si (PID - Process ID)
  • Açık metin şeklinde bir mesaj kaydı

Syslog protokolü, syslog-ng, rsyslog ve journald araçlarıyla kolaylıkla kullanılabilir ki günümüzde birçok güncel Linux dağıtımı rsyslog ve journald’yi kullanmaktadır. Syslog’a bağlı olan bu loglar journalctl aracıyla komut satırında denetlenebilir.

Bir başka logging mekanizmasının kullanılmadığı bir durumda, container ortamları için syslog araçlarıyla yerel dosya sisteminde tutulur.

SIEM Platformları

SIEM ürünleri, tüm organizasyon ağındaki sistemlerin ve uç birimlerin ürettiği logları toplayıp bunları analiz etmeyi sağlar. Lakin iş sadece text based logging ile sınırlı değildir; firewall ve uygulama logları da aynı şekilde toplanır.

Kubernetes yapısında servis, container, Pod ve node’lar arasında karşılıklı bağımlılıklar olabilir. Servislerin, container’ların veya Pod’ların sürekli yeniden başlatılabildiği veya konfigüre edildiği bir ortamda geleneksel SIEM ürünlerinin bu eylemler nedeniyle tüm ortamı takip edebilmesi zorlaşabilmektedir. Zira statik bir IP atamasının olmadığı bir senaryo Kubernetes ortamı için oldukça sıradan bir durumdur.

Elbette eski SIEM ürünlerinin daha çok on-premise ortamların mimarilerine göre dizayn edildiğini düşünürsek, yeni jenerasyondaki Cloud tabanlı SIEM ürünlerinin container teknolojilerine yönelik çözümler ürettiğini de belirtmek gerekir.

Alerting

Logging konusunda olduğu gibi, alerting tarafında Kubernetes bir built-in çözüm sunmamaktadır. Bunun yanında bazı popüler monitoring araçları alerting özellikleriyle Kubernetes’e entegre edilebilmektedir.

Cluster yöneticisi olarak burada hesaplanması gereken, monitor edilecek kaynakların ve alarm oluşturulması istenen eylemlerin metriklerinin uygun bir şekilde ayarlanmasıdır. Kubernetes üzerinde alarm oluşturabilecek bazı eylemler şu şekildedir:

  • Kullanılabilir disk boyutunun azalması
  • Disk üzerindeki performans problemleri
  • Log aktarımının durması
  • Bir Pod veya uygulamanın root haklarıyla çalışması
  • Kullanıcıların yetkisiz kaynaklara erişimi veya erişmeye çalışması
  • Anonim kullanıcıların yetkisiz eylemleri
  • API veya sistem çağrılarındaki anomaliler

vs.

Alarm mekanizması her ne kadar tek başına bir güvenlik katmanı oluşturmuyor olsa da, olası senaryolara baktığımızda aslında olayın vehametini daha iyi anlıyoruz. Misal, kaynak kullanımı beklenmedik bir limiti geçtiğinde “acaba bir cryptojacking saldırısı mı oldu?” sorusu sorulabilir ki bu aşamada disk kullanımının da %100’e gelmesi durumunda loglamanın da durması işleri iyice zor bir noktaya getirebilir veya zararlı bir uygulamanın çalışacağı bir container’ın deploy edilmesi durumunda beklenmedik bir ağ trafiğinin oluştuğunu ilk saniyelerde tespit edip önlem almak, alerting konusunun aslında ne kadar mühim olduğunu gösterebilen ve birçok senaryonun üretilebileceği bir konudur.

Bir başka yazı dizisinde uygulamalı olarak sidecar container’ı ve ELK üzerinden alerting işlemlerini de göstereceğim.

Service Meshes

Service Meshes, ya da Türkçe haliyle Hizmet Ağları, Kubernetes dünyasında uygulamalardaki microservice iletişimlerini kolaylaştıran yapılardır. Popüler olarak:

  • Istio
  • Linkerd
  • Traefik
  • Consul
  • Kong

gibi uygulamaları örnek verebiliriz. Normalde microservice düzeyinde bir problem yaşandığında özellikle kompleks mimarilerde debug işlemi yapmak gerçekten baş ağrıtabilen bir eyleme dönüşebilir. Hizmet ağları bu noktada bizlere yerine göre kolaylık sağlamaktadır. Yukarıda verdiğimiz uygulamalar özelinde de özetleyecek olursak, hizmet ağları şu eylemleri yapabilir:

  • Bir serviste herhangi bir nedenden dolayı hizmet kesintisi olduğunda trafik yönlendirilebilir.
  • Performans metrikleri toplanarak optimizasyon yapılabilir.
  • Service-to-Service iletişimindeki şifreleme yönetilebilir.
  • Service-to-Service iletişimindeki loglar toplanabilir.
  • Her bir servise ait loglar toplanarak sorunların çözümünde developerlara debug işlemlerinde kolaylık sağlayabilir.

Hizmet ağları, servislerin hibrit veya çoklu bulut platformlarına migrate edilmesine de olanak sağlayabilir. Yine de hizmet ağları Kubernetes ortamı için bir zorunluluk değildir, bu daha çok mimari yönetiminin nasıl sağlanacağıyla alakalı bir konudur. Elbette özellikle ağ trafiğinin sertifika otoriteleri aracılığyla güvenli hale getirilmesi, TLS gibi kimlik doğrulama seçenekleri göz önünde bulundurulduğunda, cluster yapısını daha güvenli hale getirebilmek adına hizmet ağlarının önemli bir rol oynadığını söylemek yanlış olmayacaktır.

Fault Tolerance

Logging servislerinin erişilebilirliğinin sağlanması adına fault tolerance policy’lerinin uygulanması önerilir. Logların mümkün mertebe harici bir sunucuya veya merkezi bir logging mekanizmasına gönderilmesi gerektiğini söylemiştik. Fault tolerance’ın bu olaydaki önemi, logların aktarımında herhangi bir problem yaşanması durumunda ikinci bir kaynağın devreye girmesi veya localde bir yedek loglamanın başlatılmasına yöneliktir. Asıl kaynakla olan iletişim yeniden kurulduğunda ikinci kaynakta veya localde depolanmış bu logların tekrar merkeze iletilebilmesi için bir aksiyon planı oluşturulmalıdır.

Kubernetes açısından baktığımızda, kullanıcı eylemlerinin olumsuz etkilenmemesi ve hataların minimum düzeyine indirgenmesi adına fault tolerance ilkesi önem taşır, yani bu konu sadece logging üzerinden düşünülmemelidir.

Araçlar

Kubernetes, tam kapsamlı bir denetleme çözümü sunmamaktadır fakat mimarisi farklı tipte uygulamaları konfigüre etmeye ve kullanıcıların kendi plugin / çözümlerini oluşturmalarına olanak sağlar. Siber güvenlik takımlarının gözünden baktığımızda, popüler SIEM platformlarının Kubernetes ile entegre edilebildiğini söyleyebiliriz. Açık kaynak dünyasındaki monitoring araçları olarak ise:

  • ELK
  • Prometheus
  • Grafana

üçlüsünü mevcuttaki en popüler uygulamalar olarak örnek verebiliriz. Bu uygulamalar kaynak kullanımı, anomali tespiti, ağ trafiği, metrik ölçümü gibi farklı alanlarda monitoring ve alerting çözümleri sunmaktadır.

RHEL ve Prometheus’a yönelik yazımı da inceleyebilirsiniz:

Prometheus & RHEL

Belki bir başka yazıda ELK - Prometheus / Grafana’ya yönelik bir uygulama da yaparız, şimdilik yazı dizisini burada noktalıyorum.



Written by Deniz Parlak