Zabbix ile SSL Sertifika Sona Erme İzleme

Geçen ay bir müşterimizin production ortamında tam da kritik bir demo sırasında SSL sertifikası sona erdi. Tarayıcı “Bu siteye güvenli değil” diye bağıra bağıra uyarı verirken ekip panikle sertifikayı yenilemeye çalışıyordu. O gün sonra o ortama Zabbix tabanlı bir SSL izleme sistemi kurdum ve bir daha böyle bir şeyle karşılaşmadık. Bu yazıda o deneyimden öğrendiklerimi sizinle paylaşacağım.

Neden SSL İzleme Bu Kadar Önemli?

Çoğu sysadmin “Let’s Encrypt kullanıyorum, otomatik yenileniyor” diye düşünür. Doğru, ama şunu düşünün: certbot cron job’u çalışmayı bıraktıysa? Proxy arkasındaki bir servis için sertifika yenilenirken bir şeyler ters gittiyse? Veya eski yöntemle alınmış, elle yönetilen onlarca wildcard sertifikanız varsa?

SSL sertifikası izleme, aslında birden fazla problemi aynı anda çözer:

  • Sona erme takibi: Sertifikanın kaç gün ömrü kaldığını bilmek
  • Uyumluluk kontrolü: Sertifikanın gerçekten HTTPS üzerinden servis edilip edilmediğini kontrol etmek
  • Konfigürasyon sorunları: Sertifika zincirinin doğru yapılandırılıp yapılandırılmadığını doğrulamak
  • Wildcard ve SAN izleme: Birden fazla domain barındıran sertifikaları takip etmek

Zabbix bu iş için hem esnek hem de güçlü bir platform. Ama doğru yapılandırılmazsa çok fazla gürültü üretir ya da hiçbir şey yapmaz.

Zabbix’in Native SSL Kontrolü

Zabbix 4.0 ve sonrasında web.certificate.get item key’i natively gelir. Ama dikkat edin, bu key bir web senaryosu içinde çalışır, standalone item olarak değil. Zabbix 6.0 ile birlikte durum biraz daha değişti ve daha esnek kullanım imkanı geldi.

Önce Zabbix agent’ın yüklü olduğunu ve zabbix_agentd.conf dosyasının düzgün yapılandırıldığını varsayarak ilerliyorum.

web.certificate.get ile Basit Kontrol

Zabbix’in built-in metodunu kullanmak istiyorsanız, aşağıdaki şekilde bir item oluşturabilirsiniz:

# Zabbix Server tarafında test etmek için:
zabbix_get -s 127.0.0.1 -p 10050 -k "web.certificate.get[example.com,443,https]"

Bu komut size JSON formatında sertifika bilgilerini döndürür. İçinde not_after, issuer, subject gibi alanlar bulunur. Ancak bu JSON’u parse etmek için dependent item’lar kullanmanız gerekir ki bu konuya birazdan değineceğiz.

External Check ile Özelleştirilmiş SSL İzleme

Benim tercih ettiğim yöntem, özellikle heterojen ortamlarda, external script kullanmak. Çünkü native metodun bazı kısıtları var. Örneğin client certificate gerektiren endpoint’leri kontrol edemezsiniz, timeout ayarlarınız çok fazla esneklik tanımaz.

Script Yazımı

/usr/lib/zabbix/externalscripts/ dizinine aşağıdaki scripti oluşturun:

#!/bin/bash
# ssl_check.sh - SSL sertifika sona erme günü hesaplama

HOST=$1
PORT=${2:-443}
TIMEOUT=${3:-10}

if [ -z "$HOST" ]; then
    echo "-1"
    exit 1
fi

# SSL bağlantısı kur ve sertifika bilgisini al
CERT_INFO=$(echo | timeout $TIMEOUT openssl s_client 
    -servername "$HOST" 
    -connect "$HOST:$PORT" 2>/dev/null | 
    openssl x509 -noout -enddate 2>/dev/null)

if [ $? -ne 0 ] || [ -z "$CERT_INFO" ]; then
    echo "-1"
    exit 1
fi

# Bitiş tarihini parse et
EXPIRY_DATE=$(echo "$CERT_INFO" | cut -d= -f2)

