Unbound DNS Sunucusunda Monitoring ve Alerting: Prometheus ve Grafana ile İzleme

DNS altyapınızın ne durumda olduğunu bilmeden sistemi yönetmek, arabasının gösterge panelini bantla kapatıp sürmek gibidir. Unbound DNS sunucunuz çalışıyor olabilir, ama kaç sorgu işliyor, cache hit oranı ne, yanıt süreleri normal mi? Bu sorulara cevap veremiyorsanız, bu yazı tam size göre.

Bu rehberde Unbound DNS sunucusunu Prometheus ile nasıl izleyeceğinizi, Grafana’da anlamlı dashboard’lar nasıl oluşturacağınızı ve kritik eşiklere ulaşıldığında nasıl alert alacağınızı adım adım anlatacağım. Küçük bir şirket altyapısından kurumsal ortama kadar uygulanabilir, gerçek dünya odaklı bir rehber olacak.

Neden Unbound Monitoring Gerekli?

Unbound, varsayılan olarak oldukça sessiz çalışır. Bir şeyler ters gidene kadar fark etmezsiniz, ta ki kullanıcılar “internet çalışmıyor” diye gelene kadar. Oysa DNS sorunları çoğunlukla ani değil, yavaş yavaş ortaya çıkar:

  • Cache hit oranı düşmeye başlar, sorgular yavaşlar
  • Upstream resolver’lara bağlantı sorunları olur, timeout’lar artar
  • Sorgu sayısı anormal yükselir, DDoS veya misconfiguration işareti olabilir
  • Memory kullanımı giderek artar, restart gerekmeden yakalanması gerekir

Monitoring olmadan bunların hiçbirini önceden yakalayamazsınız. Prometheus + Grafana kombinasyonu, Unbound için mükemmel bir izleme çözümü sunar.

Ortam ve Ön Gereksinimler

Bu rehberde şu ortamı varsayıyorum:

  • OS: Ubuntu 22.04 LTS (Debian tabanlı her sistemde benzer şekilde çalışır)
  • Unbound: 1.17+
  • Prometheus: 2.45+
  • Grafana: 10.x
  • Unbound ve Prometheus/Grafana aynı sunucuda veya aynı ağda

Unbound kurulu ve çalışıyor olduğunu varsayıyorum. Eğer kurmadıysanız önce temel kurulumu tamamlayın.

Unbound’da İstatistik Toplama Aktif Etme

Her şeyden önce Unbound’un istatistik üretmesini sağlamamız gerekiyor. Unbound, unbound-control stats komutuyla çok detaylı metrik verir, ama bunun için remote-control modülünün aktif olması şart.

/etc/unbound/unbound.conf.d/stats.conf dosyası oluşturun:

sudo nano /etc/unbound/unbound.conf.d/stats.conf

İçine şunları yazın:

server:
    # İstatistik toplama aktif
    statistics-interval: 0
    statistics-cumulative: yes
    extended-statistics: yes

remote-control:
    control-enable: yes
    control-interface: 127.0.0.1
    control-port: 8953
    control-use-cert: yes
    server-key-file: "/etc/unbound/unbound_server.key"
    server-cert-file: "/etc/unbound/unbound_server.pem"
    control-key-file: "/etc/unbound/unbound_control.key"
    control-cert-file: "/etc/unbound/unbound_control.pem"

statistics-cumulative: yes ayarı önemli. Bu sayede metrikler sıfırlanmadan birikimli olarak tutulur, Prometheus’un zaten delta hesapladığını düşünürsek bu daha sağlıklı sonuç verir.

Şimdi TLS sertifikalarını oluşturalım:

sudo unbound-control-setup

Bu komut otomatik olarak gerekli key ve sertifikaları /etc/unbound/ altına oluşturur. Ardından Unbound’u yeniden başlatın:

sudo systemctl restart unbound
sudo unbound-control stats_noreset | head -20

Çıktıda thread0.num.queries, total.num.cachehits gibi satırlar görüyorsanız istatistikler çalışıyor demektir.

Prometheus Exporter Kurulumu

Unbound için en olgun exporter unbound_exporter‘dır. GitHub’da letsencrypt/unbound_exporter projesi aktif olarak geliştirilmektedir.

Exporter’ı Binary Olarak Kurmak

# Son sürümü indir
wget https://github.com/letsencrypt/unbound_exporter/releases/download/v0.4.6/unbound_exporter-0.4.6.linux-amd64.tar.gz

