본문 바로가기
프로그램 (PHP,Python)

AI 에이전트 샌드박스 아키텍처: just-bash 기반 실행 통제 게이트웨이

by 날으는물고기 2026. 2. 24.

AI 에이전트 샌드박스 아키텍처: just-bash 기반 실행 통제 게이트웨이

728x90

에이전트가 생성한 Bash 명령을 그대로 OS에 실행하지 않고, “게이트웨이”를 거쳐 다음을 보장합니다.

  • 안전성: 실제 디스크/네트워크/바이너리 실행 위험 최소화
  • 정책 준수: 명령 허용/차단/승인(HITL) + 접근제어 + 감사지원
  • 재현성: 동일 입력에 동일 결과(가상 FS, 실행 한도)
  • 운영성: 로깅/알림/리포트/사고조사(포렌식) 가능한 형태로 구조화

just-bash를 게이트웨이 실행 엔진으로 쓰는 이유

just-bash는 애초에 AI 에이전트용 “샌드박스 bash”로 설계되어,

  • 제공된 파일시스템만 접근 가능
  • 네트워크 기본 차단, 필요 시에도 URL prefix + HTTP method allowlist로 제한
  • 바이너리/WASM 실행 비지원(풀 VM 필요하면 Vercel Sandbox 권장)
  • 무한루프/재귀 방지(단, 입력 기반 DoS에 완전 강건하지 않을 수 있어 OS 레벨 격리 병행 권고)
  • exec() 호출 단위로 환경변수/함수/cwd가 유지되지 않고(파일시스템만 유지) 격리됨

“에이전트 실행 게이트웨이” 구성요소

아키텍처를 7개 컴포넌트로 나누면 운영/보안 통제가 쉬워집니다.

  1. LLM Orchestrator (Agent Runtime)
  • 대화/계획/툴콜(tool call) 생성
  • “bash 실행”은 직접 하지 않고 게이트웨이에 요청
  1. Tool Adapter (Bash Tool Bridge)
  • LLM의 tool call을 게이트웨이 요청 형식으로 변환
  • 예: DeepWiki의 bash-agent 예시에서 createBashTool()이 “도구 통합 레이어” 역할
  1. Policy Engine (정책 엔진)
  • 사전 검증(allow/deny/HITL)
  • 실행 전/후 훅(onBeforeBashCall 등)으로 로깅·검증·차단 수행
  1. Execution Broker (실행 브로커)
  • 멀티테넌시/큐잉/동시성 제한
  • 요청 단위로 환경 구성(InMemoryFs/OverlayFs, 네트워크, 실행한도 등)
  1. just-bash Runtime
  • 실제 명령 실행(시뮬레이션)
  • 가상 FS + 실행 보호 + 네트워크 제한 모델
  1. Evidence & Audit Store (증적 저장소)
  • 입력(명령/정책결정/맥락) + 출력(stdout/stderr/exitCode) + FS diff(가능하면) 저장
  • 이후 리뷰/감사/사고 분석에 활용
  1. Result Post-Processor (결과 정규화/요약)
  • stdout/stderr가 너무 길면 요약/마스킹/구조화(JSON)
  • LLM에 “안전한 형태”로 되돌려줌

실행 플로우(LLM → 정책엔진 → just-bash → 결과 → LLM)

아래는 “한 번의 bash tool call”에 대한 표준 시퀀스입니다.

시퀀스 다이어그램(개념)

LLM(Agent)
  └─(tool_call: bash, cmd)→ Tool Adapter
         └→ Policy Engine (pre-check: allow/deny/HITL)
                ├─ deny → return policy_error to LLM
                ├─ HITL → create approval ticket → return pending to LLM
                └─ allow
                      └→ Execution Broker (build sandbox config)
                             └→ just-bash.exec(cmd)
                                    └→ stdout/stderr/exitCode (+ env info)
                             └→ Policy Engine (post-check: DLP/masking/rate-limit)
                      └→ Evidence Store (full log)
         └→ Result Post-Processor (truncate/summarize/jsonify)
  └← result to LLM

