콘텐츠로 이동

v0.6

감사 로그 레코드 CDDL 스키마 설계

1. 개요

1.1. 설계 목적

본 문서는 D'CENT Enterprise의 트랜잭션 전 생명주기(생성-승인-서명-브로드캐스트)와 시스템 운영 전반에 걸쳐 발생하는 감사 로그 레코드의 데이터 구조를 CDDL(RFC 8610) 스키마로 정의한다. 이 스키마는 에어갭 환경에서 변조 불가한 증적을 생성하고, 3계층 무결성 체인(SE 해시 앵커 - 오프라인 앱 로그 - 대시보드 집계)의 기초 데이터 단위 역할을 한다.

1.2. 규제 근거

규제 조항 요건 스키마 대응
REG-KR-08 전자금융감독규정 5년 보존, 접근/거래/오류 기록 AuditRecord에 접근(AUTH_), 거래(TX_), 오류(SECURITY_EVENT) 포함
REG-KR-14 ISMS-P 변조 불가 감사 로그 prev_hash 해시 체인 + Zone 2/3 로컬 서명
REG-KR-15 접근 기록 6개월 이상 보관 AUTH_SUCCESS/AUTH_FAILURE 이벤트, 보존 정책에 통합
REG-EU-03 MiCA 5년 보존, NCA 접근 가능 형식 CDDL -> OCSF/ESMA JSON 변환은 Phase 32에서 설계
REG-JP-02 자금결제법 10년 보존 아카이브 저장소 10년 파라미터
REG-SG-02 AML/CFT 5년 보존 기본 5년 아카이빙
CORE-03 감사 로그 장기 보존 3단계 아카이빙(활성/아카이브/영구)
CORE-04 변조 불가 감사 로그 SE 해시 앵커 + 해시 체인 + 로컬 서명

1.3. 3-Zone 배치 원칙

감사 로그는 3-Zone 아키텍처에 걸쳐 생성되며, 각 Zone의 역할에 따라 이벤트 발생 지점이 결정된다.

Zone 역할 로그 생성 주체 저장 위치
Zone 1 (대시보드) 장기 아카이빙, 표준 포맷 출력, 집계 대시보드 서버 3단계 아카이빙 저장소
Zone 2 (오프라인 앱) 로컬 감사 로거, AuditSyncPayload 생성 오프라인 앱 앱 로컬 스토리지 + 동기화 전송
Zone 3 (SE) 해시 앵커 + 서명 카운터 (상세 로그 저장 안 함) SE 펌웨어 SEAuditDigest (128B)

2. 공통 감사 레코드 구조 (AuditRecord)

2.1. CDDL 스키마 정의

; ====================================================================
; D'CENT Enterprise Audit Log Record Schema
; RFC 8610 CDDL Specification
; Version: 1.0
; Phase: 30-audit-architecture
; ====================================================================

AuditRecord = {
    record_id:    bstr .size 16,        ; UUID v7 (시간 정렬 가능, 128-bit)
    event_type:   EventType,            ; 이벤트 타입 열거형
    timestamp:    #6.1(float64),        ; CBOR tag 1, epoch seconds + 밀리초 정밀도
    actor:        Actor,                ; 행위자 정보
    zone:         Zone,                 ; 이벤트 발생 Zone
    result:       Result,               ; 실행 결과
    prev_hash:    bstr .size 32,        ; SHA-256(이전 레코드), 해시 체인 링크
    payload:      EventPayload,         ; 이벤트 타입별 상세 데이터
    ? signature:  bstr .size 64,        ; Zone 2/3 발생 이벤트 로컬 서명 (ECDSA P-256)
}

Actor = {
    role:         RBACRole,             ; RBAC v2 6역할 체계
    device_id:    bstr .size 8,         ; SE 또는 앱 식별자
    session_id:   bstr .size 16 / null, ; 서명 세션 ID (세션 외 이벤트는 null)
    ? user_id:    tstr,                 ; 사용자 식별자 (가명처리 가능)
}

Zone = &(
    zone-dashboard: 1,                 ; Zone 1: 대시보드
    zone-offline-app: 2,               ; Zone 2: 오프라인 앱
    zone-se: 3,                        ; Zone 3: SE (콜드월렛)
)

Result = &(
    result-success: 1,
    result-failure: 2,
    result-rejected: 3,
    result-timeout: 4,
)

