LLM & Generative AI/RAG in Practice

[LangChain RAG 구축 시리즈 Ep.25] 🛡️ 사용자 인증이 포함된 RAG API 구성 전략

ygtoken 2025. 4. 5. 22:36
728x90

RAG 시스템이 외부 사용자 또는 내부 팀원에게 API 형태로 제공되는 순간,
접근 제어와 보안은 필수가 됩니다.
특히 GPT 기반 응답 시스템은 비용이 발생하거나 민감 정보를 포함할 수 있으므로,
인증되지 않은 사용자에게 무제한으로 제공되어선 안 됩니다.

이 글에서는 FastAPI 기반 RAG 서버에
🔐 API Key 기반 인증 기능을 추가하는 방법을 소개합니다.

  • 클라이언트는 요청 시 Authorization 헤더에 키를 포함
  • 서버는 키를 검증하고, 일치하지 않으면 요청을 거부
  • 키는 하드코딩 대신 환경변수나 설정 파일에서 불러오도록 설계

🎯 목표

  • FastAPI에 인증 미들웨어 추가
  • 유효한 API Key가 없으면 401 Unauthorized 반환
  • 향후 OAuth, 세션 기반 인증으로 확장 가능한 구조 설계

🛠️ Step 1. 인증 로직 구현 (dependency 함수)

# src/auth.py

from fastapi import Request, HTTPException, status, Depends

# ✅ 실제 사용할 API 키는 환경변수 또는 config 파일에서 불러오는 것이 좋습니다.
VALID_API_KEYS = {"my-secret-key"}  # 예제에서는 하드코딩된 키 사용

def verify_api_key(request: Request):
    """
    HTTP 요청 헤더에서 API 키를 확인하고 유효성을 검증합니다.
    유효하지 않으면 401 에러를 반환합니다.
    """

    # ✅ 요청 헤더에서 Authorization 키 추출
    api_key = request.headers.get("Authorization")

    # ✅ 키가 없거나, 유효하지 않은 경우 401 반환
    if not api_key or api_key not in VALID_API_KEYS:
        raise HTTPException(
            status_code=status.HTTP_401_UNAUTHORIZED,
            detail="Invalid or missing API Key"
        )

    # ✅ 키가 유효하면 요청을 계속 처리
    return api_key

⚙️ Step 2. FastAPI 라우터에 인증 추가

# src/rag_server.py (수정 버전)

from fastapi import FastAPI, Request, Depends
from pydantic import BaseModel
from src.conversational_chain import create_conversational_chain
from src.auth import verify_api_key  # 인증 미들웨어 임포트
import uvicorn

app = FastAPI()

class QueryRequest(BaseModel):
    question: str

qa_chain = create_conversational_chain(
    db_path="chroma_db",
    collection_name="iceberg_tables",
    k=2
)

# ✅ 인증을 통과한 사용자만 접근 가능하도록 Depends 추가
@app.post("/rag/query")
async def rag_query(request: QueryRequest, _: str = Depends(verify_api_key)):
    """
    인증된 사용자만 질문을 보낼 수 있는 RAG API입니다.
    API 키는 Authorization 헤더를 통해 전달됩니다.
    """

    question = request.question
    result = qa_chain(question)

    answer = result["result"]
    sources = [doc.page_content for doc in result["source_documents"]]

    return {
        "question": question,
        "answer": answer,
        "sources": sources
    }

if __name__ == "__main__":
    uvicorn.run("src.rag_server:app", host="0.0.0.0", port=8000, reload=True)

🔐 Step 3. 테스트 방법

▶️ 유효한 키와 함께 요청

http POST http://localhost:8000/rag/query \
  Authorization:"my-secret-key" \
  question="products 테이블의 컬럼은?"

✅ 응답 수신 성공


▶️ 키가 없거나 잘못된 경우

http POST http://localhost:8000/rag/query question="test"
{
  "detail": "Invalid or missing API Key"
}

✅ 401 Unauthorized 반환됨


📎 요약 및 핵심 정리

  • FastAPI 기반 RAG API에 **간단한 인증 체계(API Key 방식)**를 도입했습니다.
  • 인증 미들웨어는 별도 모듈로 구성하고, 라우터에 Depends()로 연결합니다.
  • 향후에는 OAuth, JWT, 세션 기반 인증 등으로 확장할 수 있는 구조입니다.
728x90