# Çıkart ve yerleştir
tar xzf unbound_exporter-0.4.6.linux-amd64.tar.gz
sudo mv unbound_exporter-0.4.6.linux-amd64/unbound_exporter /usr/local/bin/
sudo chmod +x /usr/local/bin/unbound_exporter

# Dedicated kullanıcı oluştur
sudo useradd -rs /bin/false unbound_exporter

Systemd Service Dosyası

sudo nano /etc/systemd/system/unbound_exporter.service
[Unit]
Description=Unbound Prometheus Exporter
After=network.target unbound.service
Wants=unbound.service

[Service]
User=unbound_exporter
Group=unbound_exporter
Type=simple
ExecStart=/usr/local/bin/unbound_exporter 
    --unbound.host=tcp://127.0.0.1:8953 
    --unbound.ca=/etc/unbound/unbound_server.pem 
    --unbound.cert=/etc/unbound/unbound_control.pem 
    --unbound.key=/etc/unbound/unbound_control.key 
    --web.listen-address=:9167 
    --web.telemetry-path=/metrics

Restart=always
RestartSec=3

[Install]
WantedBy=multi-user.target

Exporter’ın Unbound sertifikalarını okuyabilmesi için izin vermemiz gerekiyor:

sudo usermod -aG unbound unbound_exporter
sudo chmod 640 /etc/unbound/unbound_control.key
sudo chgrp unbound /etc/unbound/unbound_control.key

sudo systemctl daemon-reload
sudo systemctl enable --now unbound_exporter
sudo systemctl status unbound_exporter

Metriklerin geldiğini doğrulayın:

curl -s http://localhost:9167/metrics | grep unbound_

unbound_query_total, unbound_cache_hits_total, unbound_answer_rcode_total gibi metrikler görüyorsanız exporter düzgün çalışıyor.

Prometheus Yapılandırması

Prometheus’un zaten kurulu olduğunu varsayıyorum. Eğer yoksa apt install prometheus ile kurabilirsiniz veya binary kurulumu tercih edebilirsiniz.

/etc/prometheus/prometheus.yml dosyasına unbound job’ını ekleyin:

scrape_configs:
  # Mevcut job'larınız...
  
  - job_name: 'unbound'
    static_configs:
      - targets: ['localhost:9167']
        labels:
          instance: 'dns-01'
          environment: 'production'
    scrape_interval: 15s
    scrape_timeout: 10s
    metrics_path: /metrics

Birden fazla DNS sunucunuz varsa targets’ı genişletebilirsiniz:

  - job_name: 'unbound'
    static_configs:
      - targets: 
          - 'dns-01.internal:9167'
          - 'dns-02.internal:9167'
        labels:
          environment: 'production'
    relabel_configs:
      - source_labels: [__address__]
        target_label: instance
        regex: '([^:]+)(?::d+)?'
        replacement: '${1}'

Prometheus’u yeniden yükleyin:

sudo systemctl reload prometheus

Prometheus UI’da (genellikle port 9090) Status > Targets bölümünde unbound target’ının UP durumda olduğunu görmelisiniz.

Grafana Dashboard Oluşturma

Grafana’da anlamlı bir Unbound dashboard’u oluşturmak için hangi metriklerin önemli olduğunu bilmek gerekiyor.

Önemli Unbound Metrikleri

  • unbound_query_total: Toplam sorgu sayısı (rate ile kullanın)
  • unbound_cache_hits_total: Cache’den karşılanan sorgular
  • unbound_cache_misses_total: Cache’de bulunamayan sorgular
  • unbound_answer_rcode_total: NOERROR, NXDOMAIN, SERVFAIL gibi yanıt kodları
  • unbound_memory_cache_bytes: Cache bellek kullanımı
  • unbound_memory_mod_bytes: Modül bellek kullanımı
  • unbound_time_up_seconds_total: Sunucu uptime
  • unbound_query_duration_seconds: Sorgu yanıt süresi histogram’ı
  • unbound_prefetch_count_total: Prefetch yapılan kayıt sayısı

Temel Panel Sorguları

Grafana’da yeni bir dashboard oluşturun ve şu panelleri ekleyin.

Panel 1: Sorgu Hızı (QPS)

rate(unbound_query_total{job="unbound"}[5m])

Bu panel saniyedeki sorgu sayısını gösterir. Ani artışlar dikkat gerektiren durumlardır.

Panel 2: Cache Hit Oranı

rate(unbound_cache_hits_total{job="unbound"}[5m]) 
/ 
(rate(unbound_cache_hits_total{job="unbound"}[5m]) + rate(unbound_cache_misses_total{job="unbound"}[5m])) 
* 100

