## 구현 내용 ### DR 자동화 (routers/dr.py, core/dr_engine.py) - DR 시나리오 등록/관리 (SERVER_FAILURE | SITE_FAILURE | DATA_CORRUPTION) - 복구 테스트 자동화 (SSH 기반 단계별 실행 + 헬스체크) - 백업 무결성 검증 (SSH → SHA-256 해시 검증) - RTO/RPO 목표 대비 실적 대시보드 - Failover 실행 API (ADMIN 전용) ### 네트워크 장비 관리 (routers/network_devices.py, core/network_scanner.py) - 스위치/라우터/방화벽/L4 장비 인벤토리 (CRUD) - 벤더별 SSH 설정 백업 (Cisco IOS / Huawei VRP / Junos / Linux) - 이전 백업과 unified diff 변경 감지 - 위험 명령어 차단 (write erase, factory-reset 등) - 토폴로지 조회 API ### CSAP 공공기관 보안 자동 점검 (routers/compliance.py 확장, core/csap_checker.py) - CSAP/ISMS-P 기반 25개 항목 자동 점검 - 기술적/운영 보안 자동 검증 (SSH, DB 직접 확인) - 수동 항목 증적 업로드 - Excel/HTML 보고서 자동 생성 - 기관별 준수율 대시보드 (A~D 등급) ### DB 모델 추가 (models.py) - DRScenario, DRTest - NetworkDevice, NetworkConfigBackup - CSAPCheckResult ### 하네스 확장 - 에이전트: dr-coordinator, network-guardian, csap-auditor - 스킬: dr-automation, network-devices, csap-compliance - guardia-orchestrator description에 DR/네트워크/CSAP 트리거 추가 ### 매뉴얼 - 39_DR_네트워크장비_CSAP_운영가이드.md 신규 작성 - 16_API_명세서.md v2.1.0 업데이트 (617개 라우트, 섹션 21~23 추가) Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
119 lines
5.4 KiB
Markdown
119 lines
5.4 KiB
Markdown
---
|
|
name: dr-automation
|
|
description: "GUARDiA DR(재해복구) 자동화 구현 스킬. DR 시나리오 관리, Failover 실행, 백업 무결성 검증, 복구 테스트, RTO/RPO 추적 기능을 FastAPI + paramiko 패턴으로 구현한다. 다음 상황에서 반드시 사용: (1) 'DR 구현', '재해복구', 'Failover', 'RTO/RPO' 관련 요청; (2) dr.py 라우터 또는 core/dr_engine.py 작업; (3) 백업 무결성 검증, 복구 테스트 구현; (4) DR 대시보드 구현; (5) 다시 실행, 업데이트, 보완 요청. paramiko SSH 패턴과 SQLAlchemy async 패턴을 따른다."
|
|
---
|
|
|
|
# DR 자동화 구현 스킬
|
|
|
|
## 구현 대상 파일
|
|
- `itsm/core/dr_engine.py` — DR 비즈니스 로직
|
|
- `itsm/routers/dr.py` — FastAPI 라우터
|
|
|
|
## 핵심 구현 원칙
|
|
1. **Fail-Safe 시퀀스**: 스냅샷 → 대기서버 활성화 → 서비스 전환 → 헬스체크 → 롤백(실패 시)
|
|
2. **자격증명 보호**: paramiko 접속 시 IP/계정 노출 금지, AES 복호화 후 메모리만 사용
|
|
3. **비동기**: asyncio.create_subprocess_exec + paramiko를 run_in_executor로 래핑
|
|
4. **감사 기록**: 모든 DR 작업은 tb_audit_log에 기록
|
|
|
|
## DB 모델 (models.py에 추가)
|
|
|
|
```python
|
|
class DRScenario(Base):
|
|
__tablename__ = "tb_dr_scenario"
|
|
id = Column(Integer, primary_key=True)
|
|
name = Column(String(100), nullable=False)
|
|
scenario_type = Column(String(30)) # SITE_FAILURE | SERVER_FAILURE | DATA_CORRUPTION
|
|
primary_server_id = Column(Integer, ForeignKey("tb_server_info.id"))
|
|
standby_server_id = Column(Integer, ForeignKey("tb_server_info.id"))
|
|
rto_minutes = Column(Integer) # 목표 RTO (분)
|
|
rpo_minutes = Column(Integer) # 목표 RPO (분)
|
|
failover_steps = Column(JSON) # 페일오버 실행 단계 목록
|
|
healthcheck_url = Column(String(255))
|
|
last_test_at = Column(DateTime)
|
|
last_test_result = Column(String(20)) # PASS | FAIL | PARTIAL
|
|
is_active = Column(Boolean, default=True)
|
|
created_at = Column(DateTime, default=func.now())
|
|
|
|
class DRTest(Base):
|
|
__tablename__ = "tb_dr_test"
|
|
id = Column(Integer, primary_key=True)
|
|
scenario_id = Column(Integer, ForeignKey("tb_dr_scenario.id"))
|
|
test_type = Column(String(20)) # BACKUP_VERIFY | FAILOVER_SIM | RECOVERY
|
|
status = Column(String(20)) # RUNNING | PASS | FAIL | PARTIAL
|
|
rto_actual = Column(Integer) # 실제 RTO (분)
|
|
rpo_actual = Column(Integer) # 실제 RPO (분)
|
|
result_detail = Column(JSON) # 단계별 결과
|
|
started_at = Column(DateTime, default=func.now())
|
|
completed_at = Column(DateTime)
|
|
triggered_by = Column(String(100))
|
|
```
|
|
|
|
## core/dr_engine.py 구현 패턴
|
|
|
|
```python
|
|
import asyncio, hashlib, time
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
import paramiko
|
|
from sqlalchemy.ext.asyncio import AsyncSession
|
|
|
|
from core.ssh_exec import _get_server_credentials # 기존 AES 복호화 함수 재사용
|
|
from models import DRScenario, DRTest, Server
|
|
|
|
class DREngine:
|
|
async def verify_backup(self, db: AsyncSession, server_name: str) -> dict:
|
|
"""백업 파일 무결성 검증 (SHA-256 체크)."""
|
|
# 1. 서버 정보 조회 (ip_addr, ssh_user, os_pw_enc)
|
|
# 2. AES 복호화로 자격증명 획득
|
|
# 3. paramiko SSH 접속
|
|
# 4. backup_path 하위 최신 파일 SHA-256 계산
|
|
# 5. 결과 반환 (파일명, 크기, 해시, 경로 미노출)
|
|
...
|
|
|
|
async def run_recovery_test(self, db: AsyncSession, scenario_id: int,
|
|
triggered_by: str) -> DRTest:
|
|
"""복구 테스트 실행."""
|
|
# 1. 시나리오 조회
|
|
# 2. DRTest 레코드 생성 (status=RUNNING)
|
|
# 3. failover_steps 순서대로 SSH 명령 실행
|
|
# 4. 각 단계 결과 result_detail에 누적
|
|
# 5. healthcheck_url 응답 확인
|
|
# 6. RTO 계산 (started_at ~ 헬스체크 성공)
|
|
# 7. DRTest status 업데이트 (PASS/FAIL/PARTIAL)
|
|
...
|
|
|
|
def calculate_rto_rpo(self, tests: list[DRTest]) -> dict:
|
|
"""최근 5회 테스트 기반 RTO/RPO 통계."""
|
|
...
|
|
```
|
|
|
|
## routers/dr.py 엔드포인트 구조
|
|
|
|
```
|
|
GET /api/dr/scenarios 목록 (ENGINEER 이상)
|
|
POST /api/dr/scenarios 등록 (ADMIN 전용)
|
|
GET /api/dr/scenarios/{id} 상세
|
|
PUT /api/dr/scenarios/{id} 수정 (ADMIN 전용)
|
|
POST /api/dr/test 복구 테스트 실행 (ENGINEER 이상)
|
|
GET /api/dr/test/{id} 테스트 결과 조회
|
|
GET /api/dr/tests 테스트 이력 목록
|
|
POST /api/dr/backup-verify 백업 무결성 검증 (ENGINEER 이상)
|
|
POST /api/dr/failover/{scenario_id} Failover 실행 (ADMIN 전용, 승인 필요)
|
|
GET /api/dr/rto-rpo RTO/RPO 현황 대시보드
|
|
GET /api/dr/dashboard DR 전체 현황
|
|
```
|
|
|
|
## 보안 규칙
|
|
- Failover 실행은 `require_admin_role` 의존성 필수
|
|
- 백업 검증은 ENGINEER 이상 허용
|
|
- 서버 IP/경로를 API 응답 body에 포함하지 않는다
|
|
- SSH 자격증명은 `core/ssh_exec.py`의 기존 AES 복호화 함수 재사용
|
|
|
|
## 헬스체크 URL 검증 방법
|
|
```python
|
|
import httpx
|
|
async with httpx.AsyncClient(verify=False, timeout=10) as client:
|
|
resp = await client.get(scenario.healthcheck_url)
|
|
return resp.status_code == 200
|
|
```
|