콘텐츠로 이동

보안 모델

정책 엔진부터 OS 샌드박싱, 암호화, 감사 로그까지 — Revka의 심층 방어 보안 레이어.

Revka는 설계 단계부터 감사 우선 원칙을 따릅니다. 에이전트 도구가 실행되기 전, 모든 작업은 독립적으로 중첩된 보안 레이어를 통과합니다 — 정책 엔진, OS 수준 샌드박싱, 암호화된 자격 증명 저장소, 그리고 위변조 방지 감사 로그가 그것입니다. 이 페이지에서는 각 레이어의 역할, 상호 구성 방식, 설계 철학, 그리고 취약점 신고 방법을 설명합니다.

이 페이지를 읽으면 보안 적용 지점과 위협 프로파일에 맞게 조정할 수 있는 설정이 어디에 있는지 파악할 수 있습니다. 복사·붙여넣기 가능한 설정 예시와 명령어 레퍼런스는 아래 링크를 통해 전용 보안 섹션을 참고하세요.

모든 방어 수단은 도구 실행이 허용되기 전에 평가되며, 단일 우회 수단으로는 모델 전체를 무력화할 수 없습니다 — 명령은 자율성 게이트, 허용 목록, 위험 분류, 경로 샌드박싱, 속도 제한을 모두 통과한 뒤 OS 샌드박스 내에서 실행되며, 전체 턴은 추가 전용 감사 로그에 기록됩니다.

정책 엔진

SecurityPolicy는 자율성 수준, 따옴표 인식 셸 파서를 갖춘 명령 허용 목록, 위험 분류, 작업 공간 경계, 슬라이딩 윈도우 속도 제한기를 강제 적용합니다.

OS 샌드박싱

선택적 커널/사용자 공간 격리 백엔드(Firejail, Bubblewrap, Landlock, sandbox-exec, Docker)가 명령 실행을 감싸며, 시작 시 자동으로 감지됩니다.

암호화 & 인증

시크릿은 ChaCha20-Poly1305로 저장 시 암호화되고, 페어링 토큰은 SHA-256으로 해시되며, 베어러 토큰이 게이트웨이 API를 보호합니다.

감사 & 격리

위변조 방지 머클 감사 로그가 모든 이벤트를 기록하며, 긴급 정지, OTP 게이팅, 신뢰 점수가 오작동하는 에이전트를 실시간으로 격리합니다.

이 모델은 에이전트의 세 가지 고위험 장애 모드를 방어합니다: 비인가 셸 실행(rm -rf /, curl | sh), 작업 공간 탈출(경로 순회, 심볼릭 링크, 절대 경로), LLM API 호출로 인한 비용 폭주.

아래 레이어는 가장 안쪽 정책 검사에서 바깥쪽 순서로 나열되어 있습니다. 각 레이어는 독립적이며, 도구 호출은 모든 레이어를 통과해야 합니다.

정책 엔진의 진입점은 에이전트가 실제로 작동할 수 있는지를 제어하는 3단계 자율성 모드입니다. 현재 수준은 LLM 시스템 프롬프트에 자동으로 주입됩니다.

수준동작
read_only관찰 전용 — ls/cat 같은 안전한 읽기 포함 모든 도구 작업 차단. 신뢰할 수 없는 채널에 가장 안전한 선택.
supervised기본값. 허용 목록 범위 내에서 동작하며, 중간 및 고위험 명령은 명시적 승인(approved = true)이 필요합니다.
full승인 게이트 없음. 단, 명령 허용 목록과 작업 공간 경계는 여전히 적용됩니다.
[autonomy]
level = "supervised" # read_only | supervised | full

모든 셸 명령은 실행 전에 명시적 허용 목록과 대조하여 검사됩니다. 따옴표 인식 렉서가 복합 입력을 따옴표 없는 ;, |, &&, ||, 개행 기준으로 분리한 뒤 각 하위 명령을 독립적으로 검증합니다 — 따라서 체이닝으로 차단된 명령을 게이트 뒤로 밀수할 수 없습니다.

[autonomy]
allowed_commands = ["git", "npm", "cargo", "ls", "cat", "grep", "find",
"echo", "pwd", "wc", "head", "tail", "python", "node"]

5개의 독립 게이트가 순서대로 실행됩니다:

  1. 서브셸 연산자 — 백틱, $(...), 프로세스 치환 <(...) / >(...) 거부.
  2. 리다이렉션<> 거부.
  3. tee — 허용 목록 여부와 관계없이 항상 차단(임의 파일에 씁니다).
  4. 백그라운드 & — 단일 후행 & 거부.
  5. 세그먼트별 허용 목록 — 분리된 각 하위 명령이 베이스네임, 전체 경로, 또는 와일드카드 "*"로 일치해야 합니다.

