감사 및 재정의
모든 게이트 결정은 기록됩니다. 신뢰할 수 있는 워크플로는 정책 수준에서 면제할 수 있습니다. 비활성화 스위치는 인시던트 대응을 위해 존재하며, 항상 흔적을 남깁니다.
지난주 월요일에 실행하려던 스크립트가 차단되었습니다. "취소"를 클릭했던 것은 어렴풋이 기억하지만, 정확히 어떤 스크립트였는지 기억나지 않습니다. 또는 처음부터 끝까지 검토를 마친 자동화가 있는데, 실행할 때마다 동일한 확인 질문이 반복되는 상황일 수도 있습니다. 게이트가 그냥 통과시킬 수는 없을까요?
이 페이지에서는 운영자 측의 세 가지 조작 수단을 다룹니다. 과거 결정 조회, 워크플로별 면제 범위 지정, 그리고 긴급 비활성화 스위치입니다.
설계 철학: 가시성, 차단 가능성, 항시 감사
게이트를 통과하는 모든 코드 경로에는 다음 세 가지 속성이 적용됩니다.
- 가시성. 모든 게이트 결정(거부 / 확인 / 허용)은 감사 행을 하나씩 기록합니다. 항상. 운영자는 이를 사후에 조회할 수 있습니다.
- 차단 가능성. 신뢰할 수 있는 워크플로는
script_risk_policy를 통해 특정 스크립트 본문을 사전 승인할 수 있습니다. 단, 면제 자체도 감사 행을 기록합니다. "이 스크립트는 정책에 의해 승인되었다"는 사실과 "이 스크립트는 실제로 정상이었다"는 사실을 구분할 수 있습니다. - 항시 감사. 인시던트 중에
DISABLE_SCRIPT_RISK_GATE=1을 설정하더라도, 우회된 모든 호출은bypassed_by="env_global"으로 표시된 행을 기록합니다. 어떤 사용 패턴도 게이트를 침묵시키지 않습니다.
이러한 구조를 선택한 이유는 무엇인가요? 신뢰는 투명성에서 비롯되며, 최대한 엄격한 제한에서 오지 않습니다. 엄격하기만 한 게이트는 우회의 대상이 됩니다. 사람들이 환경 변수를 설정하고 잊어버리는 것이 그 예입니다. 명확한 우회 경로를 제공하면서 동시에 모든 사용 기록을 남기는 게이트는 유연성(실제 워크플로 배포 가능)과 책임성(인시던트 후 상황 재구성 가능)을 모두 갖춥니다.
결정 조회: minara script-risk list / show
"오늘 무슨 일이 있었나"부터 시작합니다.
# 모든 도구에 대한 최근 50건의 결정
minara script-risk list
# 최근 24시간 내 거부 결정만 조회
minara script-risk list --verdict=reject --since=2026-05-14
# 특정 세션의 모든 결정
minara script-risk list --session=abc-123
# 특정 워크플로 정의 내 모든 결정
minara script-risk list --workflow=wf_daily_rebalance
# 도구별 필터
minara script-risk list --tool=execute_code
# 특정 결정의 전체 상세 내용 (모든 찾아낸 항목, 모든 증거 행)
minara script-risk show <decision-id>
# 기계 판독 가능 형식
minara script-risk list --verdict=confirm --json플래그는 조합하여 사용할 수 있습니다. 의도는 포렌식입니다. 어제 무엇이 차단되었는지 파악하려면 넓게 시작해(--verdict=reject) 좁혀나가면 됩니다(--session, --workflow, --tool, --since).
HTTP 방식은 동일한 데이터 형식을 다음 엔드포인트로 제공합니다.
GET /v1/admin/script-risk/decisions?verdict=reject&tool=terminal&since=…&limit=…
GET /v1/admin/script-risk/decisions/<id>게이트웨이를 본인 외의 사용자에게 공개하는 경우, 해당 엔드포인트를 리버스 프록시로 감싸십시오.
감사 행에 기록되는 것과 기록되지 않는 것
모든 결정에 대해 기록되는 항목:
- 결정 타임스탬프, 도구 이름, 도구 호출 ID(알려진 경우), 세션 ID
- 판정(거부 / 확인 / 허용) 및 찾아낸 항목 배열. 각 항목에는 카테고리, 한 줄 메시지, 마스킹된 증거 텍스트, 본문 내 줄 번호가 포함됩니다.
body_sha256: 분석된 본문의 해시값- 경로가 확인 위젯을 거친 경우의
user_decision(execute / cancel / timeout) - 명시적 정책에 의해 통과된 경우의
bypassed_by(env_global / workflow_policy / null)
명시적으로 기록되지 않는 항목:
- 스크립트 본문 자체
- 마스킹 규칙에 의해 매칭된 원시 개인키, Authorization 헤더, Cookie 값, Bearer token
- 스크립트의 stdout / stderr
전체 본문을 기록하지 않는 이유는 무엇인가요? 개인키를 포함하는 스크립트는 감사 로그를 두 번째 유출 경로로 만들 수 있기 때문입니다.
sha256을 저장하면 "이 스크립트를 이전에 본 적 있는가"라는 질문에 예/아니오로 답할 수 있습니다. 마스킹된 증거는 "어떤 규칙이 발동되었고 매칭 결과는 어떠했는가"를 보여줍니다. 기밀 정보를 장기 보관 테이블에 복사하지 않으면서도 이 두 가지를 달성할 수 있습니다.트레이드오프: 사후에 정확한 본문을 바이트 단위로 재현할 수 없습니다. 그 대신 백업, 공유, grep이 안전한 감사 로그를 얻을 수 있습니다.
워크플로 면제: script_risk_policy
이 기능이 필요한 상황은 다음과 같습니다. 매일 minara swap USDC ETH 100을 호출하는 분할 매수(DCA) 워크플로가 있습니다. 스크립트를 직접 작성하고 감사를 마쳤으며, 본문은 변경되지 않습니다. 실행할 때마다 확인을 요청하는 것은 불필요한 마찰입니다.
워크플로 정의 내부:
script_risk_policy:
approved_body_sha256:
- "abc123…" # 감사를 완료한 스크립트의 sha256
allowed_categories:
- fund_moving_cli # 이 워크플로는 minara swap 호출이
# 명시적으로 허용됩니다워크플로가 활성화되면(자금 이동 2단계 확인인 workflow_activate를 통해), 정책이 등록됩니다. 이후 해당 워크플로가 일치하는 스크립트 본문을 실행하면, YELLOW 찾아낸 항목은 자동으로 강등됩니다. 감사 행에는 bypassed_by="workflow_policy"가 기록되므로, 게이트가 차단하지 않았다는 사실을 사후에 확인할 수 있습니다.
이 기능을 사용해야 하는 경우:
- 본문이 안정적인 사전 감사 스크립트. 해시 검사가 특정 리비전을 고정합니다.
- 특정 카테고리의 작업이 핵심 목적인 비즈니스 워크플로. 스왑을 수행하는 분할 매수 워크플로, approve를 호출하는 리밸런싱 워크플로 등이 해당됩니다.
이 기능을 사용하지 말아야 하는 경우:
- 포괄적인 catch-all 워크플로. 정책은 "이 면제는 무엇을 위한 것인가"를 한 문장으로 설명할 수 있을 만큼 좁아야 합니다.
- 모든 카테고리를 허용 목록에 추가하는 것. 그것은 워크플로의 게이트를 끄는 것과 다름없습니다.
- 본문이 동적으로 생성되는 스크립트. 실행마다 본문이 변경되면 sha256이 일치하지 않아 정책이 자동으로 실패하며 닫힙니다. 이는 기술적으로 안전하지만, 이득 없이 복잡성만 추가됩니다.
정책이 YELLOW는 우회하면서 RED는 우회하지 않는 이유는 무엇인가요? YELLOW는 "합법적이지만 위험 부담이 있는" 상황을 의미합니다.
minara swap은 자동화하고 싶을 수 있는 실제 작업입니다. "이 특정 워크플로에 해당 작업을 허용한다"고 선언하기에 적합한 곳이 정책입니다.RED는 "합법적인 비즈니스 목적이 없는" 경우를 의미합니다. 대량 삭제, IMDS 데이터 유출, 인라인 개인키 등은 합법적인 워크플로 시나리오가 없습니다. 워크플로가 RED에 해당한다면, 정책을 확장하는 것이 아니라 워크플로의 스크립트를 수정해야 합니다. RED는 의도적으로 정책으로 우회할 수 없습니다.
전역 비활성화 스위치: DISABLE_SCRIPT_RISK_GATE
환경 변수 DISABLE_SCRIPT_RISK_GATE=1을 설정하면 게이트를 완전히 건너뜁니다. RED와 YELLOW 모두 통과됩니다. 각 우회는 여전히 bypassed_by="env_global"으로 표시된 감사 행을 기록합니다.
연간 몇 차례에 한해 사용해야 하는 경우:
- 프로덕션 인시던트 대응. 실제 거짓 양성(false positive)이 비즈니스를 차단하고 있어 수정을 배포할 시간이 10분 필요한 경우. 환경 변수를 설정하고, 복구를 실행한 후, 해제하고, 문제가 된 규칙을 강화하는 이슈를 등록하십시오.
- 완전히 격리된 CI 환경. 모든 호출자가 비대화형임이 입증되고 테스트 환경이 샌드박스로 격리된 백테스트, 엔드투엔드 테스트, 회귀 테스트 스위트.
절대 사용하지 말아야 하는 경우:
- "확인 위젯이 불편하다"는 이유. 그것이 안전 장치가 정상적으로 작동하는 것입니다.
- "팀을 위해 Agent를 운영 중이며 정책 감사를 원하지 않는다"는 이유. 이는 공격자가 레이어 1을 우회하여 침투할 수 있는 모든 것에 팀 전체를 노출시킵니다.
- 셸 프로파일에 설정하고 잊어버리는 것. 이후의 무관한 세션이 해당 설정을 상속합니다.
감사 관점에서 오용 여부를 다음과 같이 확인할 수 있습니다.
minara script-risk list --json \
| jq '.decisions[] | select(.bypassed_by == "env_global")'기억하는 시간대 외에 env_global 우회가 보인다면, 의도하지 않은 곳에 환경 변수가 설정된 것입니다.
환경 변수 전체 참조는 환경 변수 → DISABLE_SCRIPT_RISK_GATE를 확인하십시오.
운영자 책임
레이어 4(게이트), 레이어 3(자금 이동 확인), 레이어 2(OS jail)는 많은 것을 담당하지만, 다음과 같이 피할 수 없는 운영자 위생 수칙을 대체하지는 않습니다.
- Minara 인스턴스당 운영자 한 명. Minara는 단일 사용자 트레이딩을 위해 설계되었으며, 멀티테넌트 SaaS가 아닙니다. 팀 공유 웹 UI는 지원되는 구성이 아닙니다. 각 운영자는 자신의 인스턴스를 별도로 실행해야 합니다.
- 개인키는
.env에 보관하고, 레포지토리에 포함하지 마십시오. 그리고.env에는chmod 600을 적용하십시오. 게이트는 레이어 4에서 런타임 중 무단 파일 읽기를 막지만, 셸에서cat .env를 실행하는 것은 막을 수 없습니다. - RED가 표시되면 우회하려 하지 마십시오. 실행한 스크립트가 높은 신뢰도의 악성 패턴에 해당한 이유를 멈추고 생각하십시오. 95% 이상의 경우는 거짓 양성이 아니라, 게이트가 제 역할을 하는 것입니다.
- YELLOW가 표시되면 증거를 읽으십시오. 매칭된 줄을 읽는 데 2초를 투자하는 것이 위젯의 존재 이유입니다. 습관적으로 "실행"을 클릭하면 스스로 가장 약한 고리가 됩니다.
MINARA_SKIP_FUND_CONFIRM=1이나DISABLE_SCRIPT_RISK_GATE=1을.zshrc,.envrc, 또는 systemd 유닛에 절대 추가하지 마십시오. 특정 스크립트에 필요한 경우, 해당 명령에만 인라인으로 설정하고 이후에 해제하십시오.- 감사 로그 백업은 중요합니다.
script_risk_decisionsSQLite 테이블은 포렌식 기록의 일부입니다. 로그로서 적절히 관리하십시오.