Web uygulamalarında kimlik doğrulamayı merkezi bir noktadan yönetmek, hem güvenlik hem de bakım kolaylığı açısından büyük avantaj sağlar. Nginx’in auth_request modülü tam da bu ihtiyacı karşılar: gelen her isteği kendi uygulamanıza yönlendirmeden önce harici bir servise sorarak “bu kullanıcı geçerli mi?” diye sormanızı sağlar. Mikroservis mimarilerinde, reverse proxy senaryolarında veya sadece basit bir token doğrulama katmanı eklemek istediğinizde bu modül inanılmaz derecede kullanışlı hale gelir.
auth_request Modülü Nedir ve Nasıl Çalışır?
auth_request modülü, Nginx’e gelen her HTTP isteğini önce belirlediğiniz bir endpoint’e alt istek (subrequest) olarak yönlendirir. Bu endpoint 2xx döndürürse asıl istek işleme devam eder, 401 veya 403 döndürürse Nginx isteği reddeder.
Akış şu şekilde ilerler:
- Kullanıcı
/api/usersendpoint’ine istek atar - Nginx bu isteği işlemeden önce
/authendpoint’ine bir subrequest gönderir /authservisi isteği değerlendirir ve 200 ya da 401 döndürür- 200 gelirse asıl istek backend’e iletilir, 401 gelirse kullanıcıya hata döner
Bu modül Nginx’in standart derleme paketlerinde genellikle hazır gelir. Kontrol etmek için:
nginx -V 2>&1 | grep -o with-http_auth_request_module
Eğer çıktı yoksa modülü derlemeli ya da nginx-extras paketini kurmalısınız:
# Ubuntu/Debian
apt install nginx-extras
# RHEL/CentOS - önce EPEL ekleyin
yum install nginx-mod-http-auth-request
Temel Konfigürasyon Yapısı
En basit haliyle auth_request konfigürasyonu şöyle görünür:
server {
listen 80;
server_name app.example.com;
# Auth endpoint tanımı
location /auth {
internal;
proxy_pass http://auth-service:8080/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
}
# Korunan alan
location /api/ {
auth_request /auth;
proxy_pass http://backend:3000;
}
# Public alan
location /public/ {
proxy_pass http://backend:3000;
}
}
Buradaki kritik nokta internal direktifidir. Bu sayede /auth endpoint’ine dışarıdan doğrudan istek atılamaz, yalnızca Nginx’in kendi iç mekanizması kullanabilir.
proxy_pass_request_body off direktifi ise auth servisinize gereksiz yük bindirmemek için request body’yi iletmez. Kimlik doğrulama için genellikle sadece header’lar yeterlidir.
Gerçek Dünya Senaryosu 1: JWT Token Doğrulama
Pek çok modern uygulamada kimlik doğrulama JWT (JSON Web Token) ile yapılır. Kullanıcı header’da Authorization: Bearer gönderir ve siz bunu doğrulamak istersiniz.
Önce basit bir Python tabanlı auth servisi yazalım (Flask ile):
# auth_service.py
from flask import Flask, request, jsonify
import jwt
import os
app = Flask(__name__)
SECRET_KEY = os.environ.get('JWT_SECRET', 'supersecretkey')
@app.route('/validate', methods=['GET'])
def validate():
auth_header = request.headers.get('Authorization', '')
if not auth_header.startswith('Bearer '):
return jsonify({'error': 'No token'}), 401
token = auth_header.split(' ')[1]
try:
payload = jwt.decode(token, SECRET_KEY, algorithms=['HS256'])
# Kullanıcı bilgilerini header'a ekle
response = app.make_response('', 200)
response.headers['X-User-ID'] = str(payload.get('user_id', ''))
response.headers['X-User-Role'] = payload.get('role', 'user')
return response
except jwt.ExpiredSignatureError:
return jsonify({'error': 'Token expired'}), 401
except jwt.InvalidTokenError:
return jsonify({'error': 'Invalid token'}), 401
if __name__ == '__main__':
app.run(host='0.0.0.0', port=8080)
Bu servisi Nginx ile entegre eden konfigürasyon:
server {
listen 443 ssl;
server_name api.example.com;
ssl_certificate /etc/nginx/ssl/cert.pem;
ssl_certificate_key /etc/nginx/ssl/key.pem;
# Auth subrequest endpoint
location = /auth/validate {
internal;
proxy_pass http://127.0.0.1:8080/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header X-Original-URI $request_uri;
proxy_set_header X-Original-Method $request_method;
proxy_set_header Authorization $http_authorization;
# Timeout değerlerini küçük tut, auth servisi hızlı yanıt vermeli
proxy_connect_timeout 5s;
proxy_read_timeout 5s;
}
# Auth servisinden dönen header'ları backend'e ilet
location /api/v1/ {
auth_request /auth/validate;
# Auth servisinin döndürdüğü header'ları değişkene al
auth_request_set $user_id $upstream_http_x_user_id;
auth_request_set $user_role $upstream_http_x_user_role;
# Bu değişkenleri backend'e ilet
proxy_set_header X-User-ID $user_id;
proxy_set_header X-User-Role $user_role;
proxy_pass http://backend-cluster;
}
# 401 durumunda JSON yanıt dön
error_page 401 = @unauthorized;
location @unauthorized {
default_type application/json;
return 401 '{"error": "Unauthorized", "message": "Gecerli bir token gerekli"}';
}
}
Burada auth_request_set direktifi çok değerli: auth servisinin döndürdüğü response header’larını Nginx değişkenlerine atar ve bunları backend’e iletmenizi sağlar. Böylece backend uygulamanız kim olduğunu bilir.
Gerçek Dünya Senaryosu 2: Cookie Tabanlı Session Doğrulama
Klasik web uygulamalarında session cookie’si kullanılır. Auth servisi bu cookie’yi veritabanında kontrol eder:
upstream auth_backend {
server 10.0.1.10:8080;
server 10.0.1.11:8080 backup;
keepalive 32;
}
upstream app_backend {
server 10.0.2.10:3000;
server 10.0.2.11:3000;
keepalive 64;
}
server {
listen 80;
server_name dashboard.example.com;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl http2;
server_name dashboard.example.com;
ssl_certificate /etc/ssl/certs/dashboard.pem;
ssl_certificate_key /etc/ssl/private/dashboard.key;
# Cookie tabanlı auth kontrolü
location = /_auth_check {
internal;
proxy_pass http://auth_backend/session/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Cookie $http_cookie;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Original-URI $request_uri;
}
# Login sayfası auth gerektirmez
location /login {
proxy_pass http://app_backend;
}
location /logout {
proxy_pass http://app_backend;
}
# Statik dosyalar için auth bypass
location ~* .(css|js|png|jpg|gif|ico|woff2?)$ {
expires 30d;
add_header Cache-Control "public, immutable";
root /var/www/dashboard/static;
}
# Ana uygulama, auth gerektirir
location / {
auth_request /_auth_check;
auth_request_set $auth_user $upstream_http_x_authenticated_user;
auth_request_set $auth_status $upstream_status;
proxy_set_header X-Authenticated-User $auth_user;
proxy_pass http://app_backend;
# 401 alınırsa login'e yönlendir
error_page 401 = @login_redirect;
}
location @login_redirect {
return 302 /login?next=$request_uri;
}
}
Auth Request ile Rate Limiting Kombinasyonu
Sadece kimlik doğrulamak yetmez, bazen aynı kullanıcının çok fazla istek atmasını da engellemek gerekir. auth_request ile rate limiting’i birlikte kullanabilirsiniz:
http {
# Farklı limitler için map kullan
map $http_authorization $auth_zone {
default "anonymous";
~^Bearers+ "authenticated";
}
limit_req_zone $binary_remote_addr zone=anon_limit:10m rate=10r/m;
limit_req_zone $http_authorization zone=auth_limit:20m rate=100r/m;
limit_req_zone $binary_remote_addr zone=login_limit:10m rate=5r/m;
server {
listen 443 ssl;
server_name api.example.com;
location = /_internal_auth {
internal;
proxy_pass http://127.0.0.1:8080/check;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
proxy_set_header X-Forwarded-For $remote_addr;
}
# Login endpoint için agresif rate limit
location /auth/login {
limit_req zone=login_limit burst=3 nodelay;
limit_req_status 429;
proxy_pass http://auth_backend;
}
# API endpoint'leri
location /api/ {
auth_request /_internal_auth;
# Authenticated kullanıcılar için daha yüksek limit
limit_req zone=auth_limit burst=20 nodelay;
limit_req_status 429;
auth_request_set $user_id $upstream_http_x_user_id;
proxy_set_header X-User-ID $user_id;
proxy_pass http://app_backend;
}
error_page 429 = @rate_limited;
location @rate_limited {
default_type application/json;
add_header Retry-After 60;
return 429 '{"error": "Too Many Requests", "retry_after": 60}';
}
}
}
Role Tabanlı Erişim Kontrolü (RBAC)
Farklı URL’ler için farklı roller gerektirebilirsiniz. Nginx değişkenleri ve if direktifi ile bunu halledebilirsiniz:
server {
listen 443 ssl;
server_name admin.example.com;
location = /_check_admin {
internal;
proxy_pass http://auth-service:8080/check-role?required_role=admin;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
}
location = /_check_editor {
internal;
proxy_pass http://auth-service:8080/check-role?required_role=editor;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
}
# Sadece admin erişebilir
location /admin/settings {
auth_request /_check_admin;
proxy_pass http://admin-backend:4000;
}
# Editor ve üstü erişebilir
location /admin/content {
auth_request /_check_editor;
proxy_pass http://admin-backend:4000;
}
# Genel auth yeterli
location /admin/dashboard {
auth_request /_check_editor;
proxy_pass http://admin-backend:4000;
}
error_page 401 = @unauthorized;
error_page 403 = @forbidden;
location @unauthorized {
default_type application/json;
return 401 '{"code": 401, "message": "Kimlik dogrulama gerekli"}';
}
location @forbidden {
default_type application/json;
return 403 '{"code": 403, "message": "Bu kaynaga erisim izniniz yok"}';
}
}
Auth Request ile Caching: Performansı Artırma
Her istekte auth servisine gitmek gecikmeye yol açar. Nginx’in proxy_cache direktifini kullanarak auth yanıtlarını kısa süreliğine önbelleğe alabilirsiniz:
http {
# Auth yanıtları için ayrı cache zone
proxy_cache_path /var/cache/nginx/auth_cache
levels=1:2
keys_zone=auth_cache:10m
max_size=100m
inactive=5m;
server {
listen 443 ssl;
server_name app.example.com;
location = /_auth {
internal;
proxy_pass http://auth-service:8080/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
# Cache key: token'a göre cache'le
proxy_cache auth_cache;
proxy_cache_key "$http_authorization";
proxy_cache_valid 200 30s; # Başarılı auth'u 30 saniye cache'le
proxy_cache_valid 401 5s; # Hatalı auth'u 5 saniye cache'le
proxy_cache_methods GET HEAD;
# Stale cache kullan, arka planda yenile
proxy_cache_use_stale updating;
proxy_cache_background_update on;
# Cache durumunu logla
add_header X-Cache-Status $upstream_cache_status;
}
location /api/ {
auth_request /_auth;
auth_request_set $user_id $upstream_http_x_user_id;
proxy_set_header X-User-ID $user_id;
proxy_pass http://backend:3000;
}
}
}
Dikkat: Token süre dolumu durumunda cache’de geçerli bir yanıt olabilir. Bu nedenle cache süresini token’ın geçerlilik süresiyle uyumlu tutun. 30 saniyelik cache genellikle makul bir denge noktasıdır.
Hata Ayıklama ve Log Yönetimi
Auth request sorunlarını debug etmek bazen sinir bozucu olabilir. Ayrıntılı loglama kurarak süreci kolaylaştırabilirsiniz:
http {
# Auth durumunu içeren özel log formatı
log_format auth_debug '$remote_addr - $remote_user [$time_local] '
'"$request" $status $body_bytes_sent '
'auth_status=$upstream_status '
'user_id="$upstream_http_x_user_id" '
'user_role="$upstream_http_x_user_role" '
'cache="$upstream_cache_status" '
'request_time=$request_time '
'upstream_time=$upstream_response_time';
server {
access_log /var/log/nginx/app_access.log auth_debug;
error_log /var/log/nginx/app_error.log warn;
location = /_auth {
internal;
proxy_pass http://auth-service:8080/validate;
proxy_pass_request_body off;
proxy_set_header Content-Length "";
proxy_set_header Authorization $http_authorization;
# Auth servisine giden istekleri ayrı logla
access_log /var/log/nginx/auth_requests.log auth_debug;
}
location /api/ {
auth_request /_auth;
auth_request_set $user_id $upstream_http_x_user_id;
auth_request_set $user_role $upstream_http_x_user_role;
proxy_set_header X-User-ID $user_id;
proxy_set_header X-User-Role $user_role;
proxy_pass http://backend:3000;
}
}
}
Test sırasında curl ile manuel debug yapabilirsiniz:
# Token ile istek at ve tüm header'ları gör
curl -v -H "Authorization: Bearer eyJhbGc..." https://api.example.com/api/users
# Auth servisini doğrudan test et
curl -v -H "Authorization: Bearer eyJhbGc..."
-H "X-Original-URI: /api/users"
http://localhost:8080/validate
# Nginx error log'u gerçek zamanlı takip et
tail -f /var/log/nginx/app_error.log
# Auth isteklerini izle
tail -f /var/log/nginx/auth_requests.log | grep -v "200"
Yaygın Hatalar ve Çözümleri
auth_request modülü yüklü değil: Nginx binary’sini --with-http_auth_request_module ile derlemeniz ya da distro’nuzun extras paketini kurmanız gerekir.
Sonsuz döngü (infinite loop): Auth endpoint’inizin kendisi auth_request içeriyorsa sonsuz döngüye girersiniz. Her zaman internal direktifini kullanın ve auth location’ın kendisinde başka bir auth_request olmadığından emin olun.
Request body kayboluyor: Auth subrequest sırasında proxy_pass_request_body off kullandığınız için backend POST isteklerinde body kaybolabilir. Bu ayar sadece auth location içinde olmalı, asıl proxy location’da olmamalı.
Auth servisinden header gelmiyor: auth_request_set direktifinin doğru değişken adını kullandığınızdan emin olun. Auth servisinden gelen header X-User-ID ise Nginx bunu $upstream_http_x_user_id olarak tanır (küçük harf ve tire yerine alt çizgi).
Cache sorunları: Token yenileme (refresh) sonrasında eski cache yanıtı döngüde kalabilir. Kritik güvenlik işlemlerinde cache’i devre dışı bırakın veya çok kısa tutun.
# Nginx konfigürasyonunu test et
nginx -t
# Modül listesini kontrol et
nginx -V 2>&1 | tr -- - 'n' | grep module
# Cache dizininin izinlerini kontrol et
ls -la /var/cache/nginx/
chown -R nginx:nginx /var/cache/nginx/
Güvenlik Önerileri
Kimlik doğrulama katmanı yanlış yapılandırılırsa tüm güvenlik önlemleriniz işe yaramaz hale gelir. Dikkat etmeniz gereken noktalar:
internaldirektifini unutmayın: Auth endpoint’i dışarıdan erişilebilir olmamalı.- HTTPS kullanın: Hem frontend hem de auth servisi arasındaki iletişim şifreli olmalı, iç ağda dahi olsa.
- Timeout değerlerini küçük tutun: Auth servisi yanıt vermezse Nginx’in beklemesini istemezsiniz. 5 saniye genellikle yeterlidir.
- Auth servisini ayrı bir upstream grubunda tutun: Load balancer arkasına alın, tek nokta arıza olmasın.
- Header injection’a dikkat edin: Kullanıcıdan gelen
X-User-IDgibi header’ları backend’e iletmeden önce temizleyin. - Log’ları token değerlerine göre maskeleyin: Token’lar log dosyalarına düşmemeli.
# Auth servisinin sadece localhost'tan erişilebilir olduğunu doğrula
ss -tlnp | grep 8080
# Dışarıdan auth endpoint'ine erişim denemesi (403 veya bağlantı reddi gelmeli)
curl -I https://api.example.com/_auth
Sonuç
Nginx auth_request modülü, merkezi kimlik doğrulama mimarisi kurmak için güçlü ve esnek bir araçtır. Mikroservis ortamlarında her servis kendi auth mantığını tekrar yazmak yerine tek bir auth servisi üzerinden doğrulama yapabilir. JWT, cookie, API key veya özel bir kimlik doğrulama şemasını backend uygulamalarınızı değiştirmeden Nginx seviyesinde uygulayabilirsiniz.
Performans açısından auth servisini hızlı ve hafif tutmak kritiktir, çünkü her istek bu servisten geçer. Redis gibi bir in-memory store ile session ve token bilgilerini önbellekleyin, Nginx tarafında da kısa süreli cache kullanın. Yüksek trafikli uygulamalarda auth servisini yatay olarak ölçeklendirin ve upstream bloğunda birden fazla instance tanımlayın.
Son olarak, auth_request‘i tek başına bir güvenlik kalkanı olarak görmemek gerekir. Rate limiting, TLS zorunluluğu, güvenli header politikaları ve düzenli güvenlik denetimleriyle birlikte kullanıldığında gerçek anlamda sağlam bir güvenlik katmanı oluşturur.