Ollama Güvenliği: API Erişimini Kısıtlama ve Şifreleme

Yerel yapay zeka modellerini çalıştırmak harika bir özgürlük hissi veriyor; bulut servislerine bağımlı olmadan, verileriniz elinizde kalarak LLM kullanabiliyorsunuz. Ama “yerel” kelimesi sizi yanıltmasın. Ollama varsayılan kurulumda oldukça açık bir şekilde geliyor ve yanlış yapılandırılmış bir kurulum, ağınızdaki herkesin modellerinize erişmesine, hatta sunucunuzu kötüye kullanmasına neden olabilir. Bu yazıda Ollama’yı production ortamına yakın bir güvenlik seviyesine taşımak için yapmanız gerekenleri, gerçek senaryolar üzerinden anlatacağım.

Ollama’nın Varsayılan Güvenlik Durumu

Ollama’yı curl -fsSL https://ollama.com/install.sh | sh komutuyla kurduğunuzda, servis 127.0.0.1:11434 adresinde dinlemeye başlar. Localhost’a bağlı olduğu için ilk bakışta güvenli görünür. Ancak pratikte şu sorunlarla karşılaşırsınız:

  • Localhost’ta çalışan başka bir servis veya container Ollama API’sine kısıtlamasız erişebilir
  • Eğer uzak erişim için OLLAMA_HOST=0.0.0.0 ayarlarsanız tüm ağa açılır
  • Varsayılan kurulumda kimlik doğrulama yoktur
  • HTTPS desteği kutuda gelmez
  • Rate limiting mekanizması yoktur

Özellikle şunu hayal edin: Bir geliştirme sunucusunda Ollama kuruyorsunuz, uygulamanızın erişmesi için 0.0.0.0 yapıyorsunuz ve firewall kuralını geçici olarak açıyorsunuz. “Geçici” dediğiniz şey kalıcı oluyor, ve birkaç hafta sonra sunucunuz başkalarının model inference işlemleri için kullanılıyor. GPU’nuz yanıyor, bant genişliğiniz tükeniyor.

Mevcut durumu kontrol etmekle başlayalım:

# Ollama'nın hangi adreste dinlediğini kontrol et
ss -tlnp | grep 11434

# Servis durumunu ve environment değişkenlerini gör
systemctl status ollama
systemctl cat ollama

# Mevcut API erişimini test et
curl http://localhost:11434/api/tags
curl http://localhost:11434/api/version

Ağ Erişimini Kısıtlamak: İlk Savunma Hattı

Systemd Servis Yapılandırması

Ollama systemd ile çalışıyorsa, servis dosyasını override ederek network binding’i kontrol altına alabilirsiniz:

# Override dizini oluştur
sudo mkdir -p /etc/systemd/system/ollama.service.d/

# Override dosyasını oluştur
sudo tee /etc/systemd/system/ollama.service.d/override.conf << 'EOF'
[Service]
Environment="OLLAMA_HOST=127.0.0.1:11434"
Environment="OLLAMA_ORIGINS=http://localhost:3000,http://127.0.0.1:3000"
Environment="OLLAMA_MAX_LOADED_MODELS=2"
Environment="OLLAMA_NUM_PARALLEL=4"
EOF

# Systemd'yi yeniden yükle ve servisi yeniden başlat
sudo systemctl daemon-reload
sudo systemctl restart ollama

# Değişikliklerin uygulandığını doğrula
systemctl show ollama --property=Environment

OLLAMA_ORIGINS değişkeni çok kritik. Bu ayar olmadan CORS başlıkları her kaynağa izin verir. Sadece gerçekten erişmesi gereken origin’leri buraya ekleyin.

UFW ile Firewall Kuralları

Eğer Ollama’yı belirli IP’lere açmak zorundaysanız, UFW ile sıkı kurallar tanımlayın:

# Varsayılan olarak gelen trafiği reddet
sudo ufw default deny incoming

# Ollama portuna sadece belirli IP'den erişime izin ver
sudo ufw allow from 192.168.1.50 to any port 11434 proto tcp
sudo ufw allow from 10.0.0.0/24 to any port 11434 proto tcp

# Genel internetten erişimi kesinlikle engelle
sudo ufw deny 11434

# Kuralları aktifleştir
sudo ufw enable
sudo ufw status verbose