RBACRole = &(
    role-org-owner: 1,                 ; Org Owner
    role-vault-admin: 2,               ; Vault Admin
    role-policy-admin: 3,              ; Policy Admin
    role-operator: 4,                  ; Operator
    role-viewer: 5,                    ; Viewer
    role-auditor: 6,                   ; Auditor
    role-system: 7,                    ; 시스템 자동 이벤트
)

2.2. 필드 상세 설명

필드 크기 설명 규제 매핑
record_id 16B UUID v7 — 타임스탬프 기반 정렬 가능, 분산 환경에서 충돌 방지 CORE-04 (레코드 고유 식별)
event_type 1-2B 이벤트 타입 열거형 (19+ 이벤트, 섹션 3 참조) REG-KR-08 (이벤트 분류)
timestamp 8B CBOR tag 1(epoch seconds) + float64 밀리초 정밀도. Zone 3는 오프라인 앱 제공 시간 사용 (SE 시계 부재) REG-KR-08 (시간 기록)
actor 가변 행위자의 RBAC 역할, 기기 ID, 세션 ID. "누가 했는가"의 완전한 추적 REG-KR-14 (행위자 추적), CORE-05 (접근 통제)
zone 1B 이벤트 발생 Zone (1/2/3). 3계층 무결성 체인의 계층 식별 CORE-04 (계층별 검증)
result 1B 실행 결과 (성공/실패/거부/타임아웃) REG-KR-08 (결과 기록)
prev_hash 32B SHA-256(직전 AuditRecord의 CBOR 직렬화). 해시 체인의 단방향 링크 CORE-04 (변조 불가), REG-KR-14
payload 가변 이벤트 타입별 상세 데이터 (섹션 3에서 각각 CDDL 정의) REG-KR-08 (상세 내용)
signature 64B Zone 2/3 이벤트만. ECDSA P-256 서명 (오프라인 앱 키 또는 SE 키) CORE-04 (서명 무결성)

2.3. 해시 체인 구성 규칙

prev_hash 계산:
  prev_hash[n] = SHA-256( CBOR_serialize( AuditRecord[n-1] ) )

제네시스 레코드 (각 Zone의 첫 번째 레코드):
  prev_hash = 0x00 * 32 (32 bytes zero)

Zone별 독립 체인:
  - Zone 1 체인: 대시보드 이벤트만 연결
  - Zone 2 체인: 오프라인 앱 이벤트만 연결
  - Zone 3 체인: SE 이벤트만 연결 (사실상 TX_SIGN만)
  - Zone 간 교차 검증은 AuditSyncPayload(Plan 02)에서 설계

해시 체인의 변조 탐지 원리: - 중간 레코드 하나를 변조하면, 해당 레코드의 CBOR 직렬화 해시가 변경된다 - 다음 레코드의 prev_hash와 불일치가 발생한다 - 연쇄적으로 이후 모든 레코드와 불일치한다 - SE의 latest_log_hash(SEAuditDigest)와 최종적으로 불일치한다 - 따라서 SE 해시 앵커를 변조하지 않는 한, 어떤 중간 레코드도 변조 불가하다


3. 이벤트 타입 카탈로그

3.1. 이벤트 타입 열거형

EventType = &(
    ; === A. 트랜잭션 생명주기 (6개) ===
    event-tx-create:     0x0101,
    event-tx-approve:    0x0102,
    event-tx-reject:     0x0103,
    event-tx-sign:       0x0104,
    event-tx-broadcast:  0x0105,
    event-tx-confirm:    0x0106,

    ; === B. 정책/RBAC 변경 (4개) ===
    event-policy-update:  0x0201,
    event-role-assign:    0x0202,
    event-role-revoke:    0x0203,
    event-quorum-change:  0x0204,

    ; === C. 키 관리 (3개) ===
    event-key-generate:   0x0301,
    event-key-backup:     0x0302,
    event-key-recovery:   0x0303,

    ; === D. 시스템/보안 (6개) ===
    event-auth-success:   0x0401,
    event-auth-failure:   0x0402,
    event-session-start:  0x0403,
    event-session-end:    0x0404,
    event-sync-complete:  0x0405,
    event-security-event: 0x0406,
)

3.2. 페이로드 타입별 분기

