ELK Stack ile Güvenlik Log Analizi ve SIEM Kurulumu

Şirkette SIEM çözümü için bütçe yoksa ne yaparsın? Splunk’ın lisans maliyetlerine bakınca çoğu KOBİ ve hatta orta ölçekli enterprise firmaların geri adım attığını görüyoruz. İşte tam bu noktada ELK Stack devreye giriyor. Elasticsearch, Logstash ve Kibana üçlüsü, doğru yapılandırıldığında ticari SIEM çözümlerine ciddi rakip olabiliyor. Ben bu yazıda size kurumsal bir ortamda ELK’ı SIEM olarak nasıl kullandığımızı, hangi tuzaklarla karşılaştığımızı ve günün sonunda ne elde ettiğimizi aktaracağım.

ELK Stack’i Neden SIEM Olarak Kullanmalısınız?

Açık kaynak demek “bedava” demek değil, bunu baştan söyleyeyim. ELK Stack’i ayakta tutmak ciddi operasyonel maliyet gerektiriyor. Ama ticari alternatiflere kıyasla veri hacmine göre lisanslama olmadığı için özellikle log yoğun ortamlarda çok daha avantajlı. Günde 50 GB log üreten bir ortamda Splunk lisansı yılda yüz binlerce dolara gidebiliyor.

Güvenlik açısından ELK’ın güçlü yanları:

  • Gerçek zamanlı log toplama ve indeksleme: Olaylar saniyeler içinde aranabilir hale geliyor
  • Esnek sorgulama: KQL (Kibana Query Language) ile karmaşık korelasyon sorguları yazabiliyorsunuz
  • Elastic Security modülü: Artık neredeyse hazır SIEM özellikleri sunuyor
  • Beats ailesi: Filebeat, Winlogbeat, Auditbeat gibi hafif ajanlar ile her platformdan log toplayabiliyorsunuz
  • Özelleştirilebilir alarmlar: Watcher veya Kibana Alerts ile tetikleyici kurallar tanımlayabiliyorsunuz

Mimari Tasarım: Güvenlik Odaklı ELK Kurulumu

Prodüksiyon ortamında güvenlik log analizi için önerdiğim minimal mimari şu şekilde:

[Log Kaynakları] -> [Beats Ajanları] -> [Logstash Cluster] -> [Elasticsearch Cluster] -> [Kibana]
                                              |
                                         [Kafka Buffer]

Kafka katmanını neden ekliyorum? Logstash cluster’ı devre dışı kaldığında veya yoğun trafik anlarda logları kaybetmemek için. Güvenlik loglarında veri kaybı kabul edilemez.

Elasticsearch Güvenlik Yapılandırması

İlk kurulumda çoğu kişinin atladığı kritik nokta: Elasticsearch’ü varsayılan ayarlarla bırakmak. elasticsearch.yml dosyasında şunlar olmazsa olmaz:

# /etc/elasticsearch/elasticsearch.yml

cluster.name: siem-cluster
node.name: es-node-01

# Güvenlik ayarları - MUTLAKA açık olmalı
xpack.security.enabled: true
xpack.security.transport.ssl.enabled: true
xpack.security.transport.ssl.verification_mode: certificate
xpack.security.transport.ssl.keystore.path: elastic-certificates.p12
xpack.security.transport.ssl.truststore.path: elastic-certificates.p12

# HTTP SSL
xpack.security.http.ssl.enabled: true
xpack.security.http.ssl.keystore.path: http.p12

# Audit logging - kimin ne sorguladığını takip etmek için
xpack.security.audit.enabled: true
xpack.security.audit.logfile.events.include: ["access_denied", "authentication_failed", "connection_denied", "tampered_request", "run_as_denied", "anonymous_access_denied"]

# JVM heap - log analizinde bellek kritik
# -Xms16g
# -Xmx16g

network.host: 0.0.0.0
http.port: 9200

# Shard ve replica ayarları
index.number_of_shards: 3
index.number_of_replicas: 1

Logstash Pipeline Yapılandırması

Güvenlik loglarını işlerken Logstash pipeline tasarımı kritik. Burada ayrı pipeline’lar kullanmak yönetimi kolaylaştırıyor:

# /etc/logstash/conf.d/security-pipeline.conf

input {
  beats {
    port => 5044
    ssl => true
    ssl_certificate => "/etc/logstash/certs/logstash.crt"
    ssl_key => "/etc/logstash/certs/logstash.key"
    ssl_certificate_authorities => ["/etc/logstash/certs/ca.crt"]
    ssl_verify_mode => "force_peer"
  }
  
  kafka {
    bootstrap_servers => "kafka-01:9092,kafka-02:9092"
    topics => ["security-logs", "windows-events", "firewall-logs"]
    group_id => "logstash-siem"
    codec => json
  }
}