“왜 pre-check와 post-check가 둘 다 필요한가?”

  • pre-check: 위험 명령 차단, 네트워크 정책, 경로 접근 등 “실행 자체”를 통제
  • post-check: 실행 결과에 민감정보가 섞였는지(예: 키/토큰), 과도 출력/로그 주입 방지, 감사 저장 전 마스킹
300x250

핵심 설계 포인트

파일시스템 전략: InMemoryFs vs OverlayFs (기본 선택 규칙)

just-bash는 InMemoryFs/OverlayFs/ReadWriteFs/MountableFs를 제공합니다.

권장 기본 규칙(운영 관점)
  • 기본: InMemoryFs
    • 외부 파일 접근이 필요 없는 “데이터 변환/텍스트 처리/샘플 테스트”에 최적
  • 코드베이스 탐색/읽기 필요: OverlayFs
    • 실제 디렉터리를 가상 /workspace로 매핑하고
    • “읽기는 실제 파일, 쓰기는 메모리”로 격리 (bash-agent 패턴)
  • ReadWriteFs는 ‘정말 필요할 때만’ + 상위 OS 격리 필수
  • MountableFs로 구역 분리(지식베이스 read-only / 작업공간 read-write)

게이트웨이의 중요한 책임은 “요청 유형에 맞춰 FS 정책을 자동 선택”하는 것입니다.

FS 정책 예시(개념 YAML)

profiles:
  analyze_text:
    fs: in_memory
  explore_repo_readonly:
    fs: overlay
    mounts:
      - host: /real/repo
        guest: /workspace
        mode: ro   # 읽기만 허용(쓰기는 overlay 메모리)
  build_artifacts_safe:
    fs: mountable
    mounts:
      - host: /real/repo
        guest: /workspace
        mode: ro
      - host: /safe/output
        guest: /out
        mode: rw

exec() 호출 격리 모델을 게이트웨이에 어떻게 반영할까

just-bash는 exec() 단위로 env vars, functions, cwd가 지속되지 않고, 파일시스템 상태만 지속된다고 명시합니다.

게이트웨이 설계 관점에서의 의미
  • 명령을 “원자적 단위”로 다루기 쉬움
      1. 실행 전 정책결정
      1. 실행 후 결과 검증
      1. 증적 저장
        을 매 호출마다 반복 가능
  • 단점: 사용자가 기대하는 “셸 세션 상태 유지”가 필요하면
    • 게이트웨이가 한 번의 exec에 여러 명령을 묶어 실행(예: cmd1; cmd2; cmd3)
    • 또는 “세션 모델”을 별도로 만들어, 파일시스템만 지속되는 특성을 이용해 필요한 상태를 파일로 관리(예: .env를 파일로 두고 source를 매번 포함)

“멀티 스텝을 1 exec로 묶는” 예

# 게이트웨이가 내부적으로 하나의 exec로 묶어서 실행
set -e
cd /workspace
grep -R "TODO" -n src | head -200

네트워크 정책: default deny + curl allowlist (가장 중요)

just-bash는 기본적으로 네트워크 접근이 없고, 켤 수는 있지만 URL prefix allow-list와 HTTP method allow-list로 제한된다고 명시합니다.

게이트웨이 설계 원칙
  • 기본: network = off
  • 허용 필요 시에도
    • allowlist는 “업무 API 도메인 단위로 최소화”
    • 메서드는 GET만 등 최소 권한
    • 응답 바이트/시간 제한(게이트웨이 레벨에서 추가)

네트워크 정책 예시(개념)

network:
  enabled: true
  curl:
    allow_url_prefixes:
      - "https://api.github.com/"
      - "https://registry.npmjs.org/"
    allow_methods: ["GET"]
  limits:
    max_bytes: 1048576
    timeout_ms: 5000

실행 보호(Execution Protection) + 상위 격리(권장)

무한 루프/재귀로부터 보호하지만, 입력 기반 DoS에 완전 robust 하지 않을 수 있어 OS 레벨 프로세스 격리를 권고합니다. 

게이트웨이 필수 설계
  • just-bash 실행 한도(함수 깊이/명령 수/루프 등) 사용
  • 게이트웨이 레벨 추가 보호
    • 요청당 타임아웃
    • 동시 실행 수 제한
    • 출력 크기 제한(stdout/stderr)
    • 세션별 rate limit
  • 운영 환경: 컨테이너(gVisor 등)/VM 같은 상위 격리 병행 권장