EventPayload = (
    TxCreatePayload //
    TxApprovePayload //
    TxRejectPayload //
    TxSignPayload //
    TxBroadcastPayload //
    TxConfirmPayload //
    PolicyUpdatePayload //
    RoleAssignPayload //
    RoleRevokePayload //
    QuorumChangePayload //
    KeyGeneratePayload //
    KeyBackupPayload //
    KeyRecoveryPayload //
    AuthSuccessPayload //
    AuthFailurePayload //
    SessionStartPayload //
    SessionEndPayload //
    SyncCompletePayload //
    SecurityEventPayload
)

3.3. A. 트랜잭션 생명주기 이벤트 (6개)

; TX_CREATE: 트랜잭션 생성 요청
; Zone: Zone 1 (대시보드) — Operator가 대시보드에서 트랜잭션 생성
TxCreatePayload = {
    tx_hash:       bstr .size 32,       ; 트랜잭션 해시 (SHA-256)
    amount:        uint,                ; 전송량 (최소 단위: satoshi, wei 등)
    destination:   tstr,                ; 수신 주소
    creator_role:  RBACRole,            ; 생성자 역할
    vault_id:      bstr .size 16,       ; Vault 식별자
    chain:         tstr,                ; 블록체인 네트워크 ("BTC", "ETH" 등)
    ? memo:        tstr,                ; 메모 (선택)
}

; TX_APPROVE: 승인자의 트랜잭션 승인
; Zone: Zone 2 (오프라인 앱) — 개인 서명 기기에서 승인
TxApprovePayload = {
    tx_hash:        bstr .size 32,
    approver_role:  RBACRole,           ; 승인자 역할
    quorum_status:  QuorumStatus,       ; 현재 쿼럼 상태
    approval_seq:   uint,               ; 이 승인의 순서 번호
}

QuorumStatus = {
    current:  uint,                     ; 현재 승인 수
    required: uint,                     ; 필요 승인 수 (n-of-m의 n)
    total:    uint,                     ; 전체 승인자 수 (n-of-m의 m)
}

; TX_REJECT: 승인자의 트랜잭션 거부
; Zone: Zone 2 (오프라인 앱)
TxRejectPayload = {
    tx_hash:        bstr .size 32,
    rejector_role:  RBACRole,
    reason_code:    RejectReason,
    ? reason_text:  tstr,               ; 사유 텍스트 (선택)
}

RejectReason = &(
    reject-amount-exceeded: 1,          ; 금액 초과
    reject-policy-violation: 2,         ; 정책 위반
    reject-suspicious-dest: 3,          ; 의심 수신 주소
    reject-operator-judgment: 4,        ; 운영자 판단
    reject-other: 99,
)

; TX_SIGN: SE에서의 트랜잭션 서명
; Zone: Zone 3 (SE) — 에어갭 환경 내 SE에서 서명 수행
TxSignPayload = {
    tx_hash:          bstr .size 32,
    signer_device_id: bstr .size 8,     ; SE 기기 식별자
    sign_counter:     uint,             ; SE 서명 카운터 (단조 증가)
    partial_sig_hash: bstr .size 32,    ; 부분 서명(MuSig2 partial sig) 해시
    ? nonce_commitment: bstr .size 32,  ; MuSig2 nonce commitment (선택)
}

; TX_BROADCAST: 서명 완료 트랜잭션의 네트워크 브로드캐스트
; Zone: Zone 1 (대시보드) — 온라인 환경에서 브로드캐스트
TxBroadcastPayload = {
    tx_hash:          bstr .size 32,
    broadcast_result: BroadcastResult,
    ? chain_tx_id:    tstr,             ; 블록체인 트랜잭션 ID (성공 시)
    ? error_message:  tstr,             ; 오류 메시지 (실패 시)
}

BroadcastResult = &(
    broadcast-success: 1,
    broadcast-rejected: 2,
    broadcast-timeout: 3,
)

; TX_CONFIRM: 블록체인에서 트랜잭션 확인
; Zone: Zone 1 (대시보드) — 블록체인 모니터링
TxConfirmPayload = {
    tx_hash:       bstr .size 32,
    chain_tx_id:   tstr,                ; 블록체인 트랜잭션 ID
    confirmations: uint,                ; 확인 수
    block_height:  uint,                ; 포함된 블록 높이
}

