Takip et

FastAPI ve AWS S3 Presigned URL’ler ile Güvenli Dosya Yükleme API’si Nasıl Oluşturulur?

Günümüz web uygulamalarında dosya yükleme, en temel ve aynı zamanda en kritik işlevlerden biridir. Peki, bu süreci hem güvenli hem de ölçeklenebilir bir şekilde nasıl yönetebiliriz? Kullanıcı deneyimini kesintiye uğratmadan, sunucu yükünü minimumda tutarak büyük dosyaların bile sorunsuz bir şekilde yüklenebilmesini sağlamak mümkün müdür? Bu makalede, modern bir yaklaşımla, FastAPI ve AWS S3 Presigned URL‘lerini kullanarak uçtan uca güvenli ve ölçeklenebilir bir dosya yükleme API’si oluşturma sürecini adım adım ele alacağız.

Web uygulamalarının çoğunda, kullanıcıların profil resimleri, belgeler, videolar veya diğer medya dosyaları gibi içerikleri yüklemesi gerekmektedir. Ancak bu basit görünen işlem, arka planda birçok zorluğu barındırır. Geleneksel dosya yükleme yöntemlerinde, kullanıcı dosyaları önce sunucu tarafındaki API’nize gelir, sunucu bu dosyayı işler ve ardından kalıcı bir depolama alanına (genellikle sunucu diskine veya bir bulut depolama servisine) kaydeder. Bu süreç, özellikle yüksek trafikli veya büyük dosya boyutlarına sahip uygulamalarda ciddi performans darboğazlarına ve güvenlik risklerine yol açabilir.

Öncelikle, sunucuya doğrudan yüklenen dosyalar, sunucunun işlem gücünü ve bant genişliğini tüketir. Her dosya yüklemesi bir HTTP isteği olarak sunucuya gelir, sunucu bu isteği alır, dosyayı belleğe veya geçici bir konuma yazar ve ardından bulut depolama gibi nihai hedefine aktarır. Bu zincirleme işlem, özellikle aynı anda yüzlerce veya binlerce kullanıcının dosya yüklemeye çalıştığı senaryolarda sunucunun aşırı yüklenmesine neden olabilir. Sunucu kaynakları sınırlı olduğundan, bu durum uygulamanın genel yanıt süresini yavaşlatır, kullanıcı deneyimini olumsuz etkiler ve hatta sunucunun çökmesine neden olabilir. Diyelim ki bir fotoğraf paylaşım platformu geliştiriyorsunuz. Kullanıcılar anında onlarca yüksek çözünürlüklü fotoğraf yüklemek isteyeceklerdir. Geleneksel yöntemle her bir fotoğrafın önce API sunucunuza gelmesi ve oradan S3’e aktarılması, sunucunuzun performansını ciddi anlamda düşürecektir. İşte tam bu noktada, ölçeklenebilir bir çözüm arayışına girilir.

İkincil olarak, güvenlik büyük bir endişe kaynağıdır. Sunucuya doğrudan dosya yüklemeye izin vermek, kötü niyetli kullanıcıların zararlı içerikleri (virüsler, kötü amaçlı yazılımlar) sunucuya yüklemesine veya güvenlik açıklarını kullanarak sisteminize sızmasına davetiye çıkarabilir. Dosya türü doğrulaması, boyut limitleri ve kötü amaçlı yazılım taraması gibi güvenlik önlemleri her ne kadar alınsa da, bu işlemlerin her biri sunucuya ek yük bindirir ve tam koruma sağlamak zordur. Ayrıca, yüklenen dosyaların geçici olarak sunucuda depolanması, veri ihlali riskini artırır. Hassas verilerin sunucu diskinde, hatta kısa bir süreliğine bile olsa, tutulması güvenlik ekibinin korkulu rüyası olabilir. Bu nedenle, dosyaların API sunucusuyla doğrudan etkileşime girmeden güvenli bir şekilde depolanmasını sağlayacak bir mekanizma kritik öneme sahiptir.

Üçüncül olarak, güncel teknoloji standartları ve mimarileri, mikroservisler ve sunucusuz mimariler gibi dağıtık sistemlere yönelmektedir. Bu tür mimarilerde, dosya yükleme gibi I/O yoğun işlemlerin ana uygulama mantığından ayrılması ve özel, ölçeklenebilir bir hizmet tarafından ele alınması istenir. Bu sayede ana API servisleri daha hafif kalır, daha hızlı yanıt verir ve bakım ile geliştirme süreçleri kolaylaşır. Bu makalede ele alacağımız yöntem, tam da bu ihtiyaçları karşılayarak, dosya yükleme sürecini hem güvenli hem de son derece ölçeklenebilir hale getirmemizi sağlayacak.

FastAPI, AWS S3 ve Presigned URL’ler: Bu Teknolojiler Ne İşe Yarar?

Güvenli ve ölçeklenebilir dosya yükleme API’mizin temelini oluşturan üç ana teknolojiye yakından bakalım: FastAPI, AWS S3 ve S3 Presigned URL’leri. Bu üçlünün birleşimi, dosya yükleme mimarisini kökten değiştiren güçlü bir sinerji yaratır.

FastAPI: Hızlı ve Modern API Geliştirmenin Yeni Yüzü

FastAPI, Python için modern, hızlı (yüksek performanslı) bir web çerçevesidir ve Python 3.6+ standard tip ipuçlarına dayanarak API’leri oluşturmak için tasarlanmıştır. Starlette (hafif ASGI çerçevesi) ve Pydantic (veri doğrulama ve ayar yönetimi) üzerine inşa edilmiştir. Temel özellikleri arasında otomatik interaktif API dokümantasyonu (Swagger UI ve ReDoc), veri doğrulama, serileştirme, asenkron programlama desteği (async/await) ve performans yer alır. FastAPI ile API endpoint’leri yazmak hem çok hızlıdır hem de kod okunaklığı yüksektir. Geliştirici verimliliğini artırırken, düşük gecikme süresi ve yüksek verim sunar. Bir e-ticaret uygulamasında ürün görsellerini yüklemek için bir API’ye ihtiyacınız olduğunu düşünün. FastAPI, bu API’yi dakikalar içinde, veri modelleriyle birlikte tanımlamanıza olanak tanır, bu da geliştirme sürecini inanılmaz hızlandırır.