Bu değerin %70’in altına düşmesi sorun işaretidir. Sağlıklı bir DNS sunucusunda cache hit oranı %80-90 civarında olmalıdır.

Panel 3: SERVFAIL Oranı

rate(unbound_answer_rcode_total{job="unbound", rcode="SERVFAIL"}[5m])
/
rate(unbound_query_total{job="unbound"}[5m])
* 100

Panel 4: Bellek Kullanımı

unbound_memory_cache_bytes{job="unbound"} + unbound_memory_mod_bytes{job="unbound"}

Grafana Dashboard JSON Import

Grafana topluluk dashboard’ları için grafana.com/dashboards adresinde Unbound için hazır dashboard’lar bulabilirsiniz. Dashboard ID 11705 iyi bir başlangıç noktasıdır, ancak kendi ortamınıza göre özelleştirmenizi öneririm.

Alerting Kuralları

İzlemenin en kritik parçası alerting. Prometheus’ta alert rule’ları tanımlar, Alertmanager ile bildirimleri yönetirsiniz.

/etc/prometheus/rules/unbound.yml dosyası oluşturun:

groups:
  - name: unbound_alerts
    interval: 30s
    rules:
    
      # DNS sunucusu erişilemiyor
      - alert: UnboundDown
        expr: up{job="unbound"} == 0
        for: 1m
        labels:
          severity: critical
          team: infrastructure
        annotations:
          summary: "Unbound DNS sunucusu erişilemiyor"
          description: "{{ $labels.instance }} - Unbound exporter'a 1 dakikadır ulaşılamıyor. DNS servisi çalışmıyor olabilir."
          runbook: "https://wiki.internal/runbooks/unbound-down"

      # Yüksek SERVFAIL oranı
      - alert: UnboundHighServfailRate
        expr: |
          (
            rate(unbound_answer_rcode_total{rcode="SERVFAIL"}[5m])
            /
            rate(unbound_query_total[5m])
          ) * 100 > 5
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Yüksek SERVFAIL oranı tespit edildi"
          description: "{{ $labels.instance }} sunucusunda SERVFAIL oranı {{ $value | printf "%.2f" }}% seviyesinde. Upstream resolver'larda sorun olabilir."

      # Düşük cache hit oranı
      - alert: UnboundLowCacheHitRate
        expr: |
          (
            rate(unbound_cache_hits_total[10m])
            /
            (rate(unbound_cache_hits_total[10m]) + rate(unbound_cache_misses_total[10m]))
          ) * 100 < 60
        for: 15m
        labels:
          severity: warning
        annotations:
          summary: "Cache hit oranı kritik seviyenin altında"
          description: "{{ $labels.instance }} - Cache hit oranı {{ $value | printf "%.1f" }}%. Normal değer >70% olmalıdır. Cache boyutunu artırmayı değerlendirin."

      # Anormal yüksek sorgu sayısı
      - alert: UnboundHighQueryRate
        expr: rate(unbound_query_total[5m]) > 10000
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "Anormal yüksek DNS sorgu oranı"
          description: "{{ $labels.instance }} - Saniyede {{ $value | printf "%.0f" }} sorgu işleniyor. Olası DNS amplification saldırısı veya misconfigured client."

      # Yüksek bellek kullanımı  
      - alert: UnboundHighMemoryUsage
        expr: |
          (unbound_memory_cache_bytes + unbound_memory_mod_bytes) / 1024 / 1024 > 512
        for: 10m
        labels:
          severity: warning
        annotations:
          summary: "Unbound bellek kullanımı yüksek"
          description: "{{ $labels.instance }} - Unbound {{ $value | printf "%.0f" }} MB bellek kullanıyor."

Prometheus’a bu dosyayı tanıtın:

# prometheus.yml içine ekleyin
rule_files:
  - "rules/unbound.yml"
  - "rules/*.yml"

Kural syntax’ını kontrol edin:

promtool check rules /etc/prometheus/rules/unbound.yml
sudo systemctl reload prometheus

Alertmanager Yapılandırması

Alert’lerin Slack ve email ile gelmesi için Alertmanager konfigürasyonu:

global:
  smtp_smarthost: 'smtp.company.com:587'
  smtp_from: '[email protected]'
  smtp_auth_username: '[email protected]'
  smtp_auth_password: 'sifre'