3.4. B. 정책/RBAC 변경 이벤트 (4개)

; POLICY_UPDATE: 정책 변경
; Zone: Zone 1 (대시보드) — 정책 생성은 대시보드, 승인은 Zone 2 쿼럼
PolicyUpdatePayload = {
    policy_version: uint,               ; 정책 버전 번호
    policy_hash:    bstr .size 32,      ; 정책 내용의 SHA-256 해시
    approvers:      [+ bstr .size 8],   ; 승인자 device_id 목록
    change_type:    PolicyChangeType,
    ? prev_policy_hash: bstr .size 32,  ; 이전 정책 해시 (체인 연결)
}

PolicyChangeType = &(
    policy-create: 1,                   ; 신규 정책 생성
    policy-modify: 2,                   ; 기존 정책 수정
    policy-activate: 3,                 ; 정책 활성화
    policy-deactivate: 4,              ; 정책 비활성화
)

; ROLE_ASSIGN: 역할 부여
; Zone: Zone 1 (대시보드) — Org Owner 또는 Vault Admin이 수행
RoleAssignPayload = {
    target_user:   tstr,                ; 대상 사용자 식별자
    assigned_role: RBACRole,            ; 부여되는 역할
    assigner_role: RBACRole,            ; 부여자의 역할
    ? scope:       tstr,                ; 역할 범위 (Vault ID 등)
}

; ROLE_REVOKE: 역할 회수
; Zone: Zone 1 (대시보드)
RoleRevokePayload = {
    target_user:  tstr,
    revoked_role: RBACRole,
    revoker_role: RBACRole,
    ? reason:     tstr,                 ; 회수 사유
}

; QUORUM_CHANGE: 쿼럼 임계값 변경
; Zone: Zone 1 (대시보드) — 쿼럼 승인 후 적용
QuorumChangePayload = {
    vault_id:       bstr .size 16,
    old_threshold:  QuorumStatus,
    new_threshold:  QuorumStatus,
    approvers:      [+ bstr .size 8],   ; 변경 승인자 목록
}

3.5. C. 키 관리 이벤트 (3개)

; KEY_GENERATE: 새 키 쌍 생성
; Zone: Zone 3 (SE) — SE 내부에서 키 생성
KeyGeneratePayload = {
    key_id:     bstr .size 16,          ; 키 식별자
    algorithm:  KeyAlgorithm,           ; 키 알고리즘
    vault_id:   bstr .size 16,          ; 소속 Vault
    ? derivation_path: tstr,            ; BIP-32 유도 경로 (해당 시)
}

KeyAlgorithm = &(
    algo-secp256k1: 1,                  ; Bitcoin, Ethereum
    algo-ed25519: 2,                    ; Solana, Cardano
    algo-p256: 3,                       ; ECDSA P-256 (내부 인증용)
)

; KEY_BACKUP: 키 백업 수행
; Zone: Zone 2 (오프라인 앱) — R3covery 카드 또는 Metal Seed 백업
KeyBackupPayload = {
    key_id:        bstr .size 16,
    backup_method: BackupMethod,
    backup_hash:   bstr .size 32,       ; 백업 데이터의 SHA-256 (내용 자체는 미포함)
    ? backup_location: tstr,            ; 백업 위치 설명 (선택)
}

BackupMethod = &(
    backup-r3covery-card: 1,            ; R3covery 카드 (SLIP-39)
    backup-metal-seed: 2,               ; 금속 시드 플레이트
    backup-shamir-split: 3,             ; Shamir 비밀 공유
)

; KEY_RECOVERY: 키 복구 수행
; Zone: Zone 2 (오프라인 앱)
KeyRecoveryPayload = {
    key_id:           bstr .size 16,
    recovery_method:  BackupMethod,     ; 복구에 사용된 방법
    recovery_result:  RecoveryResult,
}

RecoveryResult = &(
    recovery-success: 1,
    recovery-partial: 2,                ; 부분 복구 (추가 조각 필요)
    recovery-failed: 3,
)

3.6. D. 시스템/보안 이벤트 (6개)

