Caddy ile Basic Auth ve Forward Auth Yapılandırması

Web uygulamalarını dış dünyaya açarken güvenlik her zaman birinci öncelik olmalı. Caddy, modern ve sade yapısıyla bu konuda oldukça güçlü araçlar sunuyor. Bu yazıda Caddy’nin yerleşik Basic Auth mekanizmasını ve daha gelişmiş senaryolar için kullanılan Forward Auth yöntemini derinlemesine inceleyeceğiz. Homelab’ından kurumsal ortama kadar her ölçekte işe yarayan bu bilgileri gerçek dünya senaryolarıyla pekiştireceğiz.

Temel Kavramlar

Başlamadan önce iki kavramı netleştirelim.

Basic Auth, HTTP protokolünün standart bir parçasıdır. Tarayıcı, korunan bir kaynağa erişmek istediğinde sunucu 401 döner ve tarayıcı kullanıcıya bir kullanıcı adı/şifre kutusu gösterir. Bu bilgiler Base64 ile kodlanarak her istekte Authorization başlığında taşınır. Basit ama etkilidir.

Forward Auth ise daha sofistike bir yaklaşım. Caddy, bir isteği backend’e iletmeden önce harici bir kimlik doğrulama servisine sorar: “Bu kullanıcı geçebilir mi?” Eğer servis onay verirse istek hedefe ulaşır, vermezse kullanıcı login sayfasına yönlendirilir. Authelia, Authentik, Traefik Forward Auth gibi araçlar bu modelde çalışır.

Caddy Kurulumu ve Hazırlık

Eğer henüz Caddy kurulu değilse hızlıca başlayalım. Ubuntu/Debian için:

sudo apt install -y debian-keyring debian-archive-keyring apt-transport-https curl
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/gpg.key' | sudo gpg --dearmor -o /usr/share/keyrings/caddy-stable-archive-keyring.gpg
curl -1sLf 'https://dl.cloudsmith.io/public/caddy/stable/debian.deb.txt' | sudo tee /etc/apt/sources.list.d/caddy-stable.list
sudo apt update
sudo apt install caddy

Caddy’nin düzgün çalıştığını doğrulayalım:

caddy version
sudo systemctl status caddy

Caddyfile genellikle /etc/caddy/Caddyfile konumunda bulunur. Yapılandırma değişikliklerinden sonra:

sudo caddy validate --config /etc/caddy/Caddyfile
sudo systemctl reload caddy

reload komutunu unutma, restart yerine reload kullanmak zero-downtime sağlar.

Basic Auth Yapılandırması

Şifre Hash’i Oluşturma

Caddy, şifreleri düz metin olarak saklamaz. bcrypt hash kullanır. Hash oluşturmak için:

caddy hash-password --plaintext "guclu_sifreniz"

Çıktı şuna benzer bir şey olacak:

$2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK

Bu hash’i Caddyfile’da kullanacaksın. Şifreyi terminal geçmişinde bırakmak istemiyorsan interaktif modu kullan:

caddy hash-password

Komutu çalıştırınca şifreyi girmen istenir, hiçbir şey terminale yazılmaz.

Basit Bir Senaryo: Dahili Araçları Koruma

Diyelim ki bir Grafana instance’ın var ve bunu internete açmak zorunda kaldın ama Grafana’nın kendi auth’u dışında bir katman daha eklemek istiyorsun:

# /etc/caddy/Caddyfile

grafana.sirketin.com {
    basicauth {
        # kullanici_adi hashlenmis_sifre
        admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
        operator $2a$14$hDiXBMHkVyL3CxPP7Ro8Y.yRQdFGlZP8N4SvxT1mEd9.7UVz3Bxe6
    }

    reverse_proxy localhost:3000
}

Bu kadar. Caddy artık Grafana’ya gelen her isteği önce Basic Auth ile kontrol edecek.

Sadece Belirli Yolları Koruma

Bazen tüm siteyi değil, sadece admin panelini korumak istersin. route bloğu burada devreye girer:

# /etc/caddy/Caddyfile