커스텀 명령(defineCommand)과 “보안 친화적 확장”

defineCommand로 TypeScript 기반 커스텀 명령을 추가하고, CommandContextfs, cwd, env, stdin, exec 등에 접근 가능하다고 정리돼 있습니다.

게이트웨이에서 이 기능을 쓰는 이유
  • LLM이 위험한 조합의 쉘 파이프를 만들기보다
  • 안전하게 검증된 “업무용 명령”을 하나의 커맨드로 제공
  • 예: safe_fetch, read_secret_denied, repo_scan, summarize_json

커스텀 명령 설계 예(개념)

  • safe_fetch <url>
    • allowlist + 크기 제한 + 콘텐츠 타입 제한 + 저장 경로 제한
  • repo_grep <pattern> <path>
    • 탐색 경로를 /workspace로 고정
    • 결과 최대 500라인 제한

Lazy 파일 로딩(필요 시점 생성)으로 데이터 노출 최소화

게이트웨이에 적용하면 좋은 점
  • LLM이 요청할 때만 파일 내용을 주입 → 불필요한 민감 데이터 노출 최소화
  • 예: /workspace/.env 같은 파일은 “승인된 명령에서만” 로딩되도록 제어 가능

CLI/JSON 출력과 운영 파이프라인

게이트웨이는 내부적으로 라이브러리 API를 쓰는 게 일반적이지만, 다음에 CLI가 유용합니다.

  • 로컬/CI에서 정책/명령 세트 회귀 테스트
  • “정책에 따라 어떤 출력이 나오는지” 자동 검증
  • --json을 증적 포맷으로 표준화

게이트웨이 “정책 엔진” 설계

정책 엔진을 최소 4단으로 나누면 실무에서 잘 굴러갑니다.

정책 단계 A: 입력 정규화/파싱

  • 문자열 정규화(공백/개행/제어문자)
  • (가능하면) 쉘 AST 기반 분석
    • DeepWiki는 just-bash가 Bash 문법을 AST로 파싱해 실행한다고 설명합니다.
    • 게이트웨이도 “AST 기반 정책”으로 가면 "; rm -rf /" 같은 우회에 강해집니다.

정책 단계 B: 위험 행위 분류(deny/allow/HITL)

예시 룰(개념)
  • Deny (즉시 차단)
    • rm -rf /, mkfs, dd if=, mount, chmod 777(상황 따라), fork bomb 패턴
    • 네트워크 off인데 curl/wget 호출
    • /proc, /etc, ~/.ssh 등 금지 경로 접근 시도(OverlayFs라도 정책상 금지)
  • HITL (승인 필요)
    • allowlist 외부 호출
    • 대규모 grep(성능/정보유출 우려)
    • 아카이브 압축/해제(tar 등)로 폭탄 가능성
  • Allow
    • /workspace 내 텍스트 처리, 제한된 데이터 요약 등

정책 단계 C: 실행 환경 프로파일링(자동 구성)

명령의 성격에 따라 프로파일 선택

  • “repo 탐색” → OverlayFs + /workspace 매핑 + 네트워크 off
  • “API 조회” → InMemoryFs + 네트워크 on + allowlist 엄격
  • “데이터 처리” → InMemoryFs + python/sqlite 옵션은 조직 정책에 따라 Pyodide python, WASM sqlite 옵션

정책 단계 D: 결과 검증/마스킹/요약

  • stdout/stderr에서 비밀키/토큰/PII 패턴 마스킹
  • 출력 크기 제한(예: 64KB) + 초과분은 파일로 저장하되 LLM에는 요약만
  • exitCode 기반 재시도 정책(무한 재시도 금지)

“bash-agent” 예시를 게이트웨이 패턴으로 일반화

DeepWiki의 Examples 문서는 bash-agent 패턴을 3-layer로 정리합니다.

이를 게이트웨이에 매핑하면 아래처럼 “표준 레퍼런스 아키텍처”가 됩니다.

  • Interaction Layer: Agent(대화/도구 호출)
  • Tool Integration Layer: createBashTool() + onBeforeBashCall 훅(여기가 정책엔진 훅 포인트)
  • Execution Layer: Bash + OverlayFs (실파일 읽기, 쓰기는 메모리)