; AUTH_SUCCESS: 인증 성공
; Zone: Zone 1 (대시보드) 또는 Zone 2 (오프라인 앱)
AuthSuccessPayload = {
    user_id:     tstr,                  ; 사용자 식별자
    auth_method: AuthMethod,
    ip_or_device: tstr,                 ; IP 주소 또는 기기 식별 (Zone 1: IP, Zone 2: device)
}

AuthMethod = &(
    auth-password: 1,
    auth-mfa-totp: 2,                   ; TOTP 기반 MFA
    auth-biometric: 3,                  ; 생체 인증 (오프라인 앱)
    auth-pin: 4,                        ; SE PIN 인증
    auth-hardware-key: 5,              ; 하드웨어 키 (FIDO2)
)

; AUTH_FAILURE: 인증 실패
; Zone: Zone 1 (대시보드) 또는 Zone 2 (오프라인 앱)
AuthFailurePayload = {
    user_id:       tstr,
    auth_method:   AuthMethod,
    failure_reason: AuthFailureReason,
    attempt_count: uint,                ; 연속 실패 횟수
}

AuthFailureReason = &(
    auth-fail-wrong-password: 1,
    auth-fail-wrong-pin: 2,
    auth-fail-expired-token: 3,
    auth-fail-revoked-access: 4,
    auth-fail-biometric-mismatch: 5,
    auth-fail-locked-account: 6,
)

; SESSION_START: 서명 세션 또는 관리 세션 시작
; Zone: Zone 2 (오프라인 앱) — 서명 세션 시작
SessionStartPayload = {
    session_type: SessionType,
    participants: [+ bstr .size 8],     ; 참여자 device_id 목록
    ? tx_hash:    bstr .size 32,        ; 서명 세션이면 대상 트랜잭션 해시
}

SessionType = &(
    session-signing: 1,                 ; 서명 세션
    session-admin: 2,                   ; 관리 세션 (정책 변경 등)
    session-recovery: 3,               ; 복구 세션
)

; SESSION_END: 세션 종료
; Zone: Zone 2 (오프라인 앱)
SessionEndPayload = {
    session_id:    bstr .size 16,
    duration:      uint,                ; 세션 지속 시간 (초)
    records_count: uint,                ; 세션 중 생성된 감사 레코드 수
    ? outcome:     tstr,                ; 세션 결과 요약
}

; SYNC_COMPLETE: 에어갭 동기화 완료
; Zone: Zone 1 (대시보드) — AuditSyncPayload 수신 후 기록
SyncCompletePayload = {
    sync_payload_hash: bstr .size 32,   ; 수신한 AuditSyncPayload의 해시
    records_synced:    uint,            ; 동기화된 레코드 수
    gaps_detected:     bool,            ; 시퀀스 갭 감지 여부
    ? gap_ranges:      [* GapRange],    ; 감지된 갭 범위 (gaps_detected = true 시)
}

GapRange = {
    expected_start: uint,               ; 기대 시퀀스 시작
    expected_end:   uint,               ; 기대 시퀀스 끝
}

; SECURITY_EVENT: 보안 이벤트
; Zone: 모든 Zone — 이상 탐지 시 발생
SecurityEventPayload = {
    event_class:  SecurityClass,
    severity:     Severity,
    details:      tstr,                 ; 이벤트 상세 설명
    ? affected_resources: [* tstr],     ; 영향 받는 리소스 목록
}

SecurityClass = &(
    sec-intrusion-attempt: 1,           ; 침입 시도
    sec-anomaly-detected: 2,            ; 이상 행동 감지
    sec-tampering-detected: 3,          ; 변조 시도 감지
    sec-hash-chain-break: 4,            ; 해시 체인 단절
    sec-counter-mismatch: 5,            ; 서명 카운터 불일치
    sec-policy-violation: 6,            ; 정책 위반
)

Severity = &(
    severity-critical: 1,               ; 즉시 대응 필요
    severity-high: 2,                   ; 신속 대응 필요
    severity-medium: 3,                 ; 일반 대응
    severity-low: 4,                    ; 모니터링
)

4. Zone별 로그 생성 규칙

4.1. Zone별 이벤트 매핑