IPTables ile Daha Granüler Kontrol

Kurumsal ortamlarda UFW yerine doğrudan iptables tercih edilebilir:

# Sadece belirli subnet'ten Ollama'ya erişime izin ver
sudo iptables -A INPUT -p tcp --dport 11434 -s 10.0.1.0/24 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 11434 -s 127.0.0.1 -j ACCEPT
sudo iptables -A INPUT -p tcp --dport 11434 -j DROP

# Kuralları kalıcı hale getir (Debian/Ubuntu)
sudo apt install iptables-persistent -y
sudo netfilter-persistent save

# Mevcut kuralları kontrol et
sudo iptables -L INPUT -n -v --line-numbers

Nginx Reverse Proxy ile Authentication ve HTTPS

Ollama’nın kendi kimlik doğrulama sistemi olmadığı için önüne bir reverse proxy koymak en temiz çözüm. Nginx burada hem TLS sonlandırma hem de basic auth yapabilir.

SSL Sertifikası Hazırlığı

# Self-signed sertifika oluştur (iç ağ için)
sudo mkdir -p /etc/nginx/ssl/ollama

sudo openssl req -x509 -nodes -days 365 -newkey rsa:4096 
  -keyout /etc/nginx/ssl/ollama/private.key 
  -out /etc/nginx/ssl/ollama/certificate.crt 
  -subj "/C=TR/ST=Istanbul/L=Istanbul/O=MyCompany/CN=ollama.internal" 
  -addext "subjectAltName=DNS:ollama.internal,IP:192.168.1.100"

# Sertifika izinlerini ayarla
sudo chmod 600 /etc/nginx/ssl/ollama/private.key
sudo chmod 644 /etc/nginx/ssl/ollama/certificate.crt

# Let's Encrypt kullanıyorsanız (public domain için)
# sudo certbot certonly --nginx -d ollama.yourdomain.com

Nginx Yapılandırması

# /etc/nginx/sites-available/ollama adlı dosya oluşturun
upstream ollama_backend {
    server 127.0.0.1:11434;
    keepalive 32;
}

# HTTP'yi HTTPS'e yönlendir
server {
    listen 80;
    server_name ollama.internal;
    return 301 https://$server_name$request_uri;
}

server {
    listen 443 ssl http2;
    server_name ollama.internal;

    ssl_certificate /etc/nginx/ssl/ollama/certificate.crt;
    ssl_certificate_key /etc/nginx/ssl/ollama/private.key;
    ssl_protocols TLSv1.2 TLSv1.3;
    ssl_ciphers ECDHE-RSA-AES256-GCM-SHA512:DHE-RSA-AES256-GCM-SHA512;
    ssl_prefer_server_ciphers on;
    ssl_session_cache shared:SSL:10m;

    # Güvenlik header'ları
    add_header X-Frame-Options DENY;
    add_header X-Content-Type-Options nosniff;
    add_header X-XSS-Protection "1; mode=block";
    add_header Strict-Transport-Security "max-age=31536000; includeSubDomains";

    # Basic Authentication
    auth_basic "Ollama API";
    auth_basic_user_file /etc/nginx/.ollama_htpasswd;

    # Rate limiting
    limit_req_zone $binary_remote_addr zone=ollama_limit:10m rate=10r/m;
    limit_req zone=ollama_limit burst=20 nodelay;

    # Log ayarları
    access_log /var/log/nginx/ollama_access.log;
    error_log /var/log/nginx/ollama_error.log warn;

    location / {
        proxy_pass http://ollama_backend;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;

        # Streaming için timeout ayarları
        proxy_read_timeout 300s;
        proxy_connect_timeout 10s;
        proxy_send_timeout 300s;

        # Büyük model yanıtları için buffer ayarları
        proxy_buffering off;
        proxy_cache off;
    }

    # Model yükleme/silme endpoint'lerini sadece belirli IP'lere aç
    location ~ ^/api/(pull|push|delete|copy|create) {
        allow 192.168.1.0/24;
        allow 127.0.0.1;
        deny all;
        proxy_pass http://ollama_backend;
        proxy_read_timeout 600s;
    }
}
# htpasswd dosyası oluştur
sudo apt install apache2-utils -y
sudo htpasswd -c /etc/nginx/.ollama_htpasswd apiuser
# Ek kullanıcı eklemek için -c olmadan kullanın
sudo htpasswd /etc/nginx/.ollama_htpasswd devuser

