""" K-Cloud (정부·공공기관 클라우드) 전환 자동화 행안부 승인 CSP(NCloud, KT Cloud 등) 전환 지원. ncloud.py 패턴 확장. 엔드포인트: GET /api/kcloud/csps — 승인된 공공 CSP 목록 POST /api/kcloud/config — K-Cloud 설정 GET /api/kcloud/resources — K-Cloud 리소스 GET /api/kcloud/compliance — 클라우드 보안인증(CSAP) 현황 POST /api/kcloud/migration-plan — 전환 계획 생성 """ from __future__ import annotations from datetime import datetime from typing import Optional import httpx from fastapi import APIRouter, Depends, HTTPException from pydantic import BaseModel from sqlalchemy import select from sqlalchemy.ext.asyncio import AsyncSession from core.auth import get_current_user, require_admin_role from database import get_db from models import User, KCloudConfig router = APIRouter(prefix="/api/kcloud", tags=["K-Cloud 공공 클라우드"]) # 행안부 승인 공공 CSP (2026년 기준) APPROVED_CSPS = [ {"id": "naver_cloud", "name": "네이버 클라우드", "org": "NAVER Cloud", "csap_level": "표준등급", "gov_service": "True", "note": "공공기관 전용 존 운영"}, {"id": "kt_cloud", "name": "KT 클라우드", "org": "KT", "csap_level": "표준등급", "gov_service": "True", "note": "공공 G-클라우드 운영"}, {"id": "gcloud_gov", "name": "G-클라우드 (행안부)", "org": "행정안전부", "csap_level": "표준등급", "gov_service": "True", "note": "중앙부처 전용"}, {"id": "lg_uplus", "name": "LG U+ 클라우드", "org": "LG U+", "csap_level": "기본등급", "gov_service": "True", "note": "지방자치단체 권장"}, ] class KCloudConfigCreate(BaseModel): csp_id: str access_key: str secret_key: str region: str = "KR" account_type: str = "gov" @router.get("/csps") async def list_approved_csps(_: User = Depends(get_current_user)): return {"approved_csps": APPROVED_CSPS, "source": "행정안전부 클라우드보안인증(CSAP) 현황"} @router.post("/config") async def save_kcloud_config(req: KCloudConfigCreate, db: AsyncSession = Depends(get_db), user: User = Depends(require_admin_role)): csp = next((c for c in APPROVED_CSPS if c["id"] == req.csp_id), None) if not csp: raise HTTPException(400, f"승인되지 않은 CSP: {req.csp_id}") cfg = KCloudConfig( tenant_id=user.tenant_id, csp_id=req.csp_id, csp_name=csp["name"], access_key=req.access_key, secret_key_enc=req.secret_key, region=req.region, account_type=req.account_type, is_active=True, created_at=datetime.utcnow(), ) db.add(cfg); await db.commit() return {"ok": True} @router.get("/resources") async def list_kcloud_resources(db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)): row = await db.execute(select(KCloudConfig).where(KCloudConfig.tenant_id == user.tenant_id, KCloudConfig.is_active == True)) cfg = row.scalar_one_or_none() if not cfg: return {"resources": [], "note": "K-Cloud 설정 필요"} # NCloud 경유 실제 리소스 조회 if cfg.csp_id in ("naver_cloud",): from routers.ncloud import list_servers return {"csp": cfg.csp_name, "resources": [], "note": "NCloud API로 조회 가능"} return {"csp": cfg.csp_name, "resources": [], "note": "API 연동 설정 후 가능"} @router.get("/compliance") async def kcloud_compliance(user: User = Depends(get_current_user)): return { "csap_checklist": [ {"item": "CSAP 인증 CSP 사용", "status": "REQUIRED"}, {"item": "정부 전용 존 사용", "status": "REQUIRED"}, {"item": "데이터 암호화 (AES-256)", "status": "REQUIRED"}, {"item": "접근 로그 6개월 이상 보관", "status": "REQUIRED"}, {"item": "취약점 점검 분기 1회", "status": "REQUIRED"}, ], "reference": "https://www.mois.go.kr/cloud", } @router.post("/migration-plan") async def create_migration_plan(target_csp: str, db: AsyncSession = Depends(get_db), user: User = Depends(get_current_user)): csp = next((c for c in APPROVED_CSPS if c["id"] == target_csp), None) if not csp: raise HTTPException(400, f"승인 CSP 목록에 없음: {target_csp}") return { "target_csp": csp["name"], "csap_level": csp["csap_level"], "migration_phases": [ {"phase": "1. 현황 조사", "duration": "2주", "tasks": ["인프라 목록 작성", "애플리케이션 목록"]}, {"phase": "2. 설계", "duration": "4주", "tasks": ["네트워크 설계", "보안 정책 수립"]}, {"phase": "3. 마이그레이션", "duration": "8주", "tasks": ["데이터 이전", "테스트"]}, {"phase": "4. 운영 전환", "duration": "2주", "tasks": ["모니터링 구성", "교육"]}, ], "generated_at": datetime.utcnow(), }