AWS S3 (Simple Storage Service): Bulut Depolamanın Lideri

Amazon S3, ölçeklenebilirliği, veri kullanılabilirliği, güvenliği ve performansıyla sektör standardı haline gelmiş bir nesne depolama hizmetidir. Sınırsız veri depolama kapasitesi sunar ve milyarlarca nesneyi saklayabilir. Verileriniz, dünya çapında birden fazla bölgede ve birden fazla cihazda otomatik olarak yedeklenir, bu da %99.999999999 (11 dokuz) dayanıklılık anlamına gelir. S3, fotoğraflardan videolara, yedeklemelerden uygulama paketlerine kadar her türlü veriyi depolamak için idealdir. Web sitelerinin statik içeriklerini barındırmak, büyük veri analizi için veri gölleri oluşturmak veya felaket kurtarma çözümleri sunmak gibi sayısız kullanım senaryosuna sahiptir. Örneğin, bir medya şirketiyseniz, tüm video arşivinizi S3’te depolayabilir ve dünya genelindeki izleyicilere düşük gecikmeyle ulaştırabilirsiniz.

S3 Presigned URL’ler: Güvenli ve Doğrudan Yüklemenin Anahtarı

İşte projemizin en kritik bileşeni: S3 Presigned URL’ler. Bu URL’ler, AWS kimlik bilgilerinizi ifşa etmeden, belirli bir S3 nesnesine (dosyaya) sınırlı bir süre için geçici erişim izni veren özel olarak oluşturulmuş URL’lerdir. Basitçe ifade etmek gerekirse, API sunucunuz S3’e “Şu dosyayı, şu kişi, şu süre boyunca, şu izinlerle (örneğin sadece yükleme veya sadece indirme) kullanabilir” diyen bir imza (URL) oluşturur. Bu imza daha sonra istemciye verilir ve istemci, bu URL’yi kullanarak doğrudan S3 ile etkileşime girer. Bu sayede:

  • Sunucu Yükü Azalır: Dosyalar API sunucusuna uğramadan doğrudan S3’e gider. Bu, API sunucunuzun yalnızca Presigned URL’yi oluşturma gibi hafif bir işlem yapmasını sağlar, asıl yükleme işini S3 ve istemci üstlenir.
  • Geliştirilmiş Güvenlik: AWS kimlik bilgileriniz istemcide asla açığa çıkmaz. Presigned URL’ler sınırlı bir süre için geçerlidir ve belirli izinlerle ilişkilendirilir. Bu, kötü niyetli kullanıcıların sürekli erişim sağlamasını engeller.
  • Ölçeklenebilirlik: S3’ün doğal ölçeklenebilirliğinden tam olarak yararlanılır. Aynı anda binlerce kullanıcının dosya yüklemesi bile S3 tarafından kolayca yönetilir.
  • Daha İyi Kullanıcı Deneyimi: Dosyalar doğrudan S3’e yüklendiği için yükleme süreleri kısalır ve genel kullanıcı deneyimi iyileşir.

Bir e-öğrenme platformunda öğrencilerin ödevlerini PDF olarak yüklemesi gerektiğini varsayalım. Presigned URL’ler sayesinde, API’niz sadece öğrencilerin dosyayı S3’e yükleyebileceği geçici bir link verir. Öğrenci dosyayı bu link üzerinden yüklerken, API sunucunuz başka isteklere hizmet vermeye devam edebilir, böylece platformun genel performansı etkilenmez.

Proje Kurulumu ve Gerekli Ayarlar: Güvenli Dosya Yükleme API’si İçin Ortamı Nasıl Hazırlarız?

Şimdi, bu güçlü teknolojileri bir araya getirmek için projemizin temelini oluşturalım. Temiz bir başlangıç için gerekli tüm adımları detaylı bir şekilde inceleyeceğiz. Bu bölümde, Python sanal ortamı oluşturmaktan AWS kimlik bilgilerini yapılandırmaya kadar her detayı ele alacağız.

1. Proje Dizinini Oluşturma ve Sanal Ortam Kurulumu

İlk adım olarak, projemiz için bir dizin oluşturup içine girelim ve ardından bağımlılıkları izole etmek için bir Python sanal ortamı oluşturalım. Bu, projemizin sistemimizdeki diğer Python projeleriyle çakışmasını engeller ve bağımlılık yönetimini kolaylaştırır.


mkdir fastapi-s3-upload
cd fastapi-s3-upload
python3 -m venv venv
source venv/bin/activate # Linux/macOS
# .\venv\Scripts\activate # Windows
    

Sanal ortamı etkinleştirdikten sonra, tüm bağımlılıkları bu ortamda kuracağız.

2. Gerekli Python Kütüphanelerini Kurulumu

API'mizi oluşturmak için FastAPI'ye, HTTP isteklerini yönetmek için Uvicorn'a ve AWS hizmetleriyle etkileşim kurmak için boto3'e ihtiyacımız olacak. Ayrıca, hassas bilgileri (AWS kimlik bilgileri gibi) güvenli bir şekilde yönetmek için python-dotenv kullanacağız.


pip install fastapi uvicorn python-dotenv boto3
    

Bu komut, tüm gerekli kütüphaneleri sanal ortamımıza kuracaktır.

3. AWS Kimlik Bilgileri ve S3 Bucket Konfigürasyonu

FastAPI uygulamamızın S3 ile etkileşime geçebilmesi için AWS kimlik bilgilerine ihtiyacımız var. Bu bilgileri doğrudan kod içine yazmak yerine, .env dosyası kullanarak güvenli bir şekilde yönetmek en iyi uygulamadır. Ayrıca, dosyaları yükleyeceğimiz bir S3 bucket'ı (kovası) da önceden oluşturmuş olmalıyız.

Adım 3.1: AWS Kullanıcısı ve İzinleri Oluşturma