Zone 생성 이벤트 설명
Zone 1 (대시보드) TX_CREATE, TX_BROADCAST, TX_CONFIRM, AUTH_SUCCESS, AUTH_FAILURE, SYNC_COMPLETE, SECURITY_EVENT 온라인 환경 이벤트. 트랜잭션 생성과 브로드캐스트, 사용자 인증, 동기화 수신
Zone 2 (오프라인 앱) TX_APPROVE, TX_REJECT, SESSION_START, SESSION_END, KEY_BACKUP, KEY_RECOVERY, POLICY_UPDATE(승인), ROLE_ASSIGN, ROLE_REVOKE, QUORUM_CHANGE, AUTH_SUCCESS, AUTH_FAILURE, SECURITY_EVENT 에어갭 구간 이벤트. 승인/거부, 세션 관리, 키 백업/복구
Zone 3 (SE) TX_SIGN, KEY_GENERATE SE 내부 이벤트. 서명 수행과 키 생성만. SE는 상세 로그를 저장하지 않으며, SEAuditDigest(128B)로 해시 앵커 역할만 수행

4.2. Zone 3 (SE) 제한 사항

SE는 감사 로그 시스템에서 다음 역할만 수행한다:

SE가 하는 것: - TX_SIGN 이벤트 발생 시 sign_counter 증가 - latest_sign_hash에 서명 대상 트랜잭션 해시 기록 - latest_log_hash에 오프라인 앱이 제공한 동기화 배치 해시 저장 - digest_sig로 SEAuditDigest 전체를 서명

SE가 하지 않는 것: - AuditRecord의 상세 필드(payload, actor 등) 저장 - 이벤트 필터링, 검색, 정렬 - 보고서 생성 - 해시 체인 전체 저장 (앵커 해시 1개만)

이 제한은 EAL5+ SE의 연산/저장 자원 제약과 에어갭 보안 원칙을 따른다. 상세 로그는 Zone 2(오프라인 앱)와 Zone 1(대시보드)에서 관리한다.

4.3. 서명 규칙

Zone 서명 여부 서명 키 목적
Zone 1 선택 (서버 서명) 대시보드 서버 키 서버 무결성 증명 (HSM 기반)
Zone 2 필수 오프라인 앱 키 에어갭 구간 레코드 무결성
Zone 3 필수 (SEAuditDigest 내) SE audit_key (P-256) 하드웨어 레벨 앵커 무결성

5. 해시 체인 구조

5.1. Zone별 독립 체인

각 Zone은 독립적인 해시 체인을 유지한다. 이는 에어갭으로 인해 Zone 간 실시간 해시 연결이 불가능하기 때문이다.

Zone 1 해시 체인:
  [Genesis_Z1] -> [TX_CREATE_1] -> [TX_BROADCAST_1] -> [AUTH_SUCCESS_1] -> ...
     prev_hash=0     prev_hash=H(G)   prev_hash=H(TC1)  prev_hash=H(TB1)

Zone 2 해시 체인:
  [Genesis_Z2] -> [TX_APPROVE_1] -> [SESSION_START_1] -> [TX_REJECT_1] -> ...
     prev_hash=0     prev_hash=H(G)   prev_hash=H(TA1)   prev_hash=H(SS1)

Zone 3 해시 체인:
  [Genesis_Z3] -> [TX_SIGN_1] -> [TX_SIGN_2] -> [KEY_GENERATE_1] -> ...
     prev_hash=0     prev_hash=H(G)  prev_hash=H(TS1)  prev_hash=H(TS2)

5.2. Zone 간 교차 검증

Zone 간 해시 체인의 교차 검증은 AuditSyncPayload(Plan 02)를 통해 수행된다: - Zone 2 -> Zone 1 동기화 시: Zone 2 해시 체인의 배치 해시가 AuditSyncPayload에 포함 - Zone 3 -> Zone 2: SEAuditDigest의 latest_log_hash가 Zone 2 배치 해시와 일치해야 함 - Zone 1에서 전체 교차 검증: 세 Zone의 해시 앵커 일관성을 최종 확인

상세 교차 검증 프로토콜은 Plan 02 audit-sync-integrity-chain.md에서 설계한다.


6. 보존 기간 정책

6.1. 3단계 아카이빙 구조