filter {
  # Windows Event Log işleme
  if [agent][type] == "winlogbeat" {
    mutate {
      add_field => { "log_source" => "windows" }
    }
    
    # Başarısız giriş denemelerini işaretle
    if [event][code] == 4625 {
      mutate {
        add_tag => ["failed_login"]
        add_field => { "security_event" => "authentication_failure" }
      }
    }
    
    # Hesap kilitleme
    if [event][code] == 4740 {
      mutate {
        add_tag => ["account_lockout"]
        add_field => { "security_event" => "account_locked" }
        add_field => { "severity" => "high" }
      }
    }
    
    # Yeni servis kurulumu
    if [event][code] == 7045 {
      mutate {
        add_tag => ["new_service"]
        add_field => { "security_event" => "service_installed" }
        add_field => { "severity" => "medium" }
      }
    }
  }

  # Linux auth log işleme
  if [log][file][path] =~ "/var/log/auth.log" or [log][file][path] =~ "/var/log/secure" {
    grok {
      match => {
        "message" => [
          "%{SYSLOGTIMESTAMP:timestamp} %{HOSTNAME:hostname} sshd[%{NUMBER:pid}]: Failed password for %{USERNAME:failed_user} from %{IP:src_ip} port %{NUMBER:src_port}",
          "%{SYSLOGTIMESTAMP:timestamp} %{HOSTNAME:hostname} sshd[%{NUMBER:pid}]: Accepted %{WORD:auth_method} for %{USERNAME:user} from %{IP:src_ip} port %{NUMBER:src_port}"
        ]
      }
    }
    
    if "_grokparsefailure" not in [tags] {
      geoip {
        source => "src_ip"
        target => "geoip"
      }
      
      mutate {
        add_field => { "log_source" => "linux_auth" }
      }
    }
  }

  # IP reputation check için basit liste
  if [src_ip] {
    translate {
      field => "src_ip"
      destination => "threat_intel"
      dictionary_path => "/etc/logstash/threat_intel/known_bad_ips.yml"
      fallback => "unknown"
    }
    
    if [threat_intel] != "unknown" {
      mutate {
        add_tag => ["threat_intel_match"]
        add_field => { "severity" => "critical" }
      }
    }
  }
  
  # Timestamp normalizasyonu
  date {
    match => ["timestamp", "MMM  d HH:mm:ss", "MMM dd HH:mm:ss"]
    target => "@timestamp"
  }
}

output {
  if "failed_login" in [tags] or "account_lockout" in [tags] {
    elasticsearch {
      hosts => ["https://es-01:9200", "https://es-02:9200"]
      index => "siem-auth-events-%{+YYYY.MM.dd}"
      user => "logstash_writer"
      password => "${LOGSTASH_ES_PASSWORD}"
      ssl => true
      cacert => "/etc/logstash/certs/ca.crt"
    }
  }
  
  elasticsearch {
    hosts => ["https://es-01:9200", "https://es-02:9200"]
    index => "siem-logs-%{+YYYY.MM.dd}"
    user => "logstash_writer"
    password => "${LOGSTASH_ES_PASSWORD}"
    ssl => true
    cacert => "/etc/logstash/certs/ca.crt"
  }
}

Kritik Güvenlik Senaryoları ve Korelasyonlar

Brute Force Saldırısı Tespiti

Gerçek hayatta en çok karşılaştığımız saldırı türlerinden biri. Kibana’da şu KQL sorgusu ile anlık tespiti yapabilirsiniz:

event.code: 4625 AND @timestamp > now-15m

Ama bunu daha da güçlendirmek için Kibana’da Transform kullanıyoruz. Aynı kaynak IP’den belirli bir sürede kaç başarısız giriş denemesi geldiğini hesaplayan bir transform:

PUT _transform/brute_force_detection
{
  "source": {
    "index": "siem-auth-events-*",
    "query": {
      "bool": {
        "filter": [
          { "term": { "security_event": "authentication_failure" } },
          { "range": { "@timestamp": { "gte": "now-1h" } } }
        ]
      }
    }
  },
  "pivot": {
    "group_by": {
      "src_ip": { "terms": { "field": "src_ip" } },
      "target_host": { "terms": { "field": "hostname" } }
    },
    "aggregations": {
      "failed_attempts": { "value_count": { "field": "event.code" } },
      "unique_users": { "cardinality": { "field": "failed_user" } },
      "last_attempt": { "max": { "field": "@timestamp" } }
    }
  },
  "dest": {
    "index": "siem-brute-force-summary"
  },
  "frequency": "5m"
}

Winlogbeat ile Windows Event Log Toplama

Active Directory ortamlarında kritik event ID’leri izlemek şart. Winlogbeat yapılandırması:

# winlogbeat.yml

winlogbeat.event_logs:
  - name: Security
    event_id: 4624, 4625, 4634, 4648, 4672, 4720, 4726, 4728, 4740, 4756, 7045
    level: critical, error, warning, information
    
  - name: System
    event_id: 7034, 7035, 7036, 7040, 7045
    
  - name: Application
    ignore_older: 72h

  - name: Microsoft-Windows-PowerShell/Operational
    event_id: 4103, 4104, 4105, 4106

  - name: Microsoft-Windows-Sysmon/Operational

processors:
  - add_host_metadata:
      when.not.contains.tags: forwarded
  - add_cloud_metadata: ~

output.logstash:
  hosts: ["logstash-01:5044", "logstash-02:5044"]
  loadbalance: true
  ssl.certificate_authorities: ["/etc/beats/certs/ca.crt"]
  ssl.certificate: "/etc/beats/certs/winlogbeat.crt"
  ssl.key: "/etc/beats/certs/winlogbeat.key"

PowerShell event ID 4104 özellikle önemli. Obfuscated PowerShell komutlarını yakalamak için bu event’i izlemek gerekiyor. Ransomware saldırılarının büyük çoğunluğu PowerShell üzerinden geliyor.

Linux Auditbeat ile Sistem Çağrısı İzleme

# auditbeat.yml

auditbeat.modules:
  - module: auditd
    audit_rules: |
      # Kimlik bilgilerini okuyan işlemler
      -w /etc/passwd -p wa -k identity
      -w /etc/group -p wa -k identity
      -w /etc/shadow -p wa -k identity
      
      # Sudo kullanımı
      -w /etc/sudoers -p wa -k sudoers
      -w /etc/sudoers.d/ -p wa -k sudoers
      
      # Kritik binary değişiklikleri
      -w /usr/bin/passwd -p x -k passwd_modification
      -w /usr/sbin/useradd -p x -k useradd
      -w /usr/sbin/userdel -p x -k userdel
      
      # Ağ bağlantıları
      -a always,exit -F arch=b64 -S connect -k network_connect
      
      # Cron değişiklikleri
      -w /var/spool/cron -p wa -k cron
      -w /etc/cron.d/ -p wa -k cron

  - module: file_integrity
    paths:
      - /bin
      - /usr/bin
      - /sbin
      - /usr/sbin
      - /etc
    recursive: true
    exclude_files:
      - '(?i).sw[nop]$'
      - '~$'
      - '/proc$'

  - module: system
    datasets:
      - host
      - login
      - package
      - process
      - socket
      - user
    state.period: 12h
    user.detect_password_changes: true

Kibana’da SIEM Dashboard Oluşturma

Dashboard tasarımında en önemli nokta: SOC analistinin ekrana bakıp 30 saniyede durumu anlaması gerekiyor. Karmaşık, bilgi yükleyen dashboardlar yerine hedefli, aksiyon alınabilir görünümler tercih edin.

Mutlaka bulunması gereken bileşenler:

  • Security Overview: Son 24 saatte kritik event sayısı, trend grafiği
  • Authentication Map: Coğrafi dağılım haritası, anormal konumlardan girişler
  • Top Threatened Assets: En çok hedef alınan sunucular/kullanıcılar
  • Failed Logins by User: Kilitlenme eşiğine yaklaşan hesaplar
  • Threat Intelligence Hits: Bilinen kötü IP’lerden gelen trafikler

Kibana Watcher ile Otomatik Alarm