AWS konsoluna giriş yapın ve IAM (Identity and Access Management) servisine gidin. Yeni bir kullanıcı oluşturun (Programmatic access seçeneğini işaretleyin) ve bu kullanıcıya yalnızca S3 ile ilgili belirli izinler veren bir politika ekleyin. En azından, belirli bir S3 bucket'ına s3:PutObject, s3:GetObject ve s3:ListBucket izinleri vermeniz gerekecektir. Bir örnek politika şöyle görünebilir:


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject",
                "s3:ListBucket"
            ],
            "Resource": [
                "arn:aws:s3:::your-bucket-name/*",
                "arn:aws:s3:::your-bucket-name"
            ]
        }
    ]
}
    

your-bucket-name yerine kendi S3 kovanızın adını yazmayı unutmayın. Bu adımları tamamladıktan sonra, AWS erişim anahtarı kimliğini (Access Key ID) ve gizli erişim anahtarını (Secret Access Key) alacaksınız. Bu bilgileri kimseyle paylaşmayın!

Adım 3.2: S3 Bucket Oluşturma

AWS S3 servisine gidin ve yeni bir kova (bucket) oluşturun. Kovanızın adını not alın ve erişim kontrolü için "Block all public access" seçeneğinin işaretli olduğundan emin olun. Dosyaların herkese açık olmasını isterseniz (örneğin statik bir web sitesi için), bu ayarı değiştirebilirsiniz; ancak güvenli dosya yükleme senaryomuzda genellikle özel erişim tercih edilir.

Adım 3.3: .env Dosyasını Oluşturma

Proje kök dizininizde .env adında bir dosya oluşturun ve içine aşağıdaki bilgileri ekleyin:


AWS_ACCESS_KEY_ID="YOUR_AWS_ACCESS_KEY_ID"
AWS_SECRET_ACCESS_KEY="YOUR_AWS_SECRET_ACCESS_KEY"
AWS_REGION="your-aws-region" # Örneğin: eu-central-1
S3_BUCKET_NAME="your-bucket-name"
    

Bu bilgileri kendi AWS kimlik bilgileriniz ve S3 kovanızın adı ile güncelleyin. .env dosyasının versiyon kontrol sistemlerine (Git gibi) yüklenmemesi gerektiğini unutmayın. Bu nedenle, .gitignore dosyanıza .env eklemelisiniz.

4. FastAPI Uygulamasının Temel Yapısı

Şimdi main.py adında bir dosya oluşturalım ve temel FastAPI uygulamasını yapılandıralım. Bu dosya, Presigned URL'leri oluşturacak mantığı içerecektir.


# main.py
import os
from fastapi import FastAPI, HTTPException
from pydantic import BaseModel
from dotenv import load_dotenv
import boto3

# .env dosyasını yükle
load_dotenv()

app = FastAPI(
    title="Güvenli Dosya Yükleme API'si",
    description="AWS S3 Presigned URL'ler ile güvenli ve ölçeklenebilir dosya yükleme API'si.",
    version="1.0.0"
)

# Ortam değişkenlerini al
AWS_ACCESS_KEY_ID = os.getenv("AWS_ACCESS_KEY_ID")
AWS_SECRET_ACCESS_KEY = os.getenv("AWS_SECRET_ACCESS_KEY")
AWS_REGION = os.getenv("AWS_REGION")
S3_BUCKET_NAME = os.getenv("S3_BUCKET_NAME")

# Ortam değişkenlerinin varlığını kontrol et
if not all([AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_REGION, S3_BUCKET_NAME]):
    raise EnvironmentError("Tüm AWS ortam değişkenleri ayarlanmalıdır.")

# S3 istemcisini başlat
s3_client = boto3.client(
    "s3",
    aws_access_key_id=AWS_ACCESS_KEY_ID,
    aws_secret_access_key=AWS_SECRET_ACCESS_KEY,
    region_name=AWS_REGION
)

@app.get("/")
async def read_root():
    return {"message": "FastAPI ve AWS S3 ile Dosya Yükleme API'sine Hoş Geldiniz!"}

# --- Sonraki bölümde Presigned URL endpoint'i buraya gelecek ---
    

Uzman İpucu: Ortam değişkenlerini yüklemek için python-dotenv kullanmak, hassas bilgileri kod tabanından ayırarak güvenlik risklerini minimize eder ve farklı ortamlarda (geliştirme, test, üretim) kolayca yönetilmesini sağlar. Bu yöntem, uygulamanızın dağıtımını da oldukça basitleştirir.

Bu temel yapılandırma ile artık FastAPI uygulamamızın AWS S3 ile konuşmaya hazır olduğunu söyleyebiliriz. Ortam değişkenlerinin doğru bir şekilde yüklendiğinden ve S3 istemcisinin başarıyla başlatıldığından emin olduk. Bir sonraki bölümde, asıl işlevi olan Presigned URL oluşturma mekanizmasını geliştireceğiz.

Presigned URL Oluşturma Mekanizması: Kullanıcı Dosyalarını Doğrudan S3'e Yüklemek İçin Presigned URL'leri Nasıl Üretiriz?

API'mizin kalbi olan Presigned URL oluşturma işlevine odaklanalım. Bu mekanizma, istemcilere dosyalarını doğrudan S3'e yükleyebilmeleri için güvenli, geçici bir anahtar sağlayacak. boto3 kütüphanesini kullanarak bu URL'leri nasıl oluşturacağımızı ve FastAPI üzerinden nasıl sunacağımızı adım adım inceleyeceğiz.

AWS S3, iki ana türde Presigned URL oluşturma yöntemine sahiptir: generate_presigned_url ve generate_presigned_post. Bunların her ikisinin de farklı kullanım senaryoları ve avantajları vardır:

  • generate_presigned_url (Tek Part Yükleme veya İndirme İçin): Bu yöntem, belirli bir S3 nesnesine (dosyasına) tek bir HTTP PUT isteği ile dosya yüklemek veya tek bir HTTP GET isteği ile dosya indirmek için kullanılır. Genellikle daha küçük dosyalar için veya basit indirme bağlantıları oluşturmak için tercih edilir. İstemcinin dosyayı doğrudan bu URL'ye PUT etmesi yeterlidir.
  • generate_presigned_post (Form Tabanlı Yükleme İçin): Bu yöntem, özellikle HTML formları aracılığıyla dosya yüklemek için tasarlanmıştır. Sadece bir URL değil, aynı zamanda yükleme isteğinde bulunması gereken bir dizi "alan" (fields) döndürür. Bu alanlar, S3'e yapılan POST isteğinin bir parçası olarak gönderilmelidir. Genellikle tarayıcı tabanlı yüklemelerde veya daha karmaşık güvenlik politikaları uygulamak istediğinizde kullanılır. Büyük dosyalar için daha uygun olabilir ve istemciye çok parçalı yüklemeyi (multipart upload) daha kolay yapma imkanı sunar.