route:
  group_by: ['alertname', 'instance']
  group_wait: 30s
  group_interval: 5m
  repeat_interval: 4h
  receiver: 'default'
  routes:
    - match:
        severity: critical
      receiver: 'critical-alerts'
      repeat_interval: 1h
    - match:
        severity: warning
      receiver: 'warning-alerts'

receivers:
  - name: 'default'
    email_configs:
      - to: '[email protected]'

  - name: 'critical-alerts'
    email_configs:
      - to: '[email protected], [email protected]'
        subject: '[CRITICAL] {{ .GroupLabels.alertname }}'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/XXXXX'
        channel: '#alerts-critical'
        title: 'CRITICAL: {{ .GroupLabels.alertname }}'
        text: '{{ range .Alerts }}{{ .Annotations.description }}{{ end }}'

  - name: 'warning-alerts'
    slack_configs:
      - api_url: 'https://hooks.slack.com/services/XXXXX'
        channel: '#alerts-warning'

Gerçek Dünya Senaryosu: Upstream Sorununu Erken Yakalamak

Bir gün ofis saatleri başlamadan sabah 07:30’da UnboundHighServfailRate alertı geldi. SERVFAIL oranı %12’ye çıkmıştı. Grafana’ya bakıldığında görüldü ki cache miss oranı da aynı anda artmış, yani önbelleğe alınmış kayıtlar süresi dolmaya başlamış, upstream’e giden sorgular hata dönüyordu.

Unbound log’larına bakınca upstream olarak kullanılan ISP’nin recursive resolver’larında sorun olduğu anlaşıldı. Monitoring olmasaydı, kullanıcılar geldiğinde “sabahtan beri internet çalışmıyor” diye şikayet edecekti. Alert sayesinde kullanıcılar gelmeden önce upstream resolver’lar değiştirildi ve sorun kapatıldı.

Bunu mümkün kılan şey şu Grafana paneliydi: SERVFAIL rate ile cache miss rate’i aynı grafikte görmek, korelasyonu anında ortaya koyuyordu.

Log Tabanlı Monitoring ile Tamamlamak

Prometheus metrikleri sayısal olayları izler, ama bazen log’lara da bakmanız gerekir. Loki + Promtail kombinasyonu ile Unbound log’larını da Grafana’ya çekebilirsiniz.

Unbound’da query logging aktif etmek için:

server:
    verbosity: 1
    log-queries: yes
    log-replies: yes
    log-tag-queryreply: yes

Dikkat: Production ortamında log-queries çok yüksek disk yazma üretebilir. Yüksek trafikli sunucularda bu ayarı sadece debug gerektiğinde açın veya rate limiting uygulayın.

Dashboard İçin İpuçları

Grafana dashboard’ınızı daha kullanışlı hale getirmek için birkaç öneri:

  • Time range: Default olarak son 1 saati gösterin, haftalık trend için “last 7 days” preset ekleyin
  • Annotation’lar: Unbound restart zamanlarını annotation olarak ekleyin, metrik değişikliklerini restart’larla ilişkilendirmek kolaylaşır
  • Variable’lar: Birden fazla DNS sunucunuz varsa instance için Grafana variable tanımlayın, tek dashboard’dan tüm sunucuları izleyin
  • Alert panel’leri: Dashboard’un üstüne alert durumlarını gösteren stat panel’ler ekleyin, tek bakışta durum anlaşılsın

Sonuç

Unbound’u kurmak bir saatlik iş, ama monitoring olmadan onu gözü kapalı yönetiyorsunuz demektir. Prometheus exporter kurulumu, birkaç alert kuralı ve bir Grafana dashboard ile DNS altyapınız şeffaf hale gelir. Sabah iş başlarken dashboard’a bir bakış, gün boyunca kafanızın rahat olmasını sağlar.

Bu yazıda anlattığım yapı temel bir başlangıç noktası. Zamanla kendi ortamınızın normal değerlerini öğreneceksiniz, alert eşiklerini buna göre fine-tune edeceksiniz. Özellikle cache hit oranı için kendi ortamınızdaki baseline’ı bulun, %60 çok düşük olan bir ortamda %75 de kabul edilebilir olmayabilir.

DNS izleme sistemini kurduktan sonra bir sonraki adım olarak Unbound’un DNSSEC doğrulama hatalarını da takip etmeyi, RPZ (Response Policy Zone) istatistiklerini eklemeyi düşünebilirsiniz. DNS altyapısı ne kadar görünür olursa, sorunları o kadar erken ve az stresle çözebilirsiniz.

Bir yanıt yazın

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