uygulama.sirketin.com {
    # /admin altindaki her sey korunuyor
    route /admin/* {
        basicauth {
            admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
        }
        reverse_proxy localhost:8080
    }

    # Geri kalan her sey serbest
    route {
        reverse_proxy localhost:8080
    }
}

Birden Fazla Site, Merkezi Kullanıcı Yönetimi

Birden fazla subdomain varsa her birine ayrı ayrı kullanıcı eklemek yerine snippet kullanabilirsin:

# /etc/caddy/Caddyfile

(ortak_auth) {
    basicauth {
        admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
        mehmet $2a$14$AnotherHashForMehmetXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
        ayse $2a$14$AnotherHashForAyseXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
    }
}

grafana.sirketin.com {
    import ortak_auth
    reverse_proxy localhost:3000
}

prometheus.sirketin.com {
    import ortak_auth
    reverse_proxy localhost:9090
}

kibana.sirketin.com {
    import ortak_auth
    reverse_proxy localhost:5601
}

Bu yaklaşım, kullanıcı ekleme veya silme işlemlerini tek bir yerden yapmanı sağlar. Snippet’leri ayrı bir dosyaya taşıyıp import /etc/caddy/auth_users.conf şeklinde de kullanabilirsin.

Forward Auth ile Gelişmiş Kimlik Doğrulama

Basic Auth’un ciddi bir kısıtlaması var: Her uygulama için ayrı kullanıcı yönetimi, 2FA desteği yok, merkezi oturum yönetimi yok. Birden fazla uygulaması olan bir ortamda bu hızla kaosa dönüşür. Forward Auth burada kurtarıcı olur.

Forward Auth Nasıl Çalışır?

Akış şöyle işler:

  • Kullanıcı uygulama.sirketin.com adresine istek gönderir
  • Caddy bu isteği direkt backend’e iletmez, önce auth servisine (örneğin Authelia) bir sub-request gönderir
  • Auth servisi kullanıcının oturumunu kontrol eder
  • Oturum geçerliyse 200 döner ve Caddy isteği backend’e iletir
  • Oturum geçersizse 401/302 döner ve kullanıcı login sayfasına yönlendirilir

Authelia ile Forward Auth Kurulumu

Authelia, self-hosted kimlik doğrulama için popüler bir seçenek. Docker Compose ile hızlıca ayağa kaldıralım:

# docker-compose.yml

version: '3.8'

services:
  authelia:
    image: authelia/authelia:latest
    container_name: authelia
    volumes:
      - ./authelia/config:/config
    ports:
      - "9091:9091"
    environment:
      - TZ=Europe/Istanbul
    restart: unless-stopped

  redis:
    image: redis:alpine
    container_name: authelia_redis
    volumes:
      - ./authelia/redis:/data
    restart: unless-stopped

Authelia için temel yapılandırma (./authelia/config/configuration.yml):

# Bu dosyayi tam olarak kopyalayin ve ihtiyaclariniza gore duzenleyin
server:
  host: 0.0.0.0
  port: 9091

log:
  level: info

jwt_secret: cok_guclu_bir_jwt_secret_buraya_yazin

default_redirection_url: https://auth.sirketin.com

authentication_backend:
  file:
    path: /config/users_database.yml

access_control:
  default_policy: deny
  rules:
    - domain: "*.sirketin.com"
      policy: two_factor

session:
  name: authelia_session
  secret: baska_bir_guclu_secret
  expiration: 3600
  inactivity: 300
  domain: sirketin.com
  redis:
    host: redis
    port: 6379

storage:
  local:
    path: /config/db.sqlite3

notifier:
  filesystem:
    filename: /config/notification.txt

Caddy’de Forward Auth Yapılandırması

Authelia çalışır duruma geldikten sonra Caddy tarafını yapılandıralım:

# /etc/caddy/Caddyfile

# Auth servisi kendisi
auth.sirketin.com {
    reverse_proxy localhost:9091
}

# Korunan uygulama - Authelia ile
grafana.sirketin.com {
    forward_auth localhost:9091 {
        uri /api/verify?rd=https://auth.sirketin.com
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    }

    reverse_proxy localhost:3000
}

# Daha az kritik uygulama - sadece tek faktor
wiki.sirketin.com {
    forward_auth localhost:9091 {
        uri /api/verify?rd=https://auth.sirketin.com
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
    }

    reverse_proxy localhost:3001
}

copy_headers direktifi önemli. Authelia doğrulamadan geçen kullanıcının bilgilerini bu header’lara yazar, backend uygulamalar bu bilgileri kullanabilir. Örneğin Grafana, Remote-User header’ından kullanıcı adını alarak otomatik login yapabilir.

Authentik ile Forward Auth

Authentik (Authentik), Authelia’ya göre daha kapsamlı bir kimlik sağlayıcı. OAuth, SAML, LDAP desteği var. Forward auth yapılandırması biraz farklı:

# /etc/caddy/Caddyfile

# Authentik outpost endpoint'i
authentik.sirketin.com {
    reverse_proxy localhost:9000
}

uygulama.sirketin.com {
    forward_auth authentik.sirketin.com {
        uri /outpost.goauthentik.io/auth/caddy
        
        # Authentik'in set ettigi header'lari kopyala
        copy_headers X-Authentik-Username X-Authentik-Groups X-Authentik-Email X-Authentik-Uid

        # Authentik'in kendi endpointlerine forward auth uygulanmamali
        @skip not path /outpost.goauthentik.io/*
        handle @skip {
            forward_auth authentik.sirketin.com {
                uri /outpost.goauthentik.io/auth/caddy
            }
        }
    }

    reverse_proxy localhost:8080
}

Gerçek Dünya Senaryo: Homelab Paneli

Tipik bir homelab senaryosunu ele alalım. Portainer, Grafana, Nextcloud ve bir wiki var. Nextcloud kendi auth’unu yönetiyor, diğerleri için merkezi bir çözüm istiyoruz.

# /etc/caddy/Caddyfile

# Snippet: Forward auth helper
(authelia_forward) {
    forward_auth 127.0.0.1:9091 {
        uri /api/verify?rd=https://auth.homelab.local
        copy_headers Remote-User Remote-Groups Remote-Name Remote-Email
        trusted_proxies private_ranges
    }
}

# Auth portal
auth.homelab.local {
    reverse_proxy 127.0.0.1:9091
    tls internal
}

# Portainer - admin icin 2FA zorunlu
portainer.homelab.local {
    import authelia_forward
    reverse_proxy 127.0.0.1:9000
    tls internal
}

# Grafana - dashboards
grafana.homelab.local {
    import authelia_forward
    
    # Grafana'ya kullanici bilgisini ilet
    reverse_proxy 127.0.0.1:3000 {
        header_up X-WEBAUTH-USER {http.request.header.Remote-User}
    }
    
    tls internal
}

# Nextcloud - kendi auth'unu kullaniyor
nextcloud.homelab.local {
    reverse_proxy 127.0.0.1:8080 {
        header_up Host {upstream_hostport}
    }
    tls internal
}

# Wiki.js
wiki.homelab.local {
    import authelia_forward
    reverse_proxy 127.0.0.1:3001
    tls internal
}

tls internal direktifi Caddy’nin kendi CA’sı ile self-signed sertifika oluşturmasını sağlar. Yerel ağda kullanışlı.

Basic Auth ve Forward Auth’u Birlikte Kullanmak

Bazen her ikisini de birlikte kullanmak isteyebilirsin. Örneğin forward auth ile korunan bir API endpoint’ine programatik erişim için Basic Auth da desteklemek:

# /etc/caddy/Caddyfile

api.sirketin.com {
    # API client'lari icin Basic Auth
    @api_client {
        path /v1/*
        header Authorization "Basic *"
    }
    
    handle @api_client {
        basicauth {
            api_user $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
        }
        reverse_proxy localhost:8090
    }

    # Tarayici istekleri icin Forward Auth
    handle {
        forward_auth localhost:9091 {
            uri /api/verify?rd=https://auth.sirketin.com
        }
        reverse_proxy localhost:8090
    }
}

Güvenlik Notları ve Best Practices

Rate Limiting Eklemek

Basic Auth brute force saldırılarına karşı savunmasız olabilir. Caddy’nin rate_limit modülünü kullanmak için önce modülü içeren Caddy versiyonunu kullanman gerekiyor. Alternatif olarak Fail2ban ile birlikte kullanabilirsin:

# /etc/fail2ban/filter.d/caddy-auth.conf
[Definition]
failregex = ^.*"remote_addr":"<HOST>".*"status":401.*$
ignoreregex =

HTTPS Zorlamak

Caddy zaten HTTPS’i otomatik yönetir ama bir de HTTP’den redirect ekleyelim:

# /etc/caddy/Caddyfile

http://uygulama.sirketin.com {
    redir https://uygulama.sirketin.com{uri} permanent
}

uygulama.sirketin.com {
    basicauth {
        admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
    }
    reverse_proxy localhost:8080
}

Aslında Caddy HTTPS’e otomatik redirect yapar, bu bloğu eklemek daha çok explicit olmak için.

Güvenli Header’lar Eklemek

Auth ile birlikte güvenlik header’larını da eklemek iyi bir pratik:

(guvenli_headerlar) {
    header {
        Strict-Transport-Security "max-age=31536000; includeSubDomains; preload"
        X-Content-Type-Options "nosniff"
        X-Frame-Options "SAMEORIGIN"
        Referrer-Policy "strict-origin-when-cross-origin"
        -Server
    }
}

grafana.sirketin.com {
    import guvenli_headerlar
    
    forward_auth localhost:9091 {
        uri /api/verify?rd=https://auth.sirketin.com
    }
    
    reverse_proxy localhost:3000
}

IP Kısıtlaması ile Katmanlı Güvenlik

Sadece belirli IP aralıklarından erişime izin vermek istiyorsan:

portainer.sirketin.com {
    @yerel_ag {
        remote_ip 192.168.1.0/24 10.0.0.0/8
    }
    
    handle @yerel_ag {
        basicauth {
            admin $2a$14$Zkx19XLiW6VYouLHR5NmfOFU0z2GTNmpkT/5qqR7hx4IjWJPDhjvK
        }
        reverse_proxy localhost:9000
    }
    
    handle {
        respond "Erisim Engellendi" 403
    }
}

Hata Ayıklama

Forward auth çalışmıyorsa önce şunları kontrol et:

  • Auth servisinin çalıştığını doğrula: curl -I http://localhost:9091/api/verify
  • Caddy loglarına bak: journalctl -u caddy -f
  • Auth servisinin loglarına bak
  • Cookie domain ayarlarının doğru olduğundan emin ol (Authelia’da session.domain)
  • Sub-domain’lerin auth servisinin domain’iyle aynı üst domain’de olduğundan emin ol

Detaylı loglama için Caddyfile’a ekleyebilirsin:

{
    debug
    log {
        output file /var/log/caddy/access.log {
            roll_size 10mb
            roll_keep 5
        }
        format json
        level DEBUG
    }
}

grafana.sirketin.com {
    # ...
}

Global blok ({}) Caddyfile’ın en başında olmalı.

Sonuç

Caddy, Basic Auth ve Forward Auth konularında gerçekten sade ve güçlü bir çözüm sunuyor. Basic Auth, küçük ekipler veya dahili araçlar için hızlı ve yeterli bir koruma sağlarken, Forward Auth büyüyen ve olgunlaşan ortamlarda merkezi kimlik yönetiminin kapısını açıyor.

Hangi yöntemi seçeceğin ortamına bağlı: Birkaç dahili araç ve birkaç kullanıcı varsa Basic Auth yeterli ve fazlasıyla pratik. Düzinelerce uygulama, 2FA ihtiyacı ve merkezi kullanıcı yönetimi gerekiyorsa Authelia veya Authentik ile Forward Auth kaçınılmaz hale geliyor.

Şifre hash’lerini asla düz metin bırakma, her ortam için güçlü secret’lar kullan, logları düzenli izle ve mümkün olduğunca IP kısıtlamasıyla katmanlı güvenlik uygula. Caddy’nin temiz sözdizimi bu işleri yaparken seni gereksiz karmaşıklıktan koruyor, bunu bir avantaj olarak sonuna kadar kullan.

Yorum yapın