허용 목록 항목은 베이스네임(베이스네임 일치), 전체 경로(예: /usr/bin/antigravity, 정확히 일치), 또는 "*"일 수 있습니다. "*"를 사용하더라도 위험한 인수 패턴은 차단 상태를 유지합니다: find -exec, find -ok, git config, git -c, git alias.

각 명령 — 그리고 복합 명령의 각 세그먼트 — 은 낮음/중간/높음 위험으로 분류되며, 모든 세그먼트 중 가장 높은 분류가 적용됩니다.

위험예시기본 처리
높음rm, dd, mkfs, sudo, su, chmod, chown, mount, iptables, curl, wget, nc, ssh, scp; Windows del, format, reg, net, runas, powershell명시적 허용 목록 등록 없이 차단
중간git 상태 변경(commit, push, reset, rebase, checkout); npm/cargo install/publish; mkdir, mv, cp, lnsupervised 모드에서 승인 필요
낮음ls, cat, grep, pwd, echo, date허용(허용 목록 적용)
[autonomy]
block_high_risk_commands = true # default
require_approval_for_medium_risk = true # default

4. 경로 샌드박싱 & 작업 공간 경계

섹션 제목: “4. 경로 샌드박싱 & 작업 공간 경계”

6개의 독립 검사가 파일 작업을 작업 공간 내에 유지하며, 심볼릭 링크 탈출을 차단하는 정규화 이후 검사도 포함됩니다:

  1. 널 바이트 삽입 거부.
  2. .. 컴포넌트 순회 거부.
  3. URL 인코딩 순회(..%2f) 거부.
  4. ~user 틸드 확장 거부.
  5. 작업 공간 전용 절대 경로 잠금 — 절대 경로는 workspace_dir 또는 allowed_roots 하위에 있어야 합니다.
  6. 금지 접두사 차단 목록(/etc, /root, ~/.ssh, ~/.aws, …).
[autonomy]
workspace_only = true # default
allowed_roots = ["/data/shared", "~/projects/other"]
forbidden_paths = ["/etc", "/root", "~/.ssh", "~/.aws", "~/.config"]

작업 공간과 allowed_rootsforbidden_paths보다 먼저 검사됩니다. 따라서 금지된 트리 내에 중첩된 작업 공간(예: /home이 금지된 상황에서 /home 하위에 있는 작업 공간)도 허용됩니다. Revka 자체의 런타임 설정 파일(config.toml, active_workspace.toml)은 에이전트 수정으로부터 별도로 보호되며, 이 보호는 자동으로 적용되고 재정의할 수 없습니다.

슬라이딩 1시간 윈도우가 에이전트가 실행할 수 있는 Act 유형 작업 수를 제한하고, 별도의 일일 한도가 LLM 지출을 제한합니다. 읽기 작업은 속도 제한을 받지 않습니다.

타입기본값의미
max_actions_per_houru3220인메모리 슬라이딩 윈도우; 데몬 재시작 시 초기화
max_cost_per_day_centsu32500일일 LLM 지출 한도(US$5.00)
[autonomy]
max_actions_per_hour = 20
max_cost_per_day_cents = 500

애플리케이션 레이어 정책 위에, 명령 실행을 OS 격리 백엔드로 감쌀 수 있습니다. 자동 감지가 시작 시 가장 적합한 백엔드를 선택하며, 요청한 백엔드를 사용할 수 없으면 Revka는 경고와 함께 no-op 샌드박스로 폴백합니다.

백엔드플랫폼비고
firejailLinux사용자 공간, 루트 불필요. 설정이 가장 간단합니다.
bubblewrapLinux/macOS사용자 네임스페이스 컨테이너(feature sandbox-bubblewrap).
landlockLinux 5.13+커널 강제 파일시스템 제한; 가장 강력한 격리(feature sandbox-landlock).
sandbox-execmacOSApple Seatbelt 프로파일.
docker전체컨테이너 격리; 스폰 오버헤드 추가.
none전체애플리케이션 레이어 전용; 항상 사용 가능한 폴백.
[security.sandbox]
enabled = true
backend = "auto" # auto | none | firejail | bubblewrap | landlock | sandbox-exec | docker

모든 보안 관련 이벤트는 JSONL 감사 로그에 추가됩니다. 각 항목은 이전 해시와 항목의 정규화된 JSON을 합산하여 계산한 SHA-256 entry_hash, 단조 증가하는 sequence, 그리고 prev_hash 역방향 링크를 포함하여 머클 체인을 형성합니다. 항목을 수정하면 이후의 모든 해시가 무효화됩니다. 항목은 선택적으로 HMAC-SHA256으로 서명할 수 있습니다.

[audit]
enabled = true # default
log_path = "audit.log" # relative to the revka dir
max_size_mb = 100
sign_events = false # optional HMAC signing

