OTP 게이팅 및 비상 정지
민감한 작업에 대한 TOTP 게이팅과 OTP 게이팅 재개 기능이 포함된 비상 정지 레벨 설명.
Revka는 고위험 에이전트 작업을 위한 두 가지 상호 보완적인 제어 수단을 제공합니다. OTP 게이팅([security.otp])은 민감한 도구와 도메인을 게이팅하도록 설정하는 TOTP 기반 두 번째 인증 요소입니다 — 현재 구현에서는 OTP 검증이 비상 정지 재개 기능에 연결되어 있습니다. 비상 정지([security.estop])는 킬 스위치입니다. 재시작 후에도 정지 상태를 유지하며, 원하는 경우 동일한 OTP를 통해서만 재개할 수 있습니다.
OTP 게이팅은 에이전트가 대부분의 경우 자율적으로 동작하되, 정해진 작업(셸, 파일 쓰기, 금융 도메인 등)에서는 사람의 확인을 거치도록 하고 싶을 때 사용하십시오. 비상 정지는 무언가 잘못되었거나 잘못될 가능성이 있을 때, 지금 당장 에이전트를 멈추고 의도적으로 해제해야 할 때 사용하십시오.
두 기능 모두 기본적으로 비활성화되어 있습니다. 이 페이지에서는 등록, 설정, 네 가지 estop 레벨, OTP 게이팅 재개 흐름, 그리고 이 모든 것을 뒷받침하는 fail-closed 설계를 설명합니다.
TOTP OTP 게이팅
섹션 제목: “TOTP OTP 게이팅”OTP 게이팅은 표준 TOTP(RFC 6238) 코드를 사용합니다 — 모든 인증 앱이 생성하는 것과 동일한 방식이므로 Google Authenticator, 1Password, Aegis 등 어떤 TOTP 앱이든 두 번째 인증 요소로 사용할 수 있습니다. 현재 구현에서는 OTP 검증이 비상 정지 재개 기능에 연결되어 있습니다(OTP 게이팅 재개 참조). gated_actions, gated_domains, gated_domain_categories 설정 키는 시작 시 파싱 및 검증되지만, 런타임에서 도구나 도메인 접근을 아직 게이팅하지는 않습니다.
동작 방식
섹션 제목: “동작 방식”- 최초 사용 시 20바이트 시크릿이 생성되고, base32로 인코딩되어 시크릿 저장소를 통해 암호화된 후
~/.revka/otp-secret에0600권한으로 기록됩니다. - 코드는 6자리입니다. 검증 시 현재 30초 스텝 및 앞뒤 한 스텝씩(±1)을 허용하여 Revka와 기기 간의 시계 오차를 수용합니다.
- 검증에 성공한 코드는
cache_valid_secs동안 캐시되므로, 단일 코드로 짧은 시간 동안 연속된 게이팅 작업을 매번 재입력 없이 승인할 수 있습니다. 만료된 캐시 항목은 다음 검증 시 정리됩니다. - 시크릿은 유지되므로 데몬을 재시작해도 재등록이 필요하지 않습니다.
기기 등록
섹션 제목: “기기 등록”OTP를 활성화한 상태에서 시크릿 파일이 아직 없으면 Revka가 시크릿을 생성하고 otpauth:// 등록 URI를 한 번 출력합니다. 인증 앱으로 해당 URI를 스캔하십시오.
-
~/.revka/config.toml에서 OTP를 활성화합니다:[security.otp]enabled = true -
데몬을 시작합니다. 최초 실행 시 Revka가 다음 형식의 등록 URI를 출력합니다:
otpauth://totp/Revka:revka?secret=BASE32SECRET&issuer=Revka&period=30 -
TOTP 앱으로 URI(또는 QR 코드)를 스캔합니다. 이후 앱에서
token_ttl_secs초마다 새로운 6자리 코드가 생성됩니다.
[security.otp] 설정
섹션 제목: “[security.otp] 설정”[security.otp]enabled = truemethod = "totp"token_ttl_secs = 30cache_valid_secs = 300gated_actions = ["shell", "file_write", "browser_open", "browser"]gated_domains = ["*.chase.com", "accounts.google.com"]gated_domain_categories = ["banking"]challenge_max_attempts = 3| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
enabled | bool | false | OTP 게이팅 마스터 스위치. |
method | string | "totp" | OTP 방식. 현재는 totp만 구현되어 있으며, pairing과 cli-prompt는 향후 사용을 위해 예약되어 있습니다. |
token_ttl_secs | u64 | 30 | TOTP 시간 스텝(주기, 초 단위). 0보다 커야 합니다. |
cache_valid_secs | u64 | 300 | 검증된 코드가 유효한 상태로 유지되는 시간(초). token_ttl_secs 이상이어야 합니다. |
gated_actions | list | ["shell", "file_write", "browser_open", "browser"] | OTP가 필요한 도구/액션 이름 목록. 각 항목은 영숫자, _, -만 허용됩니다. |
gated_domains | list | [] | OTP가 필요한 도메인 패턴 목록. * 와일드카드를 지원합니다(예: *.chase.com). |
gated_domain_categories | list | [] | 게이팅 도메인으로 확장되는 프리셋 카테고리 이름: banking, medical, government, identity_providers. |
challenge_max_attempts | u32 | 3 | 챌린지 잠금 전 허용되는 최대 OTP 실패 횟수. 0보다 커야 합니다. |
게이팅 도메인 카테고리
섹션 제목: “게이팅 도메인 카테고리”민감한 도메인을 일일이 나열하는 대신, gated_domain_categories에 프리셋을 하나 이상 설정하면 Revka가 해당 카테고리를 게이팅 도메인 집합으로 확장합니다:
| 카테고리 | 포함 범위 |
|---|---|
banking | 금융 및 은행 도메인 |
medical | 의료 및 진료 기록 도메인 |
government | 정부 서비스 도메인 |
identity_providers | ID 제공자 / SSO 로그인 도메인 |
카테고리와 명시적 gated_domains는 합산 적용됩니다 — 둘 다 함께 사용하십시오. 알 수 없는 카테고리 이름은 시작 시 거부됩니다.
비상 정지 (Estop)
섹션 제목: “비상 정지 (Estop)”비상 정지는 운영자의 킬 스위치입니다. 비상 정지를 작동하면 명시적으로 재개하기 전까지 데몬 재시작 후에도 유지되는 상태 파일이 기록됩니다. 현재 구현에서는 지속된 상태를 revka estop status로 확인할 수 있지만, 에이전트 루프, 도구 실행 경로, 네트워크 레이어에서 작업 전에 아직 참조하지는 않습니다. 에이전트가 제어 불능 상태가 되었을 때 가장 먼저 사용해야 할 수단입니다.
네 가지 estop 레벨
섹션 제목: “네 가지 estop 레벨”Estop은 전부 아니면 전무 방식이 아닙니다. 동결 범위를 선택할 수 있으며, 레벨은 중첩됩니다 — 여러 레벨을 동시에 적용하면 제한이 쌓이고, 하나씩 개별적으로 해제할 수 있습니다.
| 레벨 | CLI 레벨 이름 | 의도된 효과 (상태 유지됨; 런타임 적용 미구현) |
|---|---|---|
| 전체 중단 | kill-all | 모든 에이전트 실행을 중단할 예정입니다. |
| 네트워크 차단 | network-kill | 모든 외부 네트워크 접근을 차단할 예정입니다. |
| 도메인 차단 | domain-block | 특정 도메인을 차단할 예정입니다. 와일드카드 패턴을 지원합니다(예: *.chase.com). |
| 도구 동결 | tool-freeze | 이름으로 특정 도구를 동결할 예정입니다. |
차단된 도메인 및 동결된 도구 목록은 쓰기 시 정규화됩니다(소문자 변환, 공백 제거, 중복 제거, 정렬). 도메인 패턴은 정책 엔진의 다른 곳과 동일한 방식으로 검증되며, 도구 이름은 영숫자, _, -만 허용됩니다.
CLI에서 적용 및 재개
섹션 제목: “CLI에서 적용 및 재개”# 적용 (kill-all이 기본 레벨)revka estoprevka estop --level network-killrevka estop --level domain-block --domain "*.chase.com"revka estop --level tool-freeze --tool shell
# 현재 상태 확인revka estop status
# 재개 — 특정 레벨 해제, 또는 kill-all 해제revka estop resume # kill-all 해제revka estop resume --network # 네트워크 차단 해제revka estop resume --domain "*.chase.com" # 특정 도메인 차단 해제revka estop resume --tool shell # 도구 동결 해제revka estop resume --otp 123456 # OTP가 필요한 경우 코드 입력레벨은 중첩되므로, 하나를 해제해도 나머지는 그대로 유지됩니다. 예를 들어 도메인 차단을 재개해도 네트워크 차단은 명시적으로 해제하기 전까지 계속 적용됩니다.
[security.estop] 설정
섹션 제목: “[security.estop] 설정”[security.estop]enabled = truestate_file = "~/.revka/estop-state.json"require_otp_to_resume = true| 키 | 타입 | 기본값 | 설명 |
|---|---|---|---|
enabled | bool | false | 비상 정지 제어 마스터 스위치. |
state_file | string | "~/.revka/estop-state.json" | 지속적인 estop 상태가 저장되는 경로. 틸드(~) 확장을 지원하며, 상대 경로는 설정 디렉터리를 기준으로 해석됩니다. 비워둘 수 없습니다. |
require_otp_to_resume | bool | true | true로 설정하면 estop 레벨을 해제할 때 유효한 OTP 코드가 필요합니다. |
상태 파일 형식
섹션 제목: “상태 파일 형식”상태는 JSON으로 직렬화되어 원자적으로 기록됩니다(임시 파일 + 이름 변경, Unix에서 0600 권한):
{ "kill_all": false, "network_kill": false, "blocked_domains": ["*.chase.com"], "frozen_tools": ["shell"], "updated_at": "2026-06-18T10:00:00Z"}일반적으로 이 파일을 직접 편집할 필요가 없습니다 — 검증과 정규화가 실행되도록 revka estop을 사용하십시오. 런타임은 kill_all이 설정되어 있거나, network_kill이 설정되어 있거나, 두 목록 중 하나라도 비어 있지 않으면 estop이 적용 중인 것으로 판단합니다.
OTP 게이팅 재개
섹션 제목: “OTP 게이팅 재개”두 기능은 재개 시점에서 연결됩니다. [security.estop].require_otp_to_resume = true로 설정하면 유효한 OTP 코드 없이는 어떤 estop 레벨도 해제할 수 없습니다:
-
에이전트가 제어 불능 상태가 되었거나 그럴 가능성이 있습니다. 정지를 적용합니다:
Terminal window revka estop --level kill-all -
나중에 재개를 결정합니다. 코드 없이 재개를 시도하면 거부됩니다:
Terminal window revka estop resume# error: OTP code is required to resume estop state -
인증 앱에서 현재 코드를 확인하고 입력합니다:
Terminal window revka estop resume --otp 123456코드는 액션 게이팅에 사용되는 것과 동일한 TOTP 시크릿으로 검증됩니다(±1 스텝 허용). 잘못되거나 비어 있는 코드는 거부되고(
Invalid OTP code; estop resume denied) 정지 상태가 유지됩니다.
Fail-closed 설계
섹션 제목: “Fail-closed 설계”비상 정지는 안전하게 실패하도록 설계되었습니다. 상태 파일이 존재하지만 읽거나 파싱할 수 없는 경우 — 손상, 잘림, 잘못된 수동 편집 등 — Revka는 이를 무시하고 계속 실행하지 않습니다. 대신 fail-closed 상태로 진입합니다: kill_all = true. 손상된 킬 스위치는 “계속 진행”이 아닌 “모두 중단”으로 처리됩니다.
- 상태 파일이 없으면 정지가 적용되지 않은 것으로 간주합니다(정상적인 초기 상태).
- 읽을 수 없거나 파싱할 수 없는 상태 파일은
kill_all = true를 의미하며, fail-closed 상태가 다시 기록되어revka estop status에서 명시적으로 확인할 수 있습니다. - fail-closed 상태는 유지되며
revka estop status에서 확인할 수 있습니다. 현재 게이트웨이 요청은 estop 상태에 의해 게이팅되지 않지만, 운영자가 명시적으로 정지를 확인하고 재개할 수 있습니다.
이는 모호한 보안 상태는 안전한 선택으로 해석된다는 Revka의 광범위한 원칙을 반영합니다. OTP 게이팅 재개와 결합하면, 제어 불능이 되거나 변조된 에이전트가 조용히 스스로를 다시 온라인 상태로 만들 수 없습니다.