guardia-itsm/routers/grc_automation.py

115 lines
5.5 KiB
Python

"""GRC 자동화 — Governance Risk Compliance"""
from __future__ import annotations
import json, logging
from datetime import datetime
from fastapi import APIRouter, BackgroundTasks, Depends, HTTPException, Query
from pydantic import BaseModel
from core.auth import get_current_user, require_admin_role
from models import User
logger = logging.getLogger(__name__)
router = APIRouter(prefix="/api/grc", tags=["GRC 자동화"])
_policies: list[dict] = []
_risks: list[dict] = []
_pid = 0; _rid = 0
class PolicyCreate(BaseModel):
title: str; category: str = "security"; content: str = ""; version: str = "1.0"
class RiskCreate(BaseModel):
title: str; likelihood: int = 3; impact: int = 3; mitigation: str = ""
@router.get("/policies")
async def list_policies(category: str = Query(None), user: User = Depends(get_current_user)):
items = _policies if not category else [p for p in _policies if p["category"] == category]
return {"total": len(items), "items": items}
@router.post("/policies")
async def create_policy(body: PolicyCreate, user: User = Depends(require_admin_role)):
global _pid; _pid += 1
draft = body.content
if not draft:
try:
import httpx
async with httpx.AsyncClient(timeout=10) as c:
r = await c.post("http://localhost:11434/api/generate", json={
"model": "llama3", "stream": False,
"prompt": f"다음 IT 보안 정책을 한국어로 3개 항목으로 작성하라: {body.title}"})
draft = r.json().get("response", f"{body.title} 정책 초안")
except Exception:
draft = f"{body.title}: 정책 내용을 입력하세요."
p = {"id": _pid, "title": body.title, "category": body.category,
"content": draft, "version": body.version, "status": "draft",
"created_by": user.username, "created_at": datetime.utcnow().isoformat()}
_policies.append(p); return p
@router.put("/policies/{pid}")
async def update_policy(pid: int, body: PolicyCreate, user: User = Depends(require_admin_role)):
for p in _policies:
if p["id"] == pid:
p.update({"title": body.title, "category": body.category,
"content": body.content, "version": body.version}); return p
raise HTTPException(404, "정책 없음")
@router.get("/risk-matrix")
async def risk_matrix(user: User = Depends(get_current_user)):
m = {"critical": [], "high": [], "medium": [], "low": []}
for r in _risks:
s = r["risk_score"]
if s >= 20: m["critical"].append(r)
elif s >= 12: m["high"].append(r)
elif s >= 6: m["medium"].append(r)
else: m["low"].append(r)
return {"total": len(_risks), "matrix": m}
@router.post("/risk-assessment")
async def create_risk(body: RiskCreate, user: User = Depends(require_admin_role)):
global _rid; _rid += 1
s = body.likelihood * body.impact
lv = "CRITICAL" if s >= 20 else "HIGH" if s >= 12 else "MEDIUM" if s >= 6 else "LOW"
r = {"id": _rid, "title": body.title, "likelihood": body.likelihood,
"impact": body.impact, "risk_score": s, "level": lv,
"mitigation": body.mitigation, "status": "open",
"created_at": datetime.utcnow().isoformat()}
_risks.append(r); return r
@router.get("/compliance")
async def compliance_summary(user: User = Depends(get_current_user)):
crit = sum(1 for r in _risks if r.get("level") == "CRITICAL")
score = max(0, 100 - crit * 10)
return {"policies": {"total": len(_policies), "active": sum(1 for p in _policies if p.get("status") == "active")},
"risks": {"total": len(_risks), "critical": crit},
"compliance_score": score,
"grade": "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D"}
@router.post("/audit-report")
async def audit_report(standard: str = Query("CSAP"), user: User = Depends(require_admin_role)):
crit = sum(1 for r in _risks if r.get("level") == "CRITICAL")
score = max(0, 100 - crit * 10)
return {"standard": standard, "generated_at": datetime.utcnow().isoformat(),
"summary": {"total_policies": len(_policies), "total_risks": len(_risks),
"critical_risks": crit, "compliance_score": score},
"findings": [f"CRITICAL 리스크 {crit}", f"{standard} 준수율 {score}%"],
"recommendations": ["CRITICAL 리스크 즉시 완화 조치 필요"] if crit else ["컴플라이언스 상태 양호"]}
@router.get("/templates")
async def policy_templates(user: User = Depends(get_current_user)):
return {"templates": [
{"id": 1, "name": "SSH root 접속 금지 정책", "category": "security"},
{"id": 2, "name": "비밀번호 90일 주기 변경 정책", "category": "access"},
{"id": 3, "name": "미사용 계정 30일 비활성화 정책", "category": "access"},
{"id": 4, "name": "서버 패치 30일 내 적용 정책", "category": "operation"},
{"id": 5, "name": "백업 7일 보관 확인 정책", "category": "operation"},
]}
@router.get("/dashboard")
async def grc_dashboard(user: User = Depends(get_current_user)):
crit = sum(1 for r in _risks if r.get("level") == "CRITICAL")
score = max(0, 100 - crit * 10)
return {"compliance_score": score,
"grade": "A" if score >= 90 else "B" if score >= 80 else "C" if score >= 70 else "D",
"policies": len(_policies), "risks": len(_risks), "critical_risks": crit,
"recent_policies": _policies[-3:][::-1],
"top_risks": sorted(_risks, key=lambda x: x["risk_score"], reverse=True)[:3]}