--- name: csap-compliance description: "GUARDiA CSAP/ISMS-P 공공기관 보안 준수 자동 점검 구현 스킬. 기존 compliance.py를 확장하여 공공기관 보안 체크리스트(100개 항목) 자동 점검, 증적 수집, Excel/HTML 보고서 생성을 구현한다. 다음 상황에서 반드시 사용: (1) 'CSAP', 'ISMS', '보안인증', '공공기관 보안점검' 구현 요청; (2) compliance.py CSAP 고도화 또는 core/csap_checker.py 작업; (3) 보안 점검 보고서, 준수율 대시보드 구현; (4) 증적 수집, 체크리스트 자동화; (5) 다시 실행, 업데이트, 보완 요청." --- # CSAP 자동 점검 구현 스킬 ## 구현 대상 파일 - `itsm/core/csap_checker.py` — CSAP 점검 엔진 - `itsm/routers/compliance.py` — 기존 파일에 CSAP 엔드포인트 추가 ## DB 모델 (models.py에 추가) ```python class CSAPCheckResult(Base): __tablename__ = "tb_csap_result" id = Column(Integer, primary_key=True) scan_id = Column(String(50), nullable=False, index=True) # CSAP-YYYYMMDD-NNN inst_id = Column(Integer, ForeignKey("tb_inst_meta.id")) item_id = Column(String(20), nullable=False) # M-01, T-15 등 category = Column(String(20)) # 관리적 | 기술적 | 물리적 | 운영 item_name = Column(String(200)) status = Column(String(20)) # PASS|FAIL|PARTIAL|MANUAL_REQUIRED|N_A severity = Column(String(20)) # HIGH|MEDIUM|LOW finding = Column(Text) # 발견 사항 evidence = Column(JSON) # 자동 수집 증적 (마스킹 처리) recommendation = Column(Text) # 개선 권고 scanned_at = Column(DateTime, default=func.now()) ``` ## CSAP 점검 항목 구조 (core/csap_checker.py) ```python CSAP_ITEMS = [ # ── 관리적 보안 (M) ──────────────────────────────────────────────── {"id":"M-01","cat":"관리적","sev":"HIGH","auto":False, "name":"정보보호 정책 수립","check":"policy_doc_uploaded"}, {"id":"M-02","cat":"관리적","sev":"HIGH","auto":False, "name":"정보보호 조직 구성","check":"org_chart_uploaded"}, {"id":"M-03","cat":"관리적","sev":"MEDIUM","auto":True, "name":"정보보호 교육 이력","check":"training_records_exist"}, # ── 기술적 보안 (T) ──────────────────────────────────────────────── {"id":"T-01","cat":"기술적","sev":"HIGH","auto":True, "name":"계정 잠금 정책 (5회 실패 시 잠금)","check":"account_lockout"}, {"id":"T-02","cat":"기술적","sev":"HIGH","auto":True, "name":"패스워드 복잡도 정책 (8자 이상+특수문자)","check":"password_policy"}, {"id":"T-03","cat":"기술적","sev":"HIGH","auto":True, "name":"불필요 서비스 비활성화","check":"unnecessary_services"}, {"id":"T-04","cat":"기술적","sev":"HIGH","auto":True, "name":"SSH root 직접 로그인 차단","check":"ssh_root_disabled"}, {"id":"T-05","cat":"기술적","sev":"HIGH","auto":True, "name":"보안 패치 최신화 (30일 이내)","check":"patch_currency"}, {"id":"T-06","cat":"기술적","sev":"MEDIUM","auto":True, "name":"방화벽 룰 최소 권한 원칙","check":"fw_least_privilege"}, {"id":"T-07","cat":"기술적","sev":"HIGH","auto":True, "name":"암호화 전송 (HTTPS/TLS 1.2 이상)","check":"tls_version"}, {"id":"T-08","cat":"기술적","sev":"HIGH","auto":True, "name":"개인정보 암호화 저장","check":"pii_encryption"}, # ── 운영 보안 (O) ───────────────────────────────────────────────── {"id":"O-01","cat":"운영","sev":"HIGH","auto":True, "name":"로그 보존 기간 (6개월 이상)","check":"log_retention"}, {"id":"O-02","cat":"운영","sev":"HIGH","auto":True, "name":"백업 실시 및 무결성 검증","check":"backup_integrity"}, {"id":"O-03","cat":"운영","sev":"MEDIUM","auto":True, "name":"변경 관리 프로세스 이행","check":"change_management"}, # ── 물리적 보안 (P) ─────────────────────────────────────────────── {"id":"P-01","cat":"물리적","sev":"MEDIUM","auto":False, "name":"출입 통제 시스템 운영","check":"physical_access"}, {"id":"P-02","cat":"물리적","sev":"HIGH","auto":True, "name":"DR 사이트 운영 (RTO/RPO 충족)","check":"dr_test_passed"}, # ... 총 100개 항목 (실제 구현 시 전체 목록 확장) ] ``` ## 자동 점검 함수 패턴 ```python class CSAPChecker: async def check_ssh_root_disabled(self, db, inst_id: int) -> dict: """T-04: SSH root 로그인 차단 확인.""" # 기관 서버 목록 조회 → 각 서버 SSH 접속 → /etc/ssh/sshd_config 확인 # PermitRootLogin no 확인 ... async def check_patch_currency(self, db, inst_id: int) -> dict: """T-05: 보안 패치 최신화 (30일 이내 패치 여부).""" # SSH → rpm -qa --last | head -20 또는 apt list --upgradable ... async def check_log_retention(self, db, inst_id: int) -> dict: """O-01: 로그 보존 6개월 이상.""" # GUARDiA tb_audit_log 최오래된 레코드 날짜 확인 from sqlalchemy import select, func oldest = await db.scalar(select(func.min(AuditLog.created_at))) ... async def check_backup_integrity(self, db, inst_id: int) -> dict: """O-02: 백업 무결성 (DR 테스트 최근 90일 이내 PASS).""" # tb_dr_test에서 최근 PASS 결과 확인 ... async def check_dr_test_passed(self, db, inst_id: int) -> dict: """P-02: DR 테스트 이력.""" # tb_dr_test에서 최근 1년 이내 PASS 확인 ... def generate_scan_id(self) -> str: from datetime import datetime now = datetime.now() return f"CSAP-{now.strftime('%Y%m%d')}-{now.strftime('%H%M%S')}" ``` ## 보고서 생성 패턴 ```python def generate_excel_report(self, results: list, inst_name: str) -> bytes: """openpyxl 기반 Excel 보고서 생성.""" import openpyxl from openpyxl.styles import PatternFill, Font wb = openpyxl.Workbook() ws = wb.active ws.title = "CSAP 점검 결과" # 헤더: 항목ID, 카테고리, 항목명, 심각도, 결과, 발견사항, 개선권고 # 결과별 색상: PASS=녹, FAIL=적, PARTIAL=황 ... def generate_html_report(self, results: list, scan_id: str) -> str: """HTML 점검 보고서 (인쇄 가능, 공문 첨부용).""" # 준수율 차트 (SVG inline), 항목별 상세 테이블 ... ``` ## compliance.py 추가 엔드포인트 ``` POST /api/compliance/csap/scan 전체 자동 점검 (ADMIN 전용) GET /api/compliance/csap/items 점검 항목 목록 (category 필터) GET /api/compliance/csap/results 최근 점검 결과 요약 목록 GET /api/compliance/csap/results/{scan_id} 배치 상세 결과 POST /api/compliance/csap/evidence/{item_id} 수동 증적 업로드 GET /api/compliance/csap/report/html HTML 보고서 (scan_id 쿼리) GET /api/compliance/csap/report/excel Excel 보고서 (scan_id 쿼리) GET /api/compliance/csap/dashboard 기관별 준수율 대시보드 ``` ## 준수율 계산 공식 ``` 자동 점검 통과율 = (PASS + PARTIAL*0.5) / (전체 자동 항목) * 100 수동 항목 = MANUAL_REQUIRED로 표시, 별도 집계 전체 준수율 = (자동 통과 항목 수 + 수동 PASS 업로드 수) / 전체 100개 * 100 ```