Bizim senaryomuzda, hem esneklik hem de geniş tarayıcı desteği sağlamak adına generate_presigned_post metodunu kullanacağız. Bu metodun sunduğu "alanlar" sayesinde, S3'e yapılan isteği daha detaylı bir şekilde kontrol edebiliriz.

Presigned POST URL Oluşturma Endpoint'i Nasıl Tasarlanır?

FastAPI uygulamamızda, istemcinin bir Presigned URL talep edeceği bir endpoint tanımlayacağız. Bu endpoint, istemciden yüklemek istediği dosyanın adını ve isteğe bağlı olarak dosya türünü (MIME type) alacaktır. Ardından, S3 için Presigned POST URL'sini oluşturup istemciye geri döndürecektir.

Öncelikle, istemciden gelecek isteğin yapısını tanımlayalım. Bir Pydantic modeli kullanarak dosya adı ve (isteğe bağlı) içerik türü bilgilerini alabiliriz.


# main.py içindeki diğer kodların altına ekleyin

class FileUploadRequest(BaseModel):
    file_name: str
    content_type: str = "application/octet-stream" # Varsayılan olarak ikili veri

class PresignedPostResponse(BaseModel):
    url: str
    fields: dict

@app.post("/get-presigned-url", response_model=PresignedPostResponse)
async def get_presigned_url(request: FileUploadRequest):
    """
    Kullanıcının S3'e dosya yüklemesi için bir Presigned POST URL'si döndürür.
    """
    object_name = request.file_name # S3'te depolanacak dosya adı

    try:
        # Presigned POST URL'sini oluştur
        # expiration: URL'nin geçerlilik süresi (saniye cinsinden)
        # Conditions: Yükleme isteğinde karşılanması gereken koşullar.
        #             Bu örnekte: 'Content-Type' ve 'Content-Length' kontrolü.
        response = s3_client.generate_presigned_post(
            Bucket=S3_BUCKET_NAME,
            Key=object_name,
            Fields={"Content-Type": request.content_type},
            Conditions=[
                {"Content-Type": request.content_type},
                ["content-length-range", 0, 104857600] # 0 byte'tan 100 MB'a kadar
            ],
            ExpiresIn=300 # 5 dakika (300 saniye) geçerlilik süresi
        )
        return PresignedPostResponse(url=response["url"], fields=response["fields"])
    except Exception as e:
        raise HTTPException(status_code=500, detail=f"Presigned URL oluşturulurken hata oluştu: {str(e)}")
    

Yukarıdaki kod bloğunda, get_presigned_url adlı bir POST endpoint'i tanımladık. Bu endpoint, FileUploadRequest modeliyle uyumlu bir JSON gövdesi bekler. İçeride:

  • object_name: S3'e yüklenecek dosyanın adını belirtir. Genellikle bu, kullanıcı tarafından sağlanan dosya adıyla aynıdır veya daha iyi bir güvenlik için sunucu tarafında oluşturulan benzersiz bir ID (UUID) ile ön eklenir.
  • generate_presigned_post: Bu boto3 metodu ile asıl Presigned URL ve gerekli alanlar oluşturulur.
    • Bucket: Dosyanın yükleneceği S3 kovanının adı.
    • Key: S3'teki dosyanın tam yolu ve adı.
    • Fields: S3'e yapılacak POST isteğinde bulunması gereken ekstra form alanları. Burada Content-Type'ı belirtiyoruz.
    • Conditions: S3'ün yüklemeyi kabul etmesi için karşılanması gereken koşullar. Bu, güvenlik için kritik öneme sahiptir.
      • {"Content-Type": request.content_type}: Yüklenen dosyanın türünün API'mize bildirilenle eşleşmesini sağlar. Bu, kötü amaçlı dosya yüklemelerini engellemek için ilk güvenlik katmanıdır.
      • ["content-length-range", 0, 104857600]: Yüklenen dosyanın boyutunun 0 ile 100 MB (100 * 1024 * 1024 byte) arasında olmasını sağlar. Bu da sunucuyu aşırı yüklenmeden korur.
    • ExpiresIn: Oluşturulan URL'nin saniye cinsinden geçerlilik süresi. Burada 5 dakika olarak ayarlanmıştır.
Uzman İpucu: object_name için kullanıcıdan gelen dosya adını doğrudan kullanmak yerine, sunucu tarafında benzersiz bir dosya adı oluşturmak (örneğin bir UUID veya zaman damgası kullanarak) çakışmaları ve potansiyel güvenlik sorunlarını (dizin geçişi saldırıları gibi) önlemek açısından çok daha güvenlidir. Örneğin: object_name = f"uploads/{uuid.uuid4()}-{request.file_name}"

Vaka Analizi: Büyük Dosya Yüklemelerinde Performans Kazancı

Bir video düzenleme yazılımının bulut tabanlı bir versiyonunu geliştirdiğinizi düşünün. Kullanıcılar, yüzlerce megabayt hatta gigabaytlarca boyutunda video dosyalarını yüklemek durumunda kalıyor. Geleneksel yaklaşımla, her bir video dosyasının önce API sunucunuz üzerinden geçmesi, sunucunuzun işlemci, bellek ve ağ kaynaklarını ciddi şekilde zorlayacaktır. Bu, sunucunuzun yavaşlamasına, diğer kullanıcı isteklerine yanıt verememesine ve hatta çökmesine neden olabilir.

Presigned URL yaklaşımıyla ise, kullanıcı video dosyasını yüklemeye başladığında:

  1. İstemci (tarayıcı veya uygulama), FastAPI API'nize sadece dosya adı ve türüyle bir Presigned URL talep eder.
  2. API, bu hafif isteği alır, S3'ten bir Presigned POST URL'si oluşturur (yaklaşık milisaniyeler sürer) ve istemciye geri döner.
  3. İstemci, asıl video dosyasını bu Presigned URL'yi kullanarak doğrudan AWS S3'e yükler. API sunucunuz bu işlemden tamamen muaf kalır.