HMAC 서명에는 32바이트 키가 필요하며, 게이트웨이 시작 전에 설정합니다:

Terminal window
export REVKA_AUDIT_SIGNING_KEY="<64 hex chars = 32 bytes>"

게이트웨이 API를 통해 체인을 조회하고 검증합니다:

Terminal window
# Query recent events
curl "http://127.0.0.1:42617/api/audit?limit=50&event_type=command_execution" \
-H "Authorization: Bearer rk_<token>"
# Verify chain integrity (detects tampering)
curl "http://127.0.0.1:42617/api/audit/verify" \
-H "Authorization: Bearer rk_<token>"

GET /api/auditlimit(기본 50, 최대 500), event_type(command_execution, file_access, config_change, auth_success, auth_failure, policy_violation, security_event), since(RFC 3339)를 인수로 받습니다. 로그 교체 시 체인은 제네시스로 초기화되므로, 각 교체된 아카이브는 독립적으로 검증됩니다.

두 가지 암호화 레이어가 자격 증명과 게이트웨이 접근을 보호합니다:

  • 암호화된 시크릿 저장소. 설정에 기록된 API 키와 토큰은 저장 전에 ChaCha20-Poly1305 AEAD로 암호화됩니다. 키는 ~/.revka/.secret_key에 저장된 32바이트 무작위 키(Unix에서 모드 0600; Windows에서 제한된 ACL)를 사용합니다. 암호화된 값은 enc2:<hex> 형태로 표시됩니다. 키 파일을 반드시 백업하세요 — 분실하면 모든 enc2: 값을 복구할 수 없습니다.
  • 기기 페어링 & 베어러 토큰. require_pairing = true(기본값)가 설정된 경우, 첫 시작 시 6자리 일회용 코드가 출력됩니다. 클라이언트는 POST /pair를 통해 이를 rk_ 접두사가 붙은 256비트 베어러 토큰으로 교환합니다. 토큰은 SHA-256 해시로만 저장되며, 5회 연속 실패 시 클라이언트는 5분간 잠깁니다.
[secrets]
encrypt = true # default
[gateway]
require_pairing = true # default
allow_public_bind = false # must be explicit to bind beyond localhost
Terminal window
# Server prints "Pairing code: 123456" on first start
curl -X POST http://127.0.0.1:42617/pair \
-H 'Content-Type: application/json' \
-d '{"code": "123456", "device_name": "My Laptop", "device_type": "cli"}'
# Returns: {"token": "rk_<64 hex chars>"}

세 가지 하위 시스템으로 재시작 없이 오작동하는 에이전트를 격리할 수 있습니다:

  • 긴급 정지(revka estop). 4가지 수준을 갖는 영구 킬 스위치 — kill-all, network-kill, domain-block(글로브 패턴), tool-freeze. 재시작 후에도 상태가 유지되며 페일-클로즈 방식입니다: 상태가 손상되거나 읽을 수 없으면 기본값은 kill_all = true입니다. 재개 시 유효한 OTP를 요구할 수 있습니다.
  • OTP 게이팅. TOTP(RFC 6238) 코드가 특정 도구, 작업, 또는 도메인을 게이팅합니다. 등록 otpauth:// URI는 첫 사용 시 한 번만 표시됩니다.
  • 신뢰 점수. 각 도메인은 0.0–1.0 신뢰 점수를 가지며, 초기값으로 감쇠하고 수정 시 감소하며 성공 시 증가합니다. 회귀 임계값(기본 0.5) 이하로 떨어지면 자율성이 자동으로 한 단계 하향 조정됩니다(full → supervised → read_only).
Terminal window
revka estop # engage kill-all
revka estop --level domain-block --domain "*.chase.com"
revka estop --level tool-freeze --tool shell
revka estop resume --otp 123456 # OTP-gated resume
[security.otp]
enabled = true
gated_actions = ["shell", "file_write", "browser_open"]
gated_domains = ["*.chase.com"]
[security.estop]
enabled = true
require_otp_to_resume = true
[trust]
initial_score = 0.8
regression_threshold = 0.5

두 가지 휴리스틱 스캐너가 에이전트와 외부 세계 사이의 경계를 보호합니다:

  • 프롬프트 인젝션 방어(PromptGuard). 인바운드 메시지를 6가지 카테고리로 스캔합니다 — 시스템 프롬프트 재정의, 역할 혼동, 도구 호출 JSON 인젝션, 시크릿 추출, 명령 인젝션 메타문자, 탈옥 패턴 — Safe, Suspicious, Blocked를 반환합니다. 동작과 민감도를 설정할 수 있습니다.
  • 아웃바운드 유출 감지(LeakDetector). 채널 전달 전에 아웃바운드 콘텐츠를 스캔하여 제공자 API 키, AWS 자격 증명, PEM 개인 키, JWT, 데이터베이스 URL, 고엔트로피 토큰을 찾아 [REDACTED_*] 플레이스홀더로 교체합니다.