# Nginx yapılandırmasını aktifleştir
sudo ln -s /etc/nginx/sites-available/ollama /etc/nginx/sites-enabled/
sudo nginx -t
sudo systemctl reload nginx

Bu yapılandırmayla /api/pull, /api/delete gibi yönetim endpoint’leri sadece yerel ağdan erişilebilir olur. Birisi dışarıdan modellerinizi silmeye veya yeni model çekmeye çalışamaz.

API Token Tabanlı Kimlik Doğrulama

Basic auth iyi bir başlangıç ama production ortamlarında token bazlı auth daha yönetilebilir. Nginx’te Lua veya basit bir auth middleware ile bunu yapabilirsiniz. Daha pratik bir yaklaşım olarak küçük bir proxy uygulaması yazmak:

# Python ile basit bir auth proxy
cat > /opt/ollama-proxy/auth_proxy.py << 'EOF'
#!/usr/bin/env python3
import os
import hashlib
import hmac
from http.server import HTTPServer, BaseHTTPRequestHandler
import urllib.request
import urllib.error
import json

VALID_TOKENS = {
    "app-service-token": "myapp",
    "dev-team-token": "devteam",
    "readonly-token": "monitoring"
}

READONLY_PATHS = ["/api/tags", "/api/version", "/api/show"]
OLLAMA_BACKEND = "http://127.0.0.1:11434"

class OllamaAuthProxy(BaseHTTPRequestHandler):
    def do_request(self, method):
        auth_header = self.headers.get("Authorization", "")
        
        if not auth_header.startswith("Bearer "):
            self.send_error(401, "Unauthorized: Bearer token required")
            return
            
        token = auth_header[7:]
        
        if token not in VALID_TOKENS:
            self.send_error(403, "Forbidden: Invalid token")
            return
        
        # Readonly token kontrolü
        if VALID_TOKENS[token] == "monitoring":
            if self.path not in READONLY_PATHS:
                self.send_error(403, "Forbidden: Read-only access")
                return
        
        # İsteği Ollama'ya ilet
        target_url = OLLAMA_BACKEND + self.path
        content_length = int(self.headers.get("Content-Length", 0))
        body = self.rfile.read(content_length) if content_length > 0 else None
        
        req = urllib.request.Request(target_url, data=body, method=method)
        
        try:
            with urllib.request.urlopen(req, timeout=300) as resp:
                self.send_response(resp.status)
                for key, value in resp.headers.items():
                    self.send_header(key, value)
                self.end_headers()
                self.wfile.write(resp.read())
        except urllib.error.URLError as e:
            self.send_error(502, f"Backend error: {str(e)}")
    
    def do_GET(self): self.do_request("GET")
    def do_POST(self): self.do_request("POST")
    def do_DELETE(self): self.do_request("DELETE")
    
    def log_message(self, format, *args):
        token = self.headers.get("Authorization", "unknown")[-10:]
        print(f"[{self.client_address[0]}] token=...{token} {format % args}")

if __name__ == "__main__":
    server = HTTPServer(("127.0.0.1", 11435), OllamaAuthProxy)
    print("Ollama Auth Proxy çalışıyor: 127.0.0.1:11435")
    server.serve_forever()
EOF

chmod +x /opt/ollama-proxy/auth_proxy.py

# Systemd servisi oluştur
sudo tee /etc/systemd/system/ollama-proxy.service << 'EOF'
[Unit]
Description=Ollama Authentication Proxy
After=ollama.service
Requires=ollama.service

[Service]
Type=simple
User=ollama
ExecStart=/usr/bin/python3 /opt/ollama-proxy/auth_proxy.py
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl enable --now ollama-proxy

Audit Logging ve Monitoring

Kimin ne sorduğunu bilmek, güvenlik açısından kritik. Nginx access log’ları başlangıç için yeterli ama daha detaylı bir izleme için şu yaklaşımı kullanabilirsiniz:

# Ollama erişimlerini izlemek için log analiz scripti
cat > /usr/local/bin/ollama-audit.sh << 'EOF'
#!/bin/bash

LOG_FILE="/var/log/nginx/ollama_access.log"
ALERT_THRESHOLD=100  # dakikada 100'den fazla istek