Bu yöntem sayesinde, API sunucunuzun yükü önemli ölçüde azalır. Sunucunuz sadece koordinatör görevi görürken, ağır yükleme işlemi S3'ün devasa ölçeklenebilirliği tarafından karşılanır. Bu, özellikle büyük dosyaların sıkça yüklendiği senaryolarda performansı %40 veya daha fazla artırabilir. Kullanıcılar daha hızlı yükleme deneyimi yaşar, API sunucunuz daha kararlı çalışır ve operasyonel maliyetler düşer.

İstemci Tarafından Dosya Yükleme: Web Tarayıcısından S3'e Güvenli Yükleme Nasıl Gerçekleştirilir?

API'miz Presigned URL'yi oluşturduktan sonra, sıra istemci tarafında bu URL'yi kullanarak dosyayı S3'e yüklemeye gelir. Bu bölümde, bir web tarayıcısından (HTML ve JavaScript kullanarak) S3'e dosya yükleme sürecini adım adım göstereceğiz. Bu, genellikle bir React, Vue veya Angular uygulaması içinde, veya basit bir HTML/JS formunda gerçekleştirilebilir.

HTML Formu ve JavaScript Mantığı

İlk olarak, kullanıcıdan dosya seçmesini sağlayacak basit bir HTML formu oluşturalım. Ardından, JavaScript kullanarak bu formu nasıl işleyeceğimizi ve Presigned URL ile S3'e nasıl yükleme yapacağımızı görelim.

HTML (index.html)





    
    
    S3 Dosya Yükleyici
    


    

Dosyayı S3'e Yükle

Yüklemeye hazır.

JavaScript Mantığının Açıklaması:

  1. Form Gönderimini Engelleme: event.preventDefault() ile tarayıcının varsayılan form gönderme davranışını durduruyoruz. Bu sayede AJAX ile yükleme yapabiliriz.
  2. Dosyayı Seçme: fileInput.files[0] ile kullanıcının seçtiği ilk dosyayı alıyoruz.
  3. Presigned URL Talebi:
    • fetch('http://127.0.0.1:8000/get-presigned-url', ...) ile FastAPI API'mize bir POST isteği gönderiyoruz.
    • İstek gövdesinde (body), yüklemek istediğimiz dosyanın adını (file.name) ve türünü (file.type) JSON formatında belirtiyoruz. Bu bilgiler, API'mizin S3'ten doğru Presigned URL'yi istemesi için gereklidir.
    • API'den gelen yanıt, S3'e dosya yüklemek için kullanacağımız url ve fields nesnelerini içerir.
  4. S3'e Dosya Yükleme:
    • FormData nesnesi oluşturuyoruz. Bu, dosya ve S3'ten gelen diğer alanları (fields) bir HTTP POST isteğinin gövdesine eklemek için kullanılır.
    • for (const key in fields) { formData.append(key, fields[key]); } döngüsüyle, Presigned POST URL'sinden aldığımız tüm alanları formData'ya ekliyoruz. Bu alanlar S3'ün yüklemeyi kabul etmesi için kritik öneme sahiptir.
    • formData.append('file', file); ile asıl dosya içeriğini formData'ya ekliyoruz. Buradaki 'file' anahtarı, S3'ün beklediği varsayılan dosya alanıdır.
    • Son olarak, fetch(url, { method: 'POST', body: formData }) ile bu formData'yı doğrudan S3'ün bize verdiği url'ye POST ediyoruz. İşte bu noktada dosya, API sunucumuza uğramadan direkt S3'e gidiyor!
  5. Durum Güncellemesi: Yükleme süreci boyunca kullanıcıya geri bildirim sağlamak için statusDiv elementini kullanıyoruz.
Uzman İpucu: Tarayıcı tarafında dosya yükleme ilerlemesini göstermek için Fetch API'nin upload.onprogress olayını veya özel bir kütüphane (örneğin Axios) kullanabilirsiniz. Bu, özellikle büyük dosyalar için kullanıcı deneyimini önemli ölçüde iyileştirir.

Bu istemci tarafı kod, Presigned URL'ler ile güvenli ve doğrudan S3 yüklemesini nasıl gerçekleştireceğinizi gösterir. Bu yaklaşım, hem güvenlik hem de performans açısından geleneksel yöntemlere göre çok daha üstündür.

Yüklenen Dosyaları Yönetme ve Güvenlik Best Practices: S3'teki Dosyaları Güvenli Bir Şekilde Nasıl Yöneteceğiz?

Dosyaları güvenli bir şekilde S3'e yüklemek sadece başlangıçtır. Asıl mesele, bu dosyaları uzun vadede nasıl yöneteceğimiz, erişimi nasıl kontrol edeceğimiz ve olası güvenlik açıklarına karşı nasıl koruyacağımızdır. Bu bölümde, S3'teki dosyalarınızı daha da güvenli hale getirecek en iyi uygulamaları ve ek yönetim stratejilerini ele alacağız.

1. S3 Kova Politikaları ve IAM Kullanımı

S3'teki en temel güvenlik katmanı, IAM (Identity and Access Management) kullanıcıları ve S3 kova politikalarıdır. Daha önce API kullanıcımız için belirli izinler tanımlamıştık. Ancak, bazen doğrudan bir kovaya (bucket) veya içindeki belirli bir klasöre erişim kısıtlamaları getirmek isteyebilirsiniz. Örneğin, sadece belirli IP adreslerinden veya belirli bir IAM rolüne sahip kullanıcıların kovanıza yazma iznine sahip olmasını sağlayabilirsiniz.