# Epoch'a çevir
if [[ "$OSTYPE" == "darwin"* ]]; then
    EXPIRY_EPOCH=$(date -j -f "%b %d %H:%M:%S %Y %Z" "$EXPIRY_DATE" +%s 2>/dev/null)
else
    EXPIRY_EPOCH=$(date -d "$EXPIRY_DATE" +%s 2>/dev/null)
fi

NOW_EPOCH=$(date +%s)

# Kalan günü hesapla
DAYS_LEFT=$(( ($EXPIRY_EPOCH - $NOW_EPOCH) / 86400 ))

echo $DAYS_LEFT

Script’e çalıştırma izni verin:

chmod +x /usr/lib/zabbix/externalscripts/ssl_check.sh
chown zabbix:zabbix /usr/lib/zabbix/externalscripts/ssl_check.sh

Script’i test edin:

/usr/lib/zabbix/externalscripts/ssl_check.sh example.com 443
# Çıktı: 87 (kalan gün sayısı)

Zabbix’te Item Oluşturma

Şimdi bu script’i Zabbix’e tanıtalım. Template üzerinden gitmek her zaman daha iyi bir pratik, çünkü yüzlerce host’a tek seferde uygulayabilirsiniz.

Template Oluşturma

Zabbix web arayüzünden Configuration > Templates > Create Template yolunu izleyin. Template adı olarak “SSL Certificate Monitoring” kullanabilirsiniz.

Template içinde bir item oluşturun:

  • Name: SSL Certificate Expiry Days
  • Type: External check
  • Key: ssl_check.sh[{$SSL_HOST},{$SSL_PORT}]
  • Type of information: Numeric (unsigned)
  • Update interval: 1h (saatte bir kontrol yeterli)
  • History storage period: 30d

Burada {$SSL_HOST} ve {$SSL_PORT} makrolar olacak. Bu makroları host seviyesinde tanımlayacaksınız.

Dependent Item ile Zabbix Native Metodunu Kullananlar İçin

Eğer native web.certificate.get kullanmak istiyorsanız, önce master item oluşturun:

# Item key:
web.certificate.get[{$SSL_HOST},443,https]

Ardından bu item’a bağlı dependent item’lar oluşturun. Sona erme tarihi için:

  • Name: SSL Certificate Expiry Timestamp
  • Type: Dependent item
  • Master item: Az önce oluşturduğunuz web.certificate.get item’ı
  • Preprocessing: JSONPath ile $.x509.not_after.timestamp

Kalan günü hesaplamak için ise şu preprocessing adımını ekleyin:

# JSONPath sonrası Change per second değil, custom multiplier da değil
# Bir JavaScript preprocessing adımı ekleyin:

var data = JSON.parse(value);
var expiryTimestamp = data.x509.not_after.timestamp;
var now = Math.floor(Date.now() / 1000);
var daysLeft = Math.floor((expiryTimestamp - now) / 86400);
return daysLeft.toString();

Trigger Yapılandırması

Item’lar çalışıyor olsa da asıl önemli kısım trigger’lar. Burada çok agresif alarm üretmemek önemli, ama kritik eşikleri de kaçırmamak gerekiyor.

# Zabbix trigger expression örnekleri:

# Kritik: 7 gün veya daha az kaldı
last(/Template SSL Monitoring/ssl_check.sh[{$SSL_HOST},{$SSL_PORT}])<7

# Yüksek: 14 gün veya daha az kaldı
last(/Template SSL Monitoring/ssl_check.sh[{$SSL_HOST},{$SSL_PORT}])<14

# Uyarı: 30 gün veya daha az kaldı
last(/Template SSL Monitoring/ssl_check.sh[{$SSL_HOST},{$SSL_PORT}])<30

# Bilgi: Sertifika kontrol edilemiyor (-1 döndü)
last(/Template SSL Monitoring/ssl_check.sh[{$SSL_HOST},{$SSL_PORT}])=-1

Bu trigger’ları oluştururken severity seviyelerini doğru ayarlayın:

  • 30 gün kala: Warning
  • 14 gün kala: High
  • 7 gün kala: Disaster
  • Erişilemiyor (-1): High

Trigger Dependencies

Eğer bir host zaten down ise SSL alarm üretmesini istemezsiniz. Zabbix’te trigger dependency kurarak bu durumu handle edebilirsiniz. SSL trigger’larınızı host availability trigger’ına bağlayın, böylece host zaten erişilemezse gereksiz SSL alarmı gelmez.

