
에이전트가 생성한 Bash 명령을 그대로 OS에 실행하지 않고, “게이트웨이”를 거쳐 다음을 보장합니다.
- 안전성: 실제 디스크/네트워크/바이너리 실행 위험 최소화
- 정책 준수: 명령 허용/차단/승인(HITL) + 접근제어 + 감사지원
- 재현성: 동일 입력에 동일 결과(가상 FS, 실행 한도)
- 운영성: 로깅/알림/리포트/사고조사(포렌식) 가능한 형태로 구조화
just-bash를 게이트웨이 실행 엔진으로 쓰는 이유
just-bash는 애초에 AI 에이전트용 “샌드박스 bash”로 설계되어,
- 제공된 파일시스템만 접근 가능
- 네트워크 기본 차단, 필요 시에도 URL prefix + HTTP method allowlist로 제한
- 바이너리/WASM 실행 비지원(풀 VM 필요하면 Vercel Sandbox 권장)
- 무한루프/재귀 방지(단, 입력 기반 DoS에 완전 강건하지 않을 수 있어 OS 레벨 격리 병행 권고)
exec()호출 단위로 환경변수/함수/cwd가 유지되지 않고(파일시스템만 유지) 격리됨
“에이전트 실행 게이트웨이” 구성요소
아키텍처를 7개 컴포넌트로 나누면 운영/보안 통제가 쉬워집니다.
- LLM Orchestrator (Agent Runtime)
- 대화/계획/툴콜(tool call) 생성
- “bash 실행”은 직접 하지 않고 게이트웨이에 요청
- Tool Adapter (Bash Tool Bridge)
- LLM의 tool call을 게이트웨이 요청 형식으로 변환
- 예: DeepWiki의 bash-agent 예시에서
createBashTool()이 “도구 통합 레이어” 역할
- Policy Engine (정책 엔진)
- 사전 검증(allow/deny/HITL)
- 실행 전/후 훅(onBeforeBashCall 등)으로 로깅·검증·차단 수행
- Execution Broker (실행 브로커)
- 멀티테넌시/큐잉/동시성 제한
- 요청 단위로 환경 구성(InMemoryFs/OverlayFs, 네트워크, 실행한도 등)
- just-bash Runtime
- 실제 명령 실행(시뮬레이션)
- 가상 FS + 실행 보호 + 네트워크 제한 모델
- Evidence & Audit Store (증적 저장소)
- 입력(명령/정책결정/맥락) + 출력(stdout/stderr/exitCode) + FS diff(가능하면) 저장
- 이후 리뷰/감사/사고 분석에 활용
- 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: 실행 결과에 민감정보가 섞였는지(예: 키/토큰), 과도 출력/로그 주입 방지, 감사 저장 전 마스킹
핵심 설계 포인트
파일시스템 전략: 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가 지속되지 않고, 파일시스템 상태만 지속된다고 명시합니다.
게이트웨이 설계 관점에서의 의미
- 명령을 “원자적 단위”로 다루기 쉬움
-
- 실행 전 정책결정
- 실행 후 결과 검증
- 증적 저장
을 매 호출마다 반복 가능
-
- 단점: 사용자가 기대하는 “셸 세션 상태 유지”가 필요하면
- 게이트웨이가 한 번의 exec에 여러 명령을 묶어 실행(예:
cmd1; cmd2; cmd3) - 또는 “세션 모델”을 별도로 만들어, 파일시스템만 지속되는 특성을 이용해 필요한 상태를 파일로 관리(예:
.env를 파일로 두고source를 매번 포함)
- 게이트웨이가 한 번의 exec에 여러 명령을 묶어 실행(예:
“멀티 스텝을 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 기반 커스텀 명령을 추가하고, CommandContext로 fs, 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 레벨 프로세스 격리 병행 권고
댓글