{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "RestrictAccessToSpecificFolder",
            "Effect": "Deny",
            "Principal": "*",
            "Action": "s3:PutObject",
            "Resource": "arn:aws:s3:::your-bucket-name/sensitive-data/*",
            "Condition": {
                "NotIpAddress": {
                    "aws:SourceIp": "192.0.2.0/24"
                }
            }
        },
        {
            "Sid": "AllowReadAccessForPublicImages",
            "Effect": "Allow",
            "Principal": "*",
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::your-bucket-name/public-images/*"
        }
    ]
}
    

Bu örnek politika, sensitive-data klasörüne belirli bir IP aralığı dışındaki tüm yazma işlemlerini engellerken, public-images klasöründeki nesnelere herkese açık okuma erişimi verir. S3 kova politikaları, çok ince taneli erişim kontrolü sağlamak için çok güçlüdür.

2. Dosya Adlandırma Stratejileri

Güvenli ve yönetilebilir bir dosya depolama sistemi için dosya adlandırma kritik öneme sahiptir. Aşağıdaki stratejileri göz önünde bulundurun:

  • Benzersiz Kimlikler (UUID): Her yüklenen dosyaya benzersiz bir kimlik (UUID - Universally Unique Identifier) atayın. Bu, dosya adlarının çakışmasını engeller ve aynı ada sahip dosyaların üzerine yazılmasını önler. Örneğin, f"{uuid.uuid4()}-{original_filename}".
  • Klasörleme/Prefixleme: Dosyaları mantıksal olarak klasörlere ayırın (S3'te klasörler aslında nesne adlarındaki öneklerdir). Örneğin, user_uploads/{user_id}/{uuid}-{filename} veya images/{year}/{month}/{day}/{uuid}.jpg. Bu, dosyaların daha kolay bulunmasını ve yönetilmesini sağlar.
  • Orijinal Adı Saklama: Kullanıcı deneyimi için orijinal dosya adını bir meta veri olarak saklamak veya S3 anahtarında (key) bir UUID'den sonra kullanmak faydalı olabilir.

3. Yükleme Sonrası İşlemler (S3 Olayları ve AWS Lambda)

S3, bir nesneye (dosyaya) bir olay (yükleme, silme vb.) gerçekleştiğinde diğer AWS servislerini tetikleyebilen güçlü bir olay bildirim sistemine sahiptir. Bu özellik, yükleme sonrası işlemleri otomatikleştirmek için harikadır:

  • Görsel İşleme: Bir resim yüklendiğinde, bir AWS Lambda fonksiyonunu tetikleyebilir ve bu fonksiyon görüntüyü yeniden boyutlandırabilir, filigran ekleyebilir veya küçük resimler (thumbnails) oluşturabilir.
  • Dosya Taraması: Yüklenen dosyaları kötü amaçlı yazılımlara karşı taramak için Lambda veya başka bir güvenlik servisini tetikleyebilir.
  • Veritabanı Kaydı: Yükleme tamamlandıktan sonra dosya bilgilerini (S3 URL'si, dosya adı, boyutu vb.) veritabanına kaydedebilir.
  • Bildirimler: Yükleme başarılı olduğunda kullanıcıya veya yöneticilere bir e-posta veya bildirim gönderebilir.

Bu senaryolar, sunucu tarafındaki API'nizi daha da hafifletirken, iş mantığını arka planda asenkron olarak yürütmenizi sağlar.

4. ACL'ler ve Genel Erişim Kontrolü

S3 nesneleri için ACL'ler (Access Control Lists) kullanarak her bir nesneye özel erişim izinleri tanımlayabilirsiniz. Ancak, AWS genellikle kova politikaları ve IAM kullanarak daha merkezi ve yönetilebilir erişim kontrolü sağlamayı önerir. "Block all public access" ayarını etkin tutmak ve sadece ihtiyacınız olduğunda belirli nesneleri veya prefixleri herkese açık hale getirmek en güvenli yaklaşımdır. Eğer bir dosyanın indirilmesi gerekiyorsa, bunun için de bir Presigned URL oluşturmak en güvenli yöntemdir.

5. Güvenlik Açıkları ve Önlemleri

  • MIME Type Doğrulama: Presigned URL oluştururken Conditions içinde Content-Type belirterek istemcinin bildirdiği türün geçerli olduğundan emin olun. Ayrıca, dosyanın uzantısını kontrol eden veya dosyanın gerçek MIME türünü (magic number'lara bakarak) doğrulayan bir yükleme sonrası Lambda fonksiyonu ekleyebilirsiniz.
  • Dosya Boyutu Limitleri: Hem Presigned URL oluştururken content-length-range koşulu ile hem de istemci tarafında (JavaScript ile) dosya boyutunu sınırlayarak potansiyel DoS saldırılarını veya yanlışlıkla devasa dosyaların yüklenmesini engelleyin.
  • Virüs ve Kötü Amaçlı Yazılım Taraması: Yüklenen dosyaları gerçek zamanlı veya periyodik olarak virüs taramasından geçirmek, kötü amaçlı içeriklerin sisteminize girmesini engellemek için hayati önem taşır. Bu genellikle ClamAV gibi araçların bir Lambda fonksiyonu içinde veya AWS GuardDuty gibi servislerle entegre edilerek yapılır.
  • Şifreleme: Hassas verileri S3'e yüklerken, hem aktarım sırasında (HTTPS) hem de depoda (server-side encryption veya client-side encryption) şifrelediğinizden emin olun. S3, varsayılan olarak sunucu tarafı şifrelemeyi (SSE-S3, SSE-KMS, SSE-C) destekler.

Bu güvenlik pratiklerini uygulamak, dosya yükleme API'nizin sadece hızlı ve ölçeklenebilir olmasını sağlamakla kalmayacak, aynı zamanda uygulamanızın genel güvenlik duruşunu da önemli ölçüde güçlendirecektir. Unutmayın, güvenlik sürekli bir süreçtir ve düzenli olarak gözden geçirilmelidir.

İleri Düzey Kullanım Senaryoları ve Optimizasyonlar: Performansı ve Güvenliği Artırmak İçin İpuçları Nelerdir?

Temel bir Presigned URL tabanlı dosya yükleme API'si oluşturduk ve güvenlik temellerini attık. Şimdi, uygulamanızın performansını ve kullanıcı deneyimini daha da artırmak için ileri düzey ipuçlarına ve optimizasyonlara göz atalım. Bu bölüm, özellikle büyük ölçekli uygulamalar ve yüksek trafik senaryoları için değer katacaktır.

1. CDN Kullanımı (Amazon CloudFront)

Kullanıcılarınız dünyanın farklı yerlerinde mi? O zaman dosyalarınızın indirme hızını artırmak ve gecikmeyi azaltmak için bir İçerik Dağıtım Ağı (CDN) kullanmak şarttır. Amazon CloudFront, S3'teki dosyalarınızı (görüntüler, videolar, belgeler) dünya genelindeki uç konumlarındaki önbellek sunucularında (edge locations) depolar. Bir kullanıcı bir dosyayı istediğinde, dosya ona coğrafi olarak en yakın uç konumdan sunulur, bu da indirme sürelerini önemli ölçüde hızlandırır.


# CloudFront dağıtımı oluşturma adımları (AWS CLI örneği)
aws cloudfront create-distribution --distribution-config file://distribution-config.json
    

Uzman İpucu: Presigned URL'leri kullanarak doğrudan S3'e yükleme yaparken bile, S3'ten dosya indirme bağlantılarını CloudFront üzerinden sunarak son kullanıcılara daha hızlı erişim sağlayabilirsiniz. CloudFront'u S3'ün önünde bir önbellek olarak konumlandırmak, okuma işlemleri için performansı %50'ye kadar artırabilir.

2. Sunucu Tarafı Doğrulama ve İşlem Kuyrukları

İstemci tarafında yapılan tüm doğrulamalar (dosya türü, boyutu vb.) her zaman güvenilir değildir. Kötü niyetli bir kullanıcı bu kontrolleri atlatabilir. Bu nedenle, yüklenen dosyaları S3'e ulaştıktan sonra sunucu tarafında yeniden doğrulamak hayati önem taşır. Bu işlemi AWS Lambda ve SQS (Simple Queue Service) gibi servislerle entegre edebilirsiniz:

  1. S3'e bir dosya yüklendiğinde, bir S3 olayı bir Lambda fonksiyonunu tetikler.
  2. Lambda fonksiyonu, dosya adını, türünü ve boyutunu yeniden doğrular.
  3. Gerekirse, dosya içeriği üzerinde derinlemesine analiz (virüs taraması, format doğrulaması) yapar.
  4. Geçersiz veya zararlı dosyalar tespit edilirse silinir veya karantinaya alınır.
  5. Geçerli dosyalar için, veritabanına kayıt veya başka bir işleme sokmak üzere bir SQS kuyruğuna mesaj gönderilebilir. Bu, ana API sunucunuzun yükünü azaltır ve asenkron işlem gücü sağlar.

3. Dosya Sıkıştırma ve Önizleme Oluşturma

Özellikle görseller ve videolar gibi medya dosyaları için, yükleme sonrası otomatik sıkıştırma ve önizleme (thumbnail) oluşturma işlemleri kullanıcı deneyimini büyük ölçüde iyileştirir ve depolama maliyetlerini düşürür. Yine AWS Lambda bu iş için biçilmiş kaftandır. Yüksek çözünürlüklü bir fotoğraf yüklendiğinde, Lambda bunu otomatik olarak web için optimize edilmiş boyutlara ve kalitelere dönüştürebilir, farklı önizleme boyutları oluşturabilir ve tüm bu sürümleri S3'e kaydedebilir.


# Basit bir Lambda fonksiyonu psödo-kodu (Python)
import boto3
from PIL import Image # Pillow kütüphanesi

s3 = boto3.client('s3')

def lambda_handler(event, context):
    for record in event['Records']:
        bucket_name = record['s3']['bucket']['name']
        object_key = record['s3']['object']['key']

        # Dosyayı indir
        s3.download_file(bucket_name, object_key, '/tmp/original.jpg')

        # Resmi yeniden boyutlandır (örneğin thumbnail)
        with Image.open('/tmp/original.jpg') as img:
            img.thumbnail((128, 128))
            img.save('/tmp/thumbnail.jpg', 'JPEG')

        # Thumbnail'ı S3'e yükle
        s3.upload_file('/tmp/thumbnail.jpg', bucket_name, f'thumbnails/{object_key}')
        print(f"Thumbnail oluşturuldu ve yüklendi: thumbnails/{object_key}")
    

4. Çok Parçalı Yükleme (Multipart Upload) ve Büyük Dosyalar

AWS S3, 5 GB'tan büyük dosyalar için (veya daha küçük dosyalar için bile daha verimli olabilen) çok parçalı yükleme (Multipart Upload) özelliğini destekler. Bu özellik, büyük dosyaları küçük parçalara bölerek paralel olarak S3'e yüklemenize olanak tanır. Bu, hem yükleme hızını artırır hem de ağ kesintilerine karşı daha dayanıklı hale gelir. Eğer bir parça yüklemesi başarısız olursa, sadece o parçayı yeniden deneyebilirsiniz.

boto3'ün create_multipart_upload, upload_part ve complete_multipart_upload gibi metodlarını kullanarak bu işlemi kendi API'nizde yönetebilirsiniz. İstemci tarafında ise, JavaScript'teki Fetch API veya özel bir kütüphane (örneğin uppy veya resumable.js) ile bu parçalı yüklemeyi kolayca gerçekleştirebilirsiniz. Bu yöntem, özellikle video, CAD dosyaları veya büyük veritabanı yedekleri gibi çok büyük dosyalarla uğraşırken performans farkı yaratır.

Uzman İpucu: Multipart Upload için Presigned URL'ler oluştururken her bir parça için ayrı bir Presigned URL oluşturabilir veya tek bir genel Presigned URL ile istemcinin kendisinin parçaları yönetmesine izin verebilirsiniz. Bu, karmaşık ancak çok büyük dosyalar için en optimize edilmiş çözümdür.

5. İzleme ve Günlükleme

Uygulamanızın ve S3'teki dosya yükleme etkinliklerinin sağlığını izlemek için CloudWatch metriklerini ve S3 erişim günlüklerini kullanın. Hata oranlarını, yükleme sürelerini ve depolama kullanımını takip etmek, potansiyel sorunları proaktif olarak tespit etmenizi ve uygulamanızı sürekli olarak optimize etmenizi sağlar.

Bu ileri düzey optimizasyonlar, dosya yükleme API'nizi daha sağlam, daha performanslı ve daha yönetilebilir hale getirecektir. Her bir adım, uygulamanızın genel kalitesine ve güvenilirliğine katkıda bulunur.

Sonuç ve Sıkça Sorulan Sorular: FastAPI ve AWS S3 ile Güvenli Dosya Yükleme Çözümünüz

Bu makalede, FastAPI ve AWS S3 Presigned URL'lerini kullanarak güvenli ve ölçeklenebilir bir dosya yükleme API'si oluşturma sürecini detaylı bir şekilde inceledik. Geleneksel dosya yükleme yöntemlerinin getirdiği zorlukları aşarak, dosyaların doğrudan S3'e yüklenmesinin faydalarını, API sunucusu üzerindeki yükü azaltma ve güvenliği artırma potansiyelini gördük. FastAPI'nin hızını ve geliştirici dostu yapısını, S3'ün sınırsız ölçeklenebilirliğini ve Presigned URL'lerin sunduğu güvenlik katmanlarını birleştirerek modern bir çözüm ortaya koyduk.

Proje kurulumundan başlayarak, AWS kimlik bilgileri yönetimi, Presigned URL oluşturma mekanizması, istemci tarafı yükleme implementasyonu ve yüklenen dosyaların güvenli bir şekilde yönetilmesi için en iyi uygulamalar hakkında bilgi edindiniz. Ayrıca, CDN entegrasyonu, sunucu tarafı doğrulama, otomatik dosya işleme ve çok parçalı yükleme gibi ileri düzey optimizasyonları ve kullanım senaryolarını da keşfettik. Bu bilgilerle donanmış olarak, kendi uygulamalarınızda yüksek performanslı ve güvenli dosya yükleme çözümleri geliştirmeye hazırsınız.

Sıkça Sorulan Sorular (SSS)

  1. S: Presigned URL'ler ne kadar güvenlidir?

    C: Presigned URL'ler oldukça güvenlidir çünkü doğrudan AWS kimlik bilgilerinizi ifşa etmezler. Belirli bir süre (ExpiresIn parametresi ile belirlenir) geçerli olurlar ve yalnızca belirli eylemler (yükleme, indirme) için sınırlı izinler taşırlar. Ayrıca, S3 tarafında koşullar (örneğin Content-Type veya Content-Length-Range) belirleyerek yükleme sırasında ekstra güvenlik katmanları ekleyebilirsiniz. Ancak, URL bir kez oluşturulduğunda, süresi dolana kadar o URL'ye sahip herkesin belirlenen eylemi gerçekleştirebileceğini unutmamak önemlidir. Bu yüzden kısa süreler belirlemek ve hassas veriler için ek doğrulama adımları eklemek önemlidir.

  2. S: Büyük dosyaları yüklemek için bu yöntem uygun mu?

    C: Kesinlikle! Presigned URL'ler, büyük dosyaların doğrudan S3'e yüklenmesi için oldukça uygundur. Özellikle generate_presigned_post yöntemi, tarayıcıların çok parçalı yüklemeleri (multipart uploads) daha kolay yönetmesine olanak tanır. Dosyaların API sunucunuz üzerinden geçmemesi, sunucu yükünü azaltır ve S3'ün doğal ölçeklenebilirliğinden yararlanılmasını sağlar, bu da büyük dosyaların hızlı ve güvenilir bir şekilde yüklenmesi için idealdir.

  3. S: Yüklenen dosyalara erişimi nasıl kısıtlayabilirim?

    C: Yüklenen dosyalara erişimi kısıtlamanın birkaç yolu vardır. En yaygın ve önerilen yöntem, S3 kovalarını varsayılan olarak "Block all public access" ayarıyla özel (private) tutmaktır. Dosyalara erişim gerektiğinde,

    1. İndirme için başka bir Presigned URL oluşturarak yetkili kullanıcılara geçici erişim sağlayabilirsiniz.
    2. S3 kova politikaları veya IAM rolleri kullanarak belirli IAM kullanıcılarına/rollerine belirli dosyalara veya klasörlere erişim izni verebilirsiniz.
    3. Amazon CloudFront ve Signed URLs/Cookies kullanarak daha gelişmiş ve zaman bazlı erişim kontrolü uygulayabilirsiniz.
  4. S: Yükleme tamamlandıktan sonra başka bir işlem yapmak istersem ne yapmalıyım?

    C: Bu tür yükleme sonrası işlemler için AWS S3 olay bildirimlerini ve AWS Lambda'yı kullanmak en verimli yöntemdir. S3 kovanızda bir dosya oluşturulduğunda bir Lambda fonksiyonunu tetikleyecek bir olay yapılandırabilirsiniz. Bu Lambda fonksiyonu, görüntüyü yeniden boyutlandırmak, dosya içeriğini taramak, veritabanına kayıt eklemek veya başka bir AWS servisini (örneğin SQS veya Step Functions) tetiklemek gibi görevleri yerine getirebilir. Bu yaklaşım, API sunucunuzun daha hafif ve yanıt veren kalmasını sağlar.

  5. S: Bu çözümün maliyeti nedir?

    C: Maliyet, kullanımınıza bağlı olarak değişir. AWS S3 depolama alanı, veri aktarımı (özellikle S3'ten çıkış) ve API istekleri (hem S3 hem de FastAPI sunucunuz için) üzerinden ücretlendirilir. FastAPI uygulamanızı barındırdığınız sunucunun maliyeti de eklenir (örneğin, EC2, ECS veya AWS Lambda üzerinde). Presigned URL yaklaşımı, dosyaların API sunucunuzdan geçmesini engellediği için sunucu üzerindeki ağ trafiği ve işlem maliyetlerini düşürerek genel maliyetleri optimize etmenize yardımcı olabilir. AWS'nin ücretsiz katmanını kullanarak küçük ölçekli denemeler yapabilirsiniz.

Yorumlar
İçeriği beğendiniz mi? Bir tartışma başlatın veya görüşlerinizi paylaşın.
Yorum Yaz

Bir yanıt yazın

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

E-posta Bülteni
Yazılım Topluluğuna Katılın
En son güncellemeleri, yaratıcı ipuçlarını ve özel kaynakları doğrudan e-posta kutunuza alın. Tasarım ve inovasyonun geleceğini birlikte keşfedelim.