Modern mail altyapılarında güvenlik ve merkezi kimlik yönetimi giderek daha kritik bir hal alıyor. Özellikle kurumsal ortamlarda kullanıcıların tek bir kimlik sağlayıcısı üzerinden birden fazla servise erişebilmesi hem kullanıcı deneyimini hem de güvenlik yönetimini kolaylaştırıyor. Dovecot’u OAuth2 ile entegre etmek de tam bu noktada devreye giriyor: Artık kullanıcıların mail parolasını ayrıca yönetmek yerine, mevcut identity provider’ınızı (Keycloak, Google Workspace, Azure AD) kullanarak IMAP/POP3 erişimini kontrol edebilirsiniz.
OAuth2 Kimlik Doğrulama Neden Önemli?
Geleneksel yaklaşımda Dovecot, kullanıcı adı ve parola ikilisini doğrudan kendi veritabanına, LDAP’a ya da PAM’a karşı kontrol eder. Bu yöntem işlevsel olsa da bazı ciddi sorunları beraberinde getirir. Parola yönetimi dağınık hale gelir, MFA (çok faktörlü doğrulama) entegrasyonu zorlaşır ve merkezi bir kimlik revokasyon mekanizması kurmak için ekstra çaba gerekir.
OAuth2 entegrasyonu ile Dovecot, token bazlı doğrulama yapabilir hale gelir. Mail istemcisi, kullanıcı adı olarak kullanıcının e-posta adresini, parola alanına ise bir Bearer token gönderir. Dovecot bu token’ı yapılandırdığınız introspection endpoint’ine göndererek geçerliliğini kontrol eder. Token geçerliyse erişim verilir, değilse reddedilir. Basit ve zarif.
Bu yazıda Keycloak üzerinden pratik bir senaryo kurarak Dovecot OAuth2 entegrasyonunu baştan sona ele alacağız. Aynı yapı küçük farklarla Google, Azure AD veya herhangi bir RFC 7662 uyumlu authorization server için de çalışır.
Gereksinimler ve Ön Hazırlık
Ortamımızı netleştirelim. Bu yazıdaki örnekler Ubuntu 22.04 üzerinde Dovecot 2.3.x ve Keycloak 21.x ile test edilmiştir. Yapılandırma mantığı Debian tabanlı dağıtımlarda büyük ölçüde aynıdır.
Başlamadan önce şunların hazır olması gerekiyor:
- Çalışan bir Dovecot kurulumu (en az IMAP ve Submission destekli)
- Erişilebilir bir Keycloak (veya başka OAuth2/OIDC) sunucusu
- Keycloak’ta bir realm ve bu realm altında tanımlı bir client
dovecot-auth-oauth2paketinin kurulu olması
Paketin kurulu olup olmadığını kontrol edelim:
dpkg -l | grep dovecot
dovecot-core --version
# Keycloak introspection için gerekli modülün varlığını kontrol et
ls /usr/lib/dovecot/auth/ | grep oauth
Eğer dovecot-auth-oauth2 paketi kurulu değilse:
apt update
apt install dovecot-auth-oauth2
# Paketin getirdiği örnek konfigürasyona bakalım
ls /usr/share/doc/dovecot-auth-oauth2/
Keycloak Tarafında Yapılandırma
Dovecot tarafına geçmeden önce Keycloak’ta birkaç şeyi doğru ayarlamak gerekiyor. Keycloak admin paneline giriş yapıp mail servisine özel bir client oluşturacağız.
Client oluşturma adımları:
- Realm seçin (production realm’ınız)
- Clients > Create client
- Client ID:
dovecot-imap - Client authentication: ON (confidential client)
- Service accounts roles: ON
Client oluşturduktan sonra Credentials sekmesinden client secret’ı not alın. Bu secret Dovecot’un introspection isteği yaparken kullanacağı değer.
Keycloak’ın token introspection endpoint’i şu formatta olur:
https://keycloak.example.com/realms/{realm-adı}/protocol/openid-connect/token/introspect
Bu endpoint’i curl ile test edelim. Önce bir test token alalım:
# Test amaçlı token alma (gerçek kullanıcı ile)
TOKEN=$(curl -s -X POST
"https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token"
-H "Content-Type: application/x-www-form-urlencoded"
-d "client_id=dovecot-imap"
-d "client_secret=YOUR_CLIENT_SECRET"
-d "[email protected]"
-d "password=testpassword"
-d "grant_type=password" | jq -r '.access_token')
echo "Token: ${TOKEN:0:50}..."
# Token introspection testi
curl -s -X POST
"https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token/introspect"
-H "Content-Type: application/x-www-form-urlencoded"
-d "client_id=dovecot-imap"
-d "client_secret=YOUR_CLIENT_SECRET"
-d "token=$TOKEN" | jq .
Başarılı bir introspection yanıtı şöyle görünür:
{
"active": true,
"sub": "user-uuid-here",
"email": "[email protected]",
"preferred_username": "testuser",
"email_verified": true
}
active: true değerini görüyorsanız Keycloak tarafı hazır demektir.
Dovecot OAuth2 Yapılandırması
Dovecot’ta OAuth2 desteği birkaç farklı dosyaya yayılmış yapılandırma gerektirir. Sistematik gidelim.
Temel auth-oauth2 Tanımı
İlk olarak OAuth2 passdb’yi tanımlayan dosyayı oluşturalım:
cat > /etc/dovecot/conf.d/auth-oauth2.conf.ext << 'EOF'
passdb {
driver = oauth2
mechanisms = oauthbearer xoauth2
args = /etc/dovecot/dovecot-oauth2.conf.ext
}
# OAuth2 ile giriş yapan kullanıcılar için userdb
# Kullanıcı dizinleri ve UID/GID bilgileri için static veya passwd kullanılabilir
userdb {
driver = static
args = uid=vmail gid=vmail home=/var/mail/vhosts/%d/%n
}
EOF
Dovecot OAuth2 Konfigürasyon Dosyası
Asıl OAuth2 parametrelerini içeren dosyayı oluşturalım:
cat > /etc/dovecot/dovecot-oauth2.conf.ext << 'EOF'
# Introspection endpoint
introspect_url = https://keycloak.example.com/realms/myrealm/protocol/openid-connect/token/introspect
# Client kimlik bilgileri (HTTP Basic Auth olarak gönderilir)
client_id = dovecot-imap
client_secret = YOUR_CLIENT_SECRET_HERE
# Introspection yöntemi: auth için HTTP Basic Auth kullan
introspection_mode = auth
# Token geçerliliği için kontrol edilecek claim
# active claim'i true olmalı
active_attribute = active
active_value = true
# Kullanıcı adını hangi claim'den alacağız
username_attribute = email
# Token'ın scope kontrolü (opsiyonel ama önerilen)
# scope_attribute = scope
# valid_scope = imap
# Debug için (production'da kapat)
# debug = yes
# TLS doğrulama
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
EOF
# Dosya izinlerini kısıtla, client_secret açıkta kalmasın
chmod 600 /etc/dovecot/dovecot-oauth2.conf.ext
chown root:dovecot /etc/dovecot/dovecot-oauth2.conf.ext
Auth Servisi Yapılandırması
/etc/dovecot/conf.d/10-auth.conf dosyasını düzenleyelim:
# Mevcut auth mekanizmalarına ek olarak oauth mekanizmalarını ekle
# 10-auth.conf içinde ilgili satırı bul ve düzenle
grep -n "auth_mechanisms" /etc/dovecot/conf.d/10-auth.conf
# Dosyayı düzenle
sed -i 's/^auth_mechanisms = .*/auth_mechanisms = plain login oauthbearer xoauth2/'
/etc/dovecot/conf.d/10-auth.conf
# OAuth2 include'unu ekle (dosyanın sonuna)
echo '!include auth-oauth2.conf.ext' >> /etc/dovecot/conf.d/10-auth.conf
# Sonucu kontrol et
grep -E "auth_mechanisms|oauth" /etc/dovecot/conf.d/10-auth.conf
SSL/TLS Yapılandırması
OAuth2 ile IMAP çalışabilmesi için SSL zorunlu olmalıdır. Token’lar şifreli kanal üzerinden gönderilmelidir:
# 10-ssl.conf kontrolü
cat /etc/dovecot/conf.d/10-ssl.conf | grep -E "ssl|cert|key"
# SSL zorunlu yapılmalı
cat >> /etc/dovecot/conf.d/10-ssl.conf << 'EOF'
# OAuth2 için SSL zorunlu
ssl = required
ssl_cert = </etc/letsencrypt/live/mail.example.com/fullchain.pem
ssl_key = </etc/letsencrypt/live/mail.example.com/privkey.pem
ssl_min_protocol = TLSv1.2
EOF
Yapılandırmayı Test Etme
Yapılandırmayı uygulamadan önce sözdizimi kontrolü yapalım:
# Dovecot konfigürasyon kontrolü
doveconf -n 2>&1 | head -50
# Hata yoksa servisi yeniden başlat
systemctl restart dovecot
systemctl status dovecot
# Auth servisinin çalıştığını doğrula
dovecot --version
doveadm auth test [email protected]
Şimdi gerçek bir OAuth2 token ile IMAP bağlantısını test edelim:
#!/bin/bash
# oauth2_imap_test.sh - OAuth2 IMAP bağlantı test scripti
KEYCLOAK_URL="https://keycloak.example.com/realms/myrealm"
CLIENT_ID="dovecot-imap"
CLIENT_SECRET="YOUR_CLIENT_SECRET"
USERNAME="[email protected]"
PASSWORD="testpassword"
IMAP_HOST="mail.example.com"
IMAP_PORT="993"
echo "=== OAuth2 Token Alınıyor ==="
RESPONSE=$(curl -s -X POST
"${KEYCLOAK_URL}/protocol/openid-connect/token"
-H "Content-Type: application/x-www-form-urlencoded"
-d "client_id=${CLIENT_ID}"
-d "client_secret=${CLIENT_SECRET}"
-d "username=${USERNAME}"
-d "password=${PASSWORD}"
-d "grant_type=password"
-d "scope=openid email")
ACCESS_TOKEN=$(echo $RESPONSE | jq -r '.access_token')
if [ "$ACCESS_TOKEN" == "null" ] || [ -z "$ACCESS_TOKEN" ]; then
echo "HATA: Token alınamadı!"
echo $RESPONSE | jq .
exit 1
fi
echo "Token başarıyla alındı: ${ACCESS_TOKEN:0:30}..."
echo ""
echo "=== IMAP Bağlantısı Test Ediliyor ==="
# OAUTHBEARER base64 encode
OAUTHBEARER=$(printf "n,a=%s,01auth=Bearer %s0101"
"$USERNAME" "$ACCESS_TOKEN" | base64 -w 0)
# openssl s_client ile test
echo -e "A1 AUTHENTICATE OAUTHBEARER ${OAUTHBEARER}rnA2 LIST "" "*"rnA3 LOGOUTrn" |
openssl s_client -connect "${IMAP_HOST}:${IMAP_PORT}" -quiet 2>/dev/null
echo ""
echo "=== Test Tamamlandı ==="
chmod +x oauth2_imap_test.sh
./oauth2_imap_test.sh
Log İzleme ve Hata Ayıklama
Sorun yaşadığınızda Dovecot logları altın değerindedir. Birkaç önemli log konumu ve debug yöntemi:
# Dovecot auth loglarını canlı izle
tail -f /var/log/dovecot.log | grep -E "auth|oauth|Error|Warning"
# systemd journal kullanıyorsanız
journalctl -u dovecot -f --since "5 min ago"
# Debug modunu geçici olarak açmak için
# dovecot-oauth2.conf.ext içine debug = yes ekleyip
doveadm reload
# Belirli bir kullanıcı için auth trace
doveadm -D auth login [email protected]
# Auth worker süreçlerini listele
doveadm process status
Yaygın hata mesajları ve çözümleri:
oauth2: Introspection failed: HTTP request failed: Introspection URL’e erişilemiyor. Firewall kurallarını ve DNS çözümlemesini kontrol edin.oauth2: Token introspection: active field missing: Keycloak’ın döndürdüğü JSON’daactivealanı yok.active_attributeparametresini Keycloak’ın gerçekte döndürdüğü field adıyla eşleştirin.oauth2: Username field not found:username_attributeayarı yanlış. Keycloak’ın döndürdüğü token payload’ını inceleyerek doğru claim adını kullanın.SSL certificate verify failed: CA sertifikası bulunamıyor.tls_ca_cert_fileyolunu kontrol edin veya geçici olaraktls_allow_invalid_certs = yesekleyin (sadece debug için).
Token Yenileme ve Scope Yönetimi
Gerçek dünyada mail istemcileri uzun süreli oturumlar açar. OAuth2 access token’ların genellikle kısa ömrü (5-60 dakika) bu noktada sorun çıkarabilir. İki yaklaşım var:
Birinci yaklaşım: Mail istemcisinin refresh token kullanarak düzenli olarak yeni access token alması. Thunderbird ve modern mail istemcileri bunu destekler.
İkinci yaklaşım: Keycloak’ta dovecot-imap client için token lifetime’ı artırmak. Bu güvenlik açısından ideal değil ama kurumsal ağ içi kullanımda kabul edilebilir.
Scope bazlı erişim kontrolü için Keycloak’ta özel bir scope tanımlayalım. Keycloak admin panelinde:
- Client Scopes > Create client scope
- Name:
imap-access - Bu scope’u
dovecot-imapclient’a optional scope olarak atayın
Ardından Dovecot tarafında scope kontrolünü aktifleştirin:
# dovecot-oauth2.conf.ext dosyasına ekle
cat >> /etc/dovecot/dovecot-oauth2.conf.ext << 'EOF'
# Scope kontrolü - token'da imap-access scope'u olmalı
scope_attribute = scope
valid_scope = imap-access
EOF
doveadm reload
Azure AD Entegrasyonu (Alternatif Senaryo)
Keycloak yerine Azure AD kullanan ortamlar için yapılandırma farklılıklarını ele alalım. Microsoft’un OAuth2 introspection implementasyonu standart RFC 7662’den biraz sapıyor; bu yüzden userinfo endpoint kullanımı daha yaygın tercih.
cat > /etc/dovecot/dovecot-oauth2-azure.conf.ext << 'EOF'
# Azure AD için introspection yerine tokeninfo endpoint
introspect_url = https://graph.microsoft.com/oidc/userinfo
# Azure AD token'ları için tokeninfo modunu kullan
introspection_mode = get
# Authorization header olarak token gönder
# (Bearer token ile GET isteği)
use_grant_password = no
# Azure AD'nin döndürdüğü claim yapısı
username_attribute = preferred_username
active_attribute = sub
# active_value boş bırakılırsa field'ın varlığı yeterli sayılır
# Azure AD tenant'ınızın CA zinciri
tls_ca_cert_file = /etc/ssl/certs/ca-certificates.crt
EOF
Azure AD senaryosunda client_id ve client_secret yerine doğrudan token doğrulama yapıldığından, mail istemcisinin Microsoft kimlik doğrulama akışından geçip token alması ve bunu IMAP’a sunması gerekir. Bu konuyu ilerleyen bir yazıda MSAL entegrasyonu olarak ele alacağım.
Monitoring ve Güvenlik Önlemleri
OAuth2 entegrasyonunu production’a almadan önce birkaç kritik noktaya dikkat edin.
Fail2ban entegrasyonu: Token bazlı brute force denemelerini engellemek için Dovecot log formatına uygun bir Fail2ban filtresi ekleyin:
cat > /etc/fail2ban/filter.d/dovecot-oauth2.conf << 'EOF'
[Definition]
failregex = auth failed.*user=<.*@.*>.*rip=<HOST>
Aborted login.*user=<.*@.*>.*rip=<HOST>
oauth2.*authentication failed.*rip=<HOST>
ignoreregex =
EOF
cat > /etc/fail2ban/jail.d/dovecot-oauth2.conf << 'EOF'
[dovecot-oauth2]
enabled = true
port = imaps,pop3s,submission
filter = dovecot-oauth2
logpath = /var/log/dovecot.log
maxretry = 5
bantime = 3600
findtime = 600
EOF
systemctl restart fail2ban
fail2ban-client status dovecot-oauth2
Rate limiting: Dovecot’ta introspection isteklerini sınırlayarak Keycloak sunucusunu koruyun:
# 10-master.conf veya ilgili servis tanımına ekle
service auth {
client_limit = 1000
process_limit = 16
}
Secret rotation: client_secret değerini düzenli döndürmek için bir script:
#!/bin/bash
# rotate_oauth2_secret.sh
# Keycloak API üzerinden yeni secret oluştur ve Dovecot'u güncelle
KEYCLOAK_ADMIN_TOKEN=$(curl -s -X POST
"https://keycloak.example.com/realms/master/protocol/openid-connect/token"
-d "client_id=admin-cli"
-d "username=admin"
-d "password=${KEYCLOAK_ADMIN_PASS}"
-d "grant_type=password" | jq -r '.access_token')
NEW_SECRET=$(curl -s -X POST
"https://keycloak.example.com/admin/realms/myrealm/clients/${CLIENT_UUID}/client-secret"
-H "Authorization: Bearer ${KEYCLOAK_ADMIN_TOKEN}" | jq -r '.value')
# Dovecot konfigürasyonunu güncelle
sed -i "s/^client_secret = .*/client_secret = ${NEW_SECRET}/"
/etc/dovecot/dovecot-oauth2.conf.ext
# Dovecot'u yeniden yükle (servis kesintisi olmadan)
doveadm reload
echo "Secret rotation tamamlandı: $(date)"
Sonuç
Dovecot ile OAuth2 entegrasyonu ilk bakışta karmaşık görünse de adımları doğru takip ettiğinizde oldukça temiz bir kimlik yönetimi altyapısı ortaya çıkıyor. Kullanıcı parolalarını artık Dovecot’a özgü bir veritabanında tutmak yerine merkezi kimlik sağlayıcınızın kontrolüne bırakabiliyorsunuz. Bu yaklaşım özellikle büyük organizasyonlarda, MFA zorunluluğu olan ortamlarda ve kullanıcı hesabı kapandığında mail erişiminin anında kesilmesi gereken senaryolarda ciddi operasyonel kolaylık sağlıyor.
Dikkat etmeniz gereken kritik noktalar şunlar: Introspection URL’nin yüksek erişilebilirlikte olması (Keycloak HA cluster önerilen), token lifetime yönetimi ve client_secret güvenliği. Bu üç konuyu düzgün ele aldığınızda, klasik parola bazlı kimlik doğrulamaya kıyasla hem daha güvenli hem de daha yönetilebilir bir mail altyapısına kavuşursunuz.
Bir sonraki adım olarak Dovecot’un Sieve scriptleri ile OAuth2 kullanıcı claim’lerinden otomatik filtreleme kuralları üretmeyi veya JMAP protokolü üzerinden aynı token’ı kullanmayı inceleyebilirsiniz. Mail altyapısı modern kimlik sistemleriyle ne kadar entegre olursa, yönetim yükü o kadar azalıyor.