Çoklu Domain İzleme için UserParameter

Tek bir host üzerinde birden fazla domain’i izlemek isteyebilirsiniz. Örneğin bir load balancer arkasında onlarca sanal host barındırıyorsunuz. Bu durumda UserParameter daha kullanışlı:

# /etc/zabbix/zabbix_agentd.d/ssl_monitoring.conf

UserParameter=ssl.cert.expiry[*],/usr/lib/zabbix/externalscripts/ssl_check.sh "$1" "$2"
UserParameter=ssl.cert.issuer[*],/usr/lib/zabbix/externalscripts/ssl_issuer.sh "$1" "$2"
UserParameter=ssl.cert.subject[*],/usr/lib/zabbix/externalscripts/ssl_subject.sh "$1" "$2"

Issuer bilgisini çeken script de şu şekilde olabilir:

#!/bin/bash
# ssl_issuer.sh - Sertifika veren kurum bilgisi

HOST=$1
PORT=${2:-443}

ISSUER=$(echo | timeout 10 openssl s_client 
    -servername "$HOST" 
    -connect "$HOST:$PORT" 2>/dev/null | 
    openssl x509 -noout -issuer 2>/dev/null | 
    sed 's/issuer=//')

if [ -z "$ISSUER" ]; then
    echo "UNKNOWN"
else
    echo "$ISSUER"
fi

Agent’ı restart ettikten sonra Zabbix server’dan test edebilirsiniz:

zabbix_get -s <agent_ip> -p 10050 -k "ssl.cert.expiry[example.com,443]"

Discovery Rule ile Otomatik Keşif

Büyük ortamlarda her domain’i elle eklemek pratik değil. Low-level discovery kullanarak dinamik bir yapı kurabilirsiniz.

Önce bir discovery script yazın:

#!/bin/bash
# ssl_discovery.sh - İzlenecek domainleri JSON formatında döndürür

DOMAIN_LIST="/etc/zabbix/ssl_domains.txt"

if [ ! -f "$DOMAIN_LIST" ]; then
    echo '{"data":[]}'
    exit 0
fi

OUTPUT='{"data":['
FIRST=true

