REST API
JWT Bearer 인증과 RBAC를 사용해 Single Edge의 VM, 컨테이너, 스토리지, 네트워크를 자동화한다.
먼저 인증 계약을 확인한 뒤 필요한 예제를 복사해 시작한다.
14.1 개요와 기본 계약
섹션 제목: “14.1 개요와 기본 계약”| 항목 | 값 |
|---|---|
| Base URL | http://HOST/api/v1 |
| 포트 | HTTP 80 / HTTPS 443 |
| REST 엔드포인트 | 229+ |
| JSON-RPC 메서드 | 304 (POST /api/v1/rpc) |
| WebSocket | /api/v1/ws/events |
| 인증 | Authorization: Bearer {JWT} · JWT HS256 |
| CSRF | 쿠키 세션 미사용. X-CSRF-Token 헤더 없음 |
| Content-Type | application/json |
| 압축 | gzip (Accept-Encoding: gzip) |
| CORS | 화이트리스트 기반 |
| 성공 응답 | {"data": ...} |
| 오류 응답 | {"error": {code, message}} |
| 캐시 | ETag + max-age=5 (GET) / no-store (POST) |
| 페이지네이션 | X-Total-Count + Link rel="next/prev" |
| Correlation ID | 요청/응답 UUID (X-Correlation-Id) |
REST와 JSON-RPC passthrough, WebSocket은 같은 인증 경계를 사용한다.
HOST는 현재 Single Edge 노드 주소로 바꿔 사용한다.
14.2 인증과 토큰
섹션 제목: “14.2 인증과 토큰”PureCVisor REST API는 쿠키 세션 대신 Authorization header의 Bearer token을 사용한다.
14.2.1 로그인
섹션 제목: “14.2.1 로그인”설정된 관리자 계정으로 access token을 발급한다.
curl -X POST /api/v1/auth/token \ -d '{"username":"admin","password":"<configured-admin-password>"}'14.2.2 토큰 사용
섹션 제목: “14.2.2 토큰 사용”모든 보호된 요청에 Bearer token을 전달한다.
curl -H "Authorization: Bearer eyJ..." \ /api/v1/vms14.2.3 쓰기 작업
섹션 제목: “14.2.3 쓰기 작업”POST 작업도 같은 Authorization header와 역할 검사를 사용한다.
curl -X POST \ -H "Authorization: Bearer eyJ..." \ /api/v1/vms/web-prod/startaccess token 만료 후에는 POST /api/v1/auth/refresh에 {"refresh_token":"eyJ..."}를 전송해 갱신한다.
14.3 RBAC 역할
섹션 제목: “14.3 RBAC 역할”| 역할 | 레벨 | 권한 |
|---|---|---|
VIEWER | 0 | 읽기 전용(GET). 자신의 브라우저 Push 구독 등록·해지·조회 허용 |
OPERATOR | 1 | VM/컨테이너 운영. VM action은 생성자 범위 |
ADMIN | 2 | 전체 관리자 |
내장 기본 비밀번호가 없다.
첫 로그인 전daemon.conf또는PURECVISOR_ADMIN_PASSWORD로 bootstrap 비밀번호를 설정한다.
OPERATOR는 libvirt domain metadata의 owner가 본인인 VM에만 시작, 중지, 삭제, 스냅샷, VNC, 일괄 작업을 수행할 수 있다.
14.4 보안
섹션 제목: “14.4 보안”| 항목 | 계약 |
|---|---|
| 속도 제한 | 600 IP / 1200 유저 / 60 인증 |
| JWT 알고리즘 | HS256 |
| JWT 만료 | 900s (15min) + refresh 7d |
| CORS | 화이트리스트 |
| ETag | GET 응답 조건부 캐싱(304) |
| JWT IP 바인딩 | 선택적 클라이언트 IP 검증 |
| 테넌트 오버레이 암호화 | per-VM WireGuard netns (fail-closed) |
| hidepid | /proc hidepid=2 하드닝(ADR-0028) |
| Suricata | IDS/IPS 심층 패킷 검사(D13) |
14.4.1 엔드포인트별 Rate Limit
섹션 제목: “14.4.1 엔드포인트별 Rate Limit”| 엔드포인트 | 제한 |
|---|---|
POST /auth/token | 60/분 |
GET /metrics | 3,600/시간 |
GET /vms | 600/분 |
POST /vms | 60/분 |
| 기타 | 600/분(IP 기본) |
14.4.2 메서드별 타임아웃
섹션 제목: “14.4.2 메서드별 타임아웃”| 유형 | 타임아웃 |
|---|---|
| 읽기(GET) | 8초 |
| 쓰기(POST/PUT) | 30초 |
| 장기 작업(migrate, backup) | 60초 |
14.5 엔드포인트와 응답
섹션 제목: “14.5 엔드포인트와 응답”| 영역 | 경로 | 용도·응답 |
|---|---|---|
| 인증 | POST /auth/token, POST /auth/refresh | access/refresh token 발급과 갱신 |
| VM | GET/POST /vms, /vms/{name}/start, /stop, DELETE /vms/{name} | 목록·생성·수명주기. 삭제 상태는 GET /vms/{name}/delete-status |
| 컨테이너 | GET/POST /containers, /containers/{name}/exec | 목록·생성·명령 실행 |
| 모니터링 | GET /host/metrics, /processes, /alerts | 호스트 메트릭·프로세스·알림 히스토리 |
| Prometheus | GET /metrics | 인증 없는 Prometheus 메트릭 |
| Health | GET /health | 인증 없는 심층 프로브. status와 libvirt, etcd, disk, audit_db, tls, capabilities 하위 상태 반환 |
Single Edge 공개판은 클러스터 상태, 클러스터 전체 VM, 라이브 마이그레이션 REST 절차를 운영 표면으로 제공하지 않는다.
관련 역사 기록은 docs/adr/와 Multi 범위 문서에서만 확인한다.
14.6 curl 예제
섹션 제목: “14.6 curl 예제”HOST와 TOKEN을 현재 Single Edge 환경의 값으로 바꿔 실행한다.
14.6.1 VM 목록
섹션 제목: “14.6.1 VM 목록”curl -s -H "Authorization: Bearer $TOKEN" \ http://HOST/api/v1/vms | jq14.6.2 VM 생성
섹션 제목: “14.6.2 VM 생성”curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"name":"web","vcpu":2,"memory_mb":2048,"disk_size_gb":20}' \ http://HOST/api/v1/vms14.6.3 스냅샷 생성
섹션 제목: “14.6.3 스냅샷 생성”curl -X POST -H "Authorization: Bearer $TOKEN" \ -d '{"snap_name":"backup-1"}' \ http://HOST/api/v1/vms/web/snapshot/create14.6.4 컨테이너 실행
섹션 제목: “14.6.4 컨테이너 실행”curl -X POST -H "Authorization: Bearer $TOKEN" \ -d '{"command":"hostname -I"}' \ http://HOST/api/v1/containers/app-ctr/exec14.6.5 비동기 작업 조회
섹션 제목: “14.6.5 비동기 작업 조회”curl -H "Authorization: Bearer $TOKEN" http://HOST/api/v1/jobs14.6.6 WebSocket 이벤트
섹션 제목: “14.6.6 WebSocket 이벤트”wscat -c "ws://HOST/api/v1/ws/events?token=$TOKEN"14.7 브라우저 푸시 (SP2b)
섹션 제목: “14.7 브라우저 푸시 (SP2b)”구독은 3단계다.
GET /push/vapid로 서버 공개키를 받고, 브라우저가 만든PushSubscription.toJSON()을POST /push/subscribe로 올리고,POST /push/unsubscribe로 해지한다.
내 구독은GET /push/mine으로 확인한다.소유자는 호출자 신원으로 고정된다.
VIEWER도 자기 구독은 등록·해지·조회할 수 있지만 전체 명단, VAPID 회전, 테스트 발송은ADMIN전용이다.
발송은daemon.conf[webpush]의enabled,min_severity(warn|crit),contact가 결정한다.iOS Safari는 이 화면을 홈 화면에 PWA로 설치한 경우에만 푸시를 받는다.
14.7.1 VAPID 공개키 조회
섹션 제목: “14.7.1 VAPID 공개키 조회”요청:
curl -s -H "Authorization: Bearer $TOKEN" \ http://HOST/api/v1/push/vapid응답:
{"data":{"key":"BN1nZq...(base64url)"}}14.7.2 구독 등록
섹션 제목: “14.7.2 구독 등록”요청:
curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"endpoint":"https://fcm.googleapis.com/fcm/send/cXY..", "keys":{"p256dh":"BN1n..","auth":"k9Xz.."}}' \ http://HOST/api/v1/push/subscribe응답:
{"data":{"status":"subscribed"}}14.7.3 구독 해지
섹션 제목: “14.7.3 구독 해지”요청:
curl -X POST -H "Authorization: Bearer $TOKEN" \ -d '{"endpoint":"https://fcm.googleapis.com/fcm/send/cXY.."}' \ http://HOST/api/v1/push/unsubscribe응답:
{"data":{"status":"unsubscribed"}}14.7.4 구독 명단 (ADMIN)
섹션 제목: “14.7.4 구독 명단 (ADMIN)”요청:
curl -s -H "Authorization: Bearer $TOKEN" \ http://HOST/api/v1/push/subscriptions응답:
{"data":{"subscriptions":[ {"username":"admin","endpoint":"https://fcm.googleapis.com/…", "created_at":1785000000,"last_ok_at":1785003600,"fail_count":0}]}}14.7.5 VAPID 회전 (ADMIN — 전 구독 폐기)
섹션 제목: “14.7.5 VAPID 회전 (ADMIN — 전 구독 폐기)”요청:
curl -X POST -H "Authorization: Bearer $TOKEN" \ http://HOST/api/v1/push/vapid/rotate응답:
{"data":{"revoked":3,"key":"BJ7pQw...(new)"}}14.7.6 테스트 발송 (ADMIN)
섹션 제목: “14.7.6 테스트 발송 (ADMIN)”요청:
curl -X POST -H "Authorization: Bearer $TOKEN" \ -d '{"username":"admin"}' \ http://HOST/api/v1/push/test응답:
{"data":{"status":"queued"}}14.8 2.0 RPC 예제 (RPC 전용)
섹션 제목: “14.8 2.0 RPC 예제 (RPC 전용)”테넌트 오버레이, QoS, Suricata, 트레이스 네임스페이스는 RPC 전용이다.
전용 REST 경로, CLI, UI 페이지가 없으며POST /api/v1/rpcJSON-RPC passthrough로만 호출한다.
14.8.1 테넌트 암호화 오버레이 생성
섹션 제목: “14.8.1 테넌트 암호화 오버레이 생성”curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"tenant_overlay.create","params":{"tenant":"acme"},"id":"1"}' \ http://HOST/api/v1/rpc14.8.2 테넌트 QoS 설정
섹션 제목: “14.8.2 테넌트 QoS 설정”curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"qos.tenant.set","params":{"tenant":"acme","min_mbps":100,"max_mbps":1000},"id":"1"}' \ http://HOST/api/v1/rpc14.8.3 Suricata IPS 활성화
섹션 제목: “14.8.3 Suricata IPS 활성화”curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"suricata.ips.enable","params":{},"id":"1"}' \ http://HOST/api/v1/rpc14.8.4 트래픽 트레이스 시작
섹션 제목: “14.8.4 트래픽 트레이스 시작”curl -X POST -H "Authorization: Bearer $TOKEN" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","method":"debug.trace.start","params":{"timebox_sec":30,"tenant":"acme"},"id":"1"}' \ http://HOST/api/v1/rpc