echo "=== Ollama API Erişim Raporu ==="
echo "Son 1 saatteki erişimler:"
echo ""

# IP bazlı istek sayısı
echo "--- IP Bazlı İstek Dağılımı ---"
awk '{print $1}' "$LOG_FILE" | 
  grep -v "^#" | 
  sort | uniq -c | sort -rn | head -20

echo ""
echo "--- Endpoint Kullanımı ---"
awk '{print $7}' "$LOG_FILE" | 
  sort | uniq -c | sort -rn | head -10

echo ""
echo "--- Başarısız Kimlik Doğrulama ---"
grep " 401 | 403 " "$LOG_FILE" | 
  awk '{print $1, $9}' | 
  sort | uniq -c | sort -rn

echo ""
echo "--- Yüksek Hacimli İstekler (Son 5 dk) ---"
RECENT=$(date -d "5 minutes ago" "+%d/%b/%Y:%H:%M")
grep "$RECENT" "$LOG_FILE" | 
  awk '{print $1}' | 
  sort | uniq -c | 
  awk -v threshold="$ALERT_THRESHOLD" '$1 > threshold {print "UYARI: " $2 " - " $1 " istek"}'
EOF

chmod +x /usr/local/bin/ollama-audit.sh

# Günlük rapor için cron
echo "0 9 * * * root /usr/local/bin/ollama-audit.sh >> /var/log/ollama-audit.log 2>&1" | 
  sudo tee /etc/cron.d/ollama-audit

Fail2Ban ile Brute Force Koruması

# Ollama için Fail2Ban filtresi oluştur
sudo tee /etc/fail2ban/filter.d/ollama.conf << 'EOF'
[Definition]
failregex = ^<HOST> .* "(GET|POST|DELETE) /api/.* HTTP/.*" (401|403) .*$
ignoreregex =
EOF

# Fail2Ban jail yapılandırması
sudo tee /etc/fail2ban/jail.d/ollama.conf << 'EOF'
[ollama]
enabled = true
port = 443,80
filter = ollama
logpath = /var/log/nginx/ollama_access.log
maxretry = 5
findtime = 300
bantime = 3600
action = iptables-multiport[name=ollama, port="80,443", protocol=tcp]
EOF

sudo systemctl restart fail2ban

# Fail2Ban durumunu kontrol et
sudo fail2ban-client status ollama

Container Ortamında Ollama Güvenliği

Docker veya Podman ile çalışıyorsanız, ağ izolasyonu için şu yapıyı kullanın:

# Özel bir Docker network oluştur
docker network create --driver bridge 
  --subnet=172.20.0.0/24 
  --ip-range=172.20.0.0/24 
  ollama-net

# Ollama'yı izole network'te çalıştır
docker run -d 
  --name ollama 
  --network ollama-net 
  --ip 172.20.0.10 
  -p 127.0.0.1:11434:11434 
  -v ollama_data:/root/.ollama 
  --gpus all 
  --restart unless-stopped 
  --read-only 
  --tmpfs /tmp:rw,size=2g 
  -e OLLAMA_HOST=0.0.0.0:11434 
  -e OLLAMA_ORIGINS=http://172.20.0.0/24 
  ollama/ollama

# Nginx proxy container'ı aynı network'e bağla
docker run -d 
  --name ollama-proxy 
  --network ollama-net 
  -p 443:443 
  -p 80:80 
  -v /etc/nginx/ollama.conf:/etc/nginx/conf.d/default.conf:ro 
  -v /etc/nginx/ssl:/etc/nginx/ssl:ro 
  -v /etc/nginx/.ollama_htpasswd:/etc/nginx/.htpasswd:ro 
  --restart unless-stopped 
  nginx:alpine

Bu yapılandırmada Ollama container’ı sadece 127.0.0.1:11434 üzerinden host’a, ve internal network üzerinden Nginx container’ına erişilebilir durumda. Dışarıya doğrudan port açılmıyor.

Güvenlik Kontrollerini Otomatikleştirme

Tüm bu önlemleri aldıktan sonra, yapılandırmanın bozulup bozulmadığını düzenli kontrol eden bir script işinizi kolaylaştırır:

#!/bin/bash
# /usr/local/bin/ollama-security-check.sh

ERRORS=0
WARNINGS=0