┌─────────────────────────────────────────────────────────────┐
│                    3단계 아카이빙 구조                         │
├──────────────┬──────────────┬───────────────────────────────┤
│  활성 저장소   │  아카이브      │  영구 보존                     │
│  (Active)     │  (Archive)    │  (Permanent)                  │
├──────────────┼──────────────┼───────────────────────────────┤
│  최근 1년     │  1-5년/1-10년  │  무기한                       │
│  전체 레코드   │  전체 레코드    │  SE 해시 앵커만                │
│  빠른 조회     │  압축 저장      │  SEAuditDigest 스냅샷         │
│  Zone 1 DB    │  Cold Storage  │  SE NVM + Zone 1 보관          │
└──────────────┴──────────────┴───────────────────────────────┘

6.2. 관할별 보존 파라미터

관할 활성 저장 아카이브 기간 영구 보존 추가 요건 규제 근거
한국 1년 5년 SE 해시 앵커 접근 기록 최소 6개월 (REG-KR-15) REG-KR-08, REG-KR-15
EU 1년 5년 SE 해시 앵커 NCA 접근 가능 형식 출력 REG-EU-03
일본 1년 10년 SE 해시 앵커 자금결제법 장기 보존 REG-JP-02
싱가포르 1년 5년 SE 해시 앵커 AML/CFT 요건 충족 REG-SG-02
미국 1년 5년 (기본) SE 해시 앵커 NY BitLicense 적용 시 7년 REG-US-03/04

6.3. 아카이빙 전환 규칙

활성 -> 아카이브 전환:
  - 트리거: timestamp가 현재 시점 - 1년 이전
  - 처리: CBOR 압축 + 암호화(AES-256-GCM) + 해시 무결성 태그
  - 검증: 전환 전/후 해시 체인 무결성 확인

아카이브 -> 삭제:
  - 트리거: timestamp가 관할별 보존 기간 초과
  - 처리: 안전 삭제 (secure wipe)
  - 예외: SE 해시 앵커(SEAuditDigest 스냅샷)는 영구 보존
  - GDPR 대응: 가명 처리(pseudonymization) 후 보존 (DELTA-EU-03)

GDPR 가명처리 메커니즘:
  - actor.user_id -> 단방향 해시로 대체
  - AuditRecord의 구조와 해시 체인은 유지
  - 가명처리 이전 원본 매핑 테이블은 삭제
  - Art. 17(3)(b) 법률 의무 예외: 감사 로그 자체는 보존 의무가 삭제권에 우선

7. 기존 설계 매핑

7.1. AC-ID 관계

AC-ID 기존 설명 이번 설계로 구체화
AC-AU-01 변조 불가 감사 로그 (Design) AuditRecord CDDL + prev_hash 해시 체인 + Zone별 서명으로 구체화
AC-AU-03 로그 보존 정책 5년 (Design) 3단계 아카이빙(활성 1년/아카이브 5-10년/영구) + 관할별 파라미터로 확장
CORE-03 감사 로그 장기 보존 AuditRecord 보존 기간 정책으로 구현
CORE-04 변조 불가 감사 로그 해시 체인 + SE 앵커 + 로컬 서명으로 3중 보호

7.2. v0.5 RBAC v2 연동

AuditRecord의 actor.role 필드는 v0.5에서 정의된 RBAC v2 6역할 체계를 직접 참조한다:

RBAC 역할 주요 감사 이벤트 설명
Org Owner ROLE_ASSIGN, ROLE_REVOKE, QUORUM_CHANGE 조직 수준 권한 변경
Vault Admin POLICY_UPDATE, QUORUM_CHANGE Vault 정책 관리
Policy Admin POLICY_UPDATE 정책 규칙 변경
Operator TX_CREATE, TX_APPROVE, TX_SIGN 트랜잭션 운영
Viewer AUTH_SUCCESS 읽기 전용 접근
Auditor AUTH_SUCCESS, 전체 레코드 조회 감사 목적 접근

7.3. Plan 02 연결점

본 문서에서 정의한 AuditRecord 스키마는 Plan 02의 다음 설계의 기반이 된다: - AuditSyncPayload: AuditRecord 배열을 압축하여 에어갭 전달 (CompactAuditRecord) - 3계층 무결성 체인: Zone별 해시 체인의 교차 검증 메커니즘 - Proof of Cold Storage: TX_SIGN의 sign_counter를 기반으로 콜드 서명 건수 증명


Phase: 30-audit-architecture Version: 1.0 규제 기준일: 2026-03 (CORE-03/04, REG-KR-08/14, REG-EU-03, REG-JP-02 기준)


관련 문서