[security.prompt_guard]
action = "warn" # warn | block | sanitize
sensitivity = 0.7 # 0.0 lenient — 1.0 strict
[security.leak_detector]
sensitivity = 0.7

이 레이어들이 구현되는 방식을 형성하는 두 가지 설계 원칙이 있습니다.

보안은 이식성을 희생시키지 않습니다. 무거운 보호 기능은 플랫폼별 조건부 컴파일 뒤에 있는 선택적 Cargo 기능 플래그로 제공되므로, 기능이 비활성화되면 해당 코드는 컴파일되지 않아 바이너리 크기 증가가 없습니다. 샌드박스 백엔드는 단일 Sandbox 트레이트 뒤에서 플러그인 방식으로 교체 가능하며(제공자, 채널, 메모리와 동일한 방식), 동일한 바이너리가 Linux(x86_64, ARM, RISC-V), macOS, Windows에서 실행되며 호스트가 지원하는 수준에 맞게 보호 수준을 조정합니다.

Terminal window
# Standard release — application-layer security always on
cargo build --release
# Add a platform sandbox at compile time
cargo build --release --features sandbox-landlock # Linux
cargo build --release --features sandbox-bubblewrap # macOS/Linux

보안은 에어백과 같아야 합니다 — 존재하고, 보호하며, 필요할 때까지 눈에 띄지 않아야 합니다. 온보딩 마법사는 추가 단계를 요구하지 않으며, 직접 커스터마이즈하지 않는 한 config.toml에 보안 섹션을 쓰지 않습니다. 합리적인 기본값(supervised 자율성, 작업 공간 범위 접근, 시크릿 암호화, 자동 감지 샌드박스)이 자동으로 적용됩니다. 고급 사용자는 [autonomy], [security.*], [secrets] 설정 섹션을 통해 명시적 제어를 유지합니다.

위에서 설명한 레이어는 현재 런타임에서 적용됩니다. 일부 관련 기능은 게이팅되거나 단계적으로 제공됩니다:

기능상태
정책 엔진, 명령 허용 목록, 위험 분류, 경로 샌드박싱, 속도 제한현재 제공
감사 로그, 암호화된 시크릿, 기기 페어링, OTP, 긴급 정지, 프롬프트 인젝션 & 유출 감지, 신뢰 점수현재 제공
OS 샌드박스 백엔드(Firejail, Bubblewrap, Landlock, sandbox-exec, Docker)현재 제공, 기능 플래그/자동 감지 뒤에 있음
WebAuthn / FIDO2 게이트웨이 로그인기능 게이팅 — --features webauthn으로 빌드
Nevis IAM(OAuth2/OIDC, FIDO2, 역할 매핑)엔터프라이즈 — 엔터프라이즈 IAM(Nevis) 참고
검증 가능한 인텐트(SD-JWT 상거래 게이팅)고급 — 검증 가능한 인텐트 참고

Revka의 Docker 이미지는 CIS Docker 벤치마크 관행을 따릅니다: 런타임 스테이지는 셸과 패키지 매니저가 없는 distroless nonroot 이미지이며, 컨테이너는 비루트 UID로 실행되고, 읽기 전용 루트 파일시스템을 지원합니다.

제어구현
비루트 사용자UID 65534(distroless nonroot)로 실행
최소 기본 이미지gcr.io/distroless/cc-debian12:nonroot
읽기 전용 파일시스템docker run --read-only/workspace 볼륨
Terminal window
# Verify the image runs as non-root
docker build -t revka .
docker inspect --format='{{.Config.User}}' revka
# Expected: 65534:65534
# Run hardened: read-only root, writable workspace volume
docker run --read-only -v /path/to/workspace:/workspace revka gateway

CI는 컨테이너가 루트로 실행되지 않는지, 런타임 스테이지가 :nonroot 변형을 사용하는지, 명시적인 숫자 USER 지시문이 존재하는지 강제 검사합니다. 배포 가이드는 Docker, Compose & 원클릭 PaaS를 참고하세요.

보안 취약점은 책임감 있게 신고해 주세요 — 공개 GitHub 이슈를 열지 마세요.

  1. GitHub Security Advisories를 통해 비공개 어드바이저리를 열거나, GitHub 비공개 취약점 신고를 통해 관리자에게 연락하세요.

  2. 설명, 재현 단계, 영향 평가, 그리고 가능하다면 수정 제안을 포함해 주세요.

  3. 48시간 이내 확인, 1주일 이내 평가, 심각한 이슈의 경우 2주 이내 수정을 기대하세요.