check() {
    local desc="$1"
    local cmd="$2"
    local expected="$3"
    
    result=$(eval "$cmd" 2>/dev/null)
    if echo "$result" | grep -q "$expected"; then
        echo "✓ $desc"
    else
        echo "✗ HATA: $desc"
        ERRORS=$((ERRORS + 1))
    fi
}

warn() {
    local desc="$1"
    local cmd="$2"
    local pattern="$3"
    
    result=$(eval "$cmd" 2>/dev/null)
    if echo "$result" | grep -q "$pattern"; then
        echo "! UYARI: $desc"
        WARNINGS=$((WARNINGS + 1))
    else
        echo "✓ $desc"
    fi
}

echo "=== Ollama Güvenlik Kontrol Listesi ==="
echo ""

check "Ollama sadece localhost'ta dinliyor" 
    "ss -tlnp | grep 11434" "127.0.0.1"

check "Nginx servisi çalışıyor" 
    "systemctl is-active nginx" "active"

check "Fail2Ban çalışıyor" 
    "systemctl is-active fail2ban" "active"

check "SSL sertifikası geçerli" 
    "openssl x509 -checkend 2592000 -noout -in /etc/nginx/ssl/ollama/certificate.crt" "will not expire"

warn "Doğrudan 11434 portuna dış erişim var" 
    "curl -s --max-time 3 http://$(curl -s ifconfig.me):11434/api/version" "version"

check "Htpasswd dosyası mevcut" 
    "test -f /etc/nginx/.ollama_htpasswd && echo exists" "exists"

check "Auth olmadan API erişimi reddediliyor" 
    "curl -s -o /dev/null -w '%{http_code}' https://localhost/api/tags -k" "401"

echo ""
echo "Sonuç: $ERRORS hata, $WARNINGS uyarı"
[ $ERRORS -gt 0 ] && exit 1 || exit 0
chmod +x /usr/local/bin/ollama-security-check.sh

# Haftalık otomatik kontrol
echo "0 8 * * 1 root /usr/local/bin/ollama-security-check.sh | mail -s 'Ollama Güvenlik Raporu' [email protected]" | 
  sudo tee /etc/cron.d/ollama-security

Pratik Güvenlik Kontrol Listesi

Bir Ollama kurulumunu production’a almadan önce şu maddeleri kontrol edin:

  • Ağ binding: OLLAMA_HOST sadece gerekli adresi dinlemeli
  • Firewall: 11434 portu doğrudan internete açık olmamalı
  • Reverse proxy: Nginx veya Caddy önde olmalı, TLS zorunlu
  • Authentication: Basic auth veya token auth aktif olmalı
  • CORS: OLLAMA_ORIGINS sadece gereken origin’leri içermeli
  • Rate limiting: API abuse’a karşı Nginx level’da limit tanımlı olmalı
  • Fail2Ban: Auth hataları için aktif kural olmalı
  • Logging: Erişim logları düzenli incelenmeli
  • Endpoint kısıtlaması: Yönetim endpoint’leri (/api/pull, /api/delete) IP ile kısıtlanmalı
  • Sertifika: SSL sertifika son kullanma tarihleri takip edilmeli
  • Güncellemeler: Ollama versiyonu güncel tutulmalı

Sonuç

Ollama’yı güvenli çalıştırmak, kurulumdan sonra unutulan bir detay değil; başından beri düşünülmesi gereken bir mimari karar. Varsayılan kurulumda kendi bilgisayarınızda kullanmak için yeterli güvenlik var ama herhangi bir sunucu veya çok kullanıcılı ortamda bu yazıdaki adımların tamamına ihtiyacınız var.

En önemli üç önlem şunlar: Ollama’yı asla doğrudan internete açmayın, önüne mutlaka authentication koyun ve erişim loglarını takip edin. GPU kaynaklarınız pahalı; başkasının sizin sunucunuzda model çalıştırmasına fırsat vermeyin.

Ortamınız geliştikçe güvenlik yapılandırmanızı da gözden geçirin. Yeni bir servis eklendiğinde CORS listesini güncelleyin, eski API token’larını rotasyona sokun, sertifika yenileme süreçlerini otomasyona bağlayın. Güvenlik bir kere yapılıp biten bir şey değil, sürekli bakım gerektiren bir alışkanlık.

Bir yanıt yazın

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