게이트웨이에서 반드시 가져올 포인트
  • uploadDirectory(실 디렉터리 → 가상 경로 매핑)로 코드베이스 탐색을 안전하게 제공
  • onBeforeBashCall에서 로깅/검증/차단 가능

구현 스케치(구체 예시)

아래는 “게이트웨이 서비스”가 받는 요청 포맷과 처리 흐름의 예시입니다. (개념 코드)

요청/응답 스키마(예시)

{
  "request_id": "req-20260223-0001",
  "actor": { "user": "pageskr", "agent": "sec-agent-v1" },
  "command": "grep -R \"TODO\" -n /workspace/src | head -200",
  "context": {
    "purpose": "repo_explore",
    "workspace_mount": "/real/repo",
    "network_needed": false
  }
}

응답(LLM으로 반환될 “안전 결과”)

{
  "request_id": "req-20260223-0001",
  "decision": "allow",
  "exec": {
    "exitCode": 0,
    "stdout_truncated": false,
    "stdout": "src/a.ts:10:TODO ...\n",
    "stderr": ""
  },
  "audit_ref": "s3://evidence/.../req-20260223-0001.json"
}

게이트웨이 처리 의사코드(개념)

async function handleBashToolCall(req) {
  const normalized = normalize(req.command);

  // 1) 정책 판단
  const decision = policyEngine.preCheck({
    cmd: normalized,
    context: req.context,
  });
  if (decision.type === "deny") return toLLMError(decision);
  if (decision.type === "hitl") return toLLMPending(decision);

  // 2) 실행 환경 구성 (FS/네트워크/limits)
  const profile = buildProfile(decision.profile, req.context);

  // 3) 실행 전 훅(로깅/추가검증)
  audit.logPre(req, profile);

  // 4) just-bash 실행
  const result = await justBashExec(profile, normalized); // env.exec(...)
  // exec() 격리 특성(환경/cwd 비지속, fs만 지속) 고려 :contentReference[oaicite:21]{index=21}

  // 5) 결과 후처리(마스킹/요약/크기제한)
  const safe = postProcess(result);

  // 6) 증적 저장
  audit.store(req, profile, result, safe);

  // 7) LLM에 반환
  return safe;
}

보안 관점 “점검 포인트” 체크리스트

접근 통제

  • 누가 어떤 repo/디렉터리를 uploadDirectory로 매핑할 수 있는가?
  • 가상 경로는 항상 /workspace 같은 고정 prefix로 제한하는가?

네트워크

  • 기본 off인가?
  • allowlist가 URL prefix + method 최소권한으로 구성됐는가?
  • 응답 크기/타임아웃/도메인 수 제한이 있는가?

실행 보호(DoS)

  • just-bash 실행 보호 옵션을 표준값으로 강제하는가?
  • 게이트웨이 차원의 타임아웃/동시성 제한이 있는가?
  • 운영은 OS 레벨 격리를 병행하는가(README 권고)?

데이터 유출 방지(DLP)

  • stdout/stderr 마스킹(토큰/키/PII)
  • 민감 경로 마운트 금지(MountableFs 정책)
  • Lazy 파일 로딩으로 “필요 시점만” 주입하도록 했는가?

감사/증적

  • 원문 명령 + 정책결정 + 프로파일 + 결과(exitCode/stdout/stderr) 저장
  • 재현 가능한 실행환경(프로파일, 버전, allowlist)을 함께 저장

권장 “운영 표준”

  • 기본 프로파일
    • FS: InMemoryFs 또는 OverlayFs(read real, write memory)
    • Network: off
    • Limits: 보수적으로(명령 수/루프/출력/시간)
  • 도구 통합
    • createBashTool() + onBeforeBashCall 같은 훅을 게이트웨이 정책엔진에 연결(로그/차단)
  • 안전 확장
    • defineCommand로 “검증된 업무용 커맨드”를 제공해 LLM의 위험한 쉘 조합을 줄이기
  • 상위 격리
    • 입력 기반 DoS까지 강하게 막으려면 OS 레벨 프로세스 격리 병행 권고
728x90
그리드형(광고전용)

댓글