while IFS= read -r line || [ -n "$line" ]; do
    # Yorum satırlarını ve boş satırları atla
    [[ "$line" =~ ^#.*$ ]] && continue
    [ -z "$line" ] && continue
    
    HOST=$(echo "$line" | cut -d: -f1)
    PORT=$(echo "$line" | cut -d: -f2)
    PORT=${PORT:-443}
    
    if [ "$FIRST" = true ]; then
        FIRST=false
    else
        OUTPUT="$OUTPUT,"
    fi
    
    OUTPUT="$OUTPUT{"{#SSL_HOST}":"$HOST","{#SSL_PORT}":"$PORT"}"
    
done < "$DOMAIN_LIST"

OUTPUT="$OUTPUT]}"
echo "$OUTPUT"

Domain listesi dosyasını oluşturun:

# /etc/zabbix/ssl_domains.txt
example.com:443
api.example.com:443
mail.example.com:465
internal-app.company.local:8443
# wildcard için ana domain yeterli

Bu script’i de externalscripts dizinine koyun ve Zabbix’te bir discovery rule oluşturun:

  • Name: SSL Domain Discovery
  • Type: External check
  • Key: ssl_discovery.sh
  • Update interval: 1d (günde bir kez keşif yeterli)

Discovery rule içinde item prototype ve trigger prototype oluşturun, makrolar olarak {#SSL_HOST} ve {#SSL_PORT} kullanın.

Grafana ile Görselleştirme

Zabbix’in kendi grafik arayüzü SSL expiry için yeterli, ama ekibiniz Grafana kullanıyorsa Zabbix datasource üzerinden güzel bir dashboard hazırlayabilirsiniz.

Zabbix API ile veri çekmek için şu sorguyu kullanabilirsiniz:

# Zabbix API ile tüm SSL item değerlerini çek
curl -s -X POST http://zabbix-server/api_jsonrpc.php 
  -H "Content-Type: application/json" 
  -d '{
    "jsonrpc": "2.0",
    "method": "item.get",
    "params": {
        "output": ["name","lastvalue","hosts"],
        "search": {
            "key_": "ssl_check"
        },
        "selectHosts": ["host"]
    },
    "auth": "YOUR_AUTH_TOKEN",
    "id": 1
  }' | python3 -m json.tool

Grafana’da stat panel kullanarak kalan gün sayısını threshold renkleriyle göstermek çok etkileyici bir dashboard çıkarıyor. Kırmızı = 14 gün altı, sarı = 30 gün altı, yeşil = 30 gün üstü gibi.

Gerçek Dünyadan Dersler

Teorinin ötesinde, bu sistemi kurarken ve işletirken birkaç önemli şey öğrendim.

Timeout değerlerini iyi ayarlayın. Bazı sistemler SSL handshake sırasında çok yavaş yanıt verir. Özellikle network gecikmeleri yüksek ortamlarda 10 saniyelik timeout yetersiz kalabiliyor. 15-20 saniyeye çıkarmak bazen gerekiyor, ama bunu Zabbix item timeout ile de senkronize etmelisiniz.

IPv6 karmaşası. Dual-stack ortamlarda openssl bazen IPv6 üzerinden bağlanmaya çalışır ve bu farklı sonuçlar üretebilir. Script’inizde -4 flag’ini zorunlu tutmak daha tutarlı sonuçlar verebilir:

# IPv4 zorunlu bağlantı
CERT_INFO=$(echo | timeout $TIMEOUT openssl s_client 
    -4 
    -servername "$HOST" 
    -connect "$HOST:$PORT" 2>/dev/null | 
    openssl x509 -noout -enddate 2>/dev/null)

Proxy arkasındaki sistemler. İç network’te proxy arkasında kalan sistemler için script’e proxy desteği eklemek gerekebilir. Alternatif olarak Zabbix proxy kullanmak daha temiz bir çözüm.

Alert fatigue. 30 günlük uyarı eşiği bazı ortamlarda çok fazla gürültü yaratır. Eğer Let’s Encrypt kullanıyorsanız ve 90 günlük sertifika alıyorsanız, 45. günde alarm gelmeye başlıyor ama certbot zaten 30. günde yenileme yapıyor. Bu durumda uyarı eşiğini 20 güne indirmek mantıklı.

Non-standard portlar. 443 dışında SSL kullanan servisleri unutmayın: LDAPS (636), IMAPS (993), SMTPS (465), custom portlardaki microservice’ler. Discovery list’ini oluştururken bunları da dahil edin.

Bildirim Kanallarını Doğru Ayarlama

SSL alarmları için Zabbix’te ayrı bir action oluşturmanızı öneririm. Böylece bu alarmlar için farklı bir bildirim kanalı (örneğin doğrudan email yerine Slack veya PagerDuty) kullanabilirsiniz.

Action condition’larında şunu kullanabilirsiniz:

  • Trigger name contains “SSL”
  • Trigger severity is greater than or equal to Warning

Bu action için bir mesaj template’i:

SSL Sertifika Uyarısı

Host: {HOST.NAME}
Domain: {ITEM.VALUE1}
Kalan Gun: {ITEM.LASTVALUE}
Trigger: {TRIGGER.NAME}
Severity: {TRIGGER.SEVERITY}

Zabbix Link: {TRIGGER.URL}

Sonuç

SSL sertifika izleme, sysadmin’lerin çoğunlukla “bir gün yapacağım” listesinde bekleyen ama ilk sertifika krizi yaşanana kadar ertelenen bir konudur. Zabbix ile bu sistemi bir kere doğru kurduğunuzda neredeyse sıfır bakım gerektiriyor.

Özet olarak yapmanız gerekenler:

  • External script veya native web.certificate.get metodunu seçin
  • Ortamınızın büyüklüğüne göre elle tanımlama ya da discovery rule kullanın
  • Trigger eşiklerini 30/14/7 gün üzerine kurgulayın
  • SSL alarm aksiyonlarını normal alarmlardan ayırın
  • Non-standard portları ve internal servisleri unutmayın

Production ortamda bu sistemi birkaç yıldır çalıştırıyorum. Şimdiye kadar hiçbir sertifika sona erme vakası yaşamadık, ki bu tek başına yeterince iyi bir başarı ölçütü. Umarım sizin ortamınızda da aynı rahatlığı sağlar.

Bir yanıt yazın

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