PUT _watcher/watch/brute_force_alert
{
  "trigger": {
    "schedule": {
      "interval": "5m"
    }
  },
  "input": {
    "search": {
      "request": {
        "indices": ["siem-auth-events-*"],
        "body": {
          "query": {
            "bool": {
              "filter": [
                { "term": { "security_event": "authentication_failure" } },
                { "range": { "@timestamp": { "gte": "now-10m" } } }
              ]
            }
          },
          "aggs": {
            "by_ip": {
              "terms": { "field": "src_ip", "size": 10 },
              "aggs": {
                "attempt_count": { "value_count": { "field": "src_ip" } }
              }
            }
          }
        }
      }
    }
  },
  "condition": {
    "script": {
      "source": "return ctx.payload.aggregations.by_ip.buckets.stream().anyMatch(b -> b.attempt_count.value > 20);"
    }
  },
  "actions": {
    "send_alert": {
      "webhook": {
        "method": "POST",
        "url": "https://hooks.slack.com/services/YOUR/SLACK/WEBHOOK",
        "body": "{"text": "SIEM Alert: Brute force saldırısı tespit edildi! Kaynak IP: {{#ctx.payload.aggregations.by_ip.buckets}}{{key}}: {{attempt_count.value}} deneme {{/ctx.payload.aggregations.by_ip.buckets}}"}"
      }
    }
  }
}

Index Lifecycle Management ile Log Saklama Politikası

Güvenlik loglarını ne kadar saklayacaksınız? Hukuki gereklilikler açısından 1 yıl minimum, bazı sektörlerde 3-5 yıl zorunlu olabiliyor. ILM ile hem maliyeti kontrol altında tutabilir hem de compliance gereksinimlerini karşılayabilirsiniz:

# ILM policy oluşturma
curl -X PUT "https://localhost:9200/_ilm/policy/siem-log-policy" 
  -H "Content-Type: application/json" 
  -u elastic:$ES_PASSWORD 
  --cacert /etc/elasticsearch/certs/ca.crt 
  -d '{
    "policy": {
      "phases": {
        "hot": {
          "min_age": "0ms",
          "actions": {
            "rollover": {
              "max_age": "1d",
              "max_size": "50gb"
            },
            "set_priority": { "priority": 100 }
          }
        },
        "warm": {
          "min_age": "7d",
          "actions": {
            "shrink": { "number_of_shards": 1 },
            "forcemerge": { "max_num_segments": 1 },
            "set_priority": { "priority": 50 },
            "allocate": {
              "require": { "data": "warm" }
            }
          }
        },
        "cold": {
          "min_age": "30d",
          "actions": {
            "set_priority": { "priority": 0 },
            "allocate": {
              "require": { "data": "cold" }
            }
          }
        },
        "delete": {
          "min_age": "365d",
          "actions": {
            "delete": {}
          }
        }
      }
    }
  }'

Performans ve Ölçeklendirme Notları

Birkaç yıl önce ilk kurulumda yaptığımız hatalar:

  • Mapping explosion: Her yeni log formatı için dinamik mapping açık bırakıldığında Elasticsearch shard başına binlerce field oluşturabilir. dynamic: strict ya da dynamic: false kullanın, sadece bilinen fieldları kabul edin.
  • Shard boyutu: Güvenlik loglarında shard başına 30-50 GB ideal. Çok küçük shardlar overhead yaratır, çok büyük shardlar recovery süresini uzatır.
  • Heap ayarları: JVM heap’i toplam RAM’in yarısına eşitleyin ama 32 GB’ı geçmeyin. 32 GB üzerinde compressed ordinary object pointer optimizasyonu devre dışı kalıyor.
  • Logstash worker sayısı: pipeline.workers değerini CPU core sayısına eşitleyin. Log parsing CPU bound bir işlem.

Güvenlik Operasyonu: Günlük Rutin

ELK SIEM’i kurduktan sonra asıl iş başlıyor. Sabah mesaiye geldiğimde ilk yaptığım şeyler:

  • Gece boyunca tetiklenen Watcher alarmlarını kontrol etmek
  • Threat intelligence match sayısına bakmak, artış var mı?
  • Yeni servis kurulumu event’lerini gözden geçirmek (Windows Event 7045)
  • Kritik sunuculara gece yarısı yapılan başarılı girişleri incelemek
  • Auditbeat’ten gelen dosya bütünlüğü değişikliklerine bakmak

Bu rutini Kibana’da otomatikleştirmek mümkün. Scheduled reporting ile her sabah e-posta ile özet rapor alabilirsiniz. Elastic Security’nin ML tabanlı anomali tespiti de zamanla ortamınızı öğrenerek gürültüyü azaltıyor.

Sonuç

ELK Stack ile gerçek bir SIEM kurmak, Kibana’yı açıp birkaç dashboard oluşturmaktan çok daha fazlasını gerektiriyor. Doğru pipeline tasarımı, normalize edilmiş veri modeli, güvenli iletişim kanalları ve düzenli bakım olmadan sisteminiz ya veri kaybeder ya da arama yapılamaz hale gelir.

Ama doğru yapılandırıldığında ne elde ediyorsunuz? Günde milyonlarca event içinden saniyeler içinde anlamlı korelasyonlar çıkarabildiğiniz, tehdit avı yapabildiğiniz, uyumluluk raporları üretebildiğiniz bir platform. Üstelik veri hacminize göre lisans ödemeden.

En büyük tavsiyem: Başlangıçta kapsamı dar tutun. Tüm logları bir anda almaya çalışmak yerine en kritik kaynakları önce alın, bunları düzgün çalıştırın, sonra genişletin. Büyük patlamayla başlayıp yönetilemez hale gelen birçok ELK SIEM projesi gördüm. Küçük ama sağlam temelli bir kurulum her zaman daha değerlidir.

Bir yanıt yazın

E-posta adresiniz yayınlanmayacak. Gerekli alanlar * ile işaretlenmişlerdir