feat(gateway): API Key 인증 + HTTPS (Caddy) 보안 강화

- gateway.py: auth middleware — /api/* 엔드포인트에 Bearer token 필수
- Caddyfile: Let's Encrypt 자동 HTTPS 리버스 프록시
- docker-compose.yml: Caddy 추가, Gateway 포트 내부 전용
- config.py: GATEWAY_API_KEY 설정 추가
- .env: 키 생성 명령어 가이드 포함
This commit is contained in:
Variet Worker
2026-03-11 19:49:24 +09:00
parent 6dbbb57fa7
commit 95da3e9307
5 changed files with 57 additions and 7 deletions

View File

@@ -28,11 +28,12 @@ logger = logging.getLogger(__name__)
class GatewayAPI:
"""HTTP API server for Collector ↔ Gateway communication."""
def __init__(self, bot, host: str = "0.0.0.0", port: int = 8585):
def __init__(self, bot, host: str = "0.0.0.0", port: int = 8585, api_key: str = ""):
self.bot = bot
self.host = host
self.port = port
self.app = web.Application()
self.api_key = api_key
self.app = web.Application(middlewares=[self._auth_middleware])
self._setup_routes()
# In-memory stores (Gateway is stateless across restarts)
@@ -47,6 +48,27 @@ class GatewayAPI:
self.app.router.add_post("/api/register", self._post_register)
self.app.router.add_get("/api/commands/{project}", self._get_commands)
# ─── Auth Middleware ───
@web.middleware
async def _auth_middleware(self, request: web.Request, handler):
"""Reject requests without valid API key on /api/* routes."""
# Health endpoint is public
if request.path == "/health":
return await handler(request)
# All /api/* routes require auth
if request.path.startswith("/api/") and self.api_key:
auth = request.headers.get("Authorization", "")
if auth != f"Bearer {self.api_key}":
logger.warning(f"[GATEWAY] 401 Unauthorized: {request.method} {request.path} from {request.remote}")
return web.json_response(
{"error": "Unauthorized", "detail": "Invalid or missing API key"},
status=401,
)
return await handler(request)
# ─── Health ───
async def _health(self, request: web.Request) -> web.Response:
@@ -170,4 +192,5 @@ class GatewayAPI:
await runner.setup()
site = web.TCPSite(runner, self.host, self.port)
await site.start()
logger.info(f"[GATEWAY] HTTP API started on {self.host}:{self.port}")
auth_status = "API Key enabled" if self.api_key else "⚠️ NO AUTH (set GATEWAY_API_KEY!)"
logger.info(f"[GATEWAY] HTTP API started on {self.host}:{self.port} [{auth_status}]")