콘텐츠로 이동

샌드박싱과 격리

에이전트가 코드를 실행하고 파일을 수정할 수 있다면, 하나의 잘못된 명령이 호스트 시스템 전체에 영향을 미칠 수 있습니다. 이를 막는 것이 샌드박싱(Sandboxing) — 에이전트의 실행 환경을 호스트와 격리하는 기술입니다.

샌드박싱에는 크게 두 가지 접근법이 있습니다.

방식설명강도
스키마 레벨 격리위험한 도구를 에이전트 스키마에서 제거중간
런타임 권한 검사도구 호출 시 실시간으로 권한 확인중간
컨테이너 격리별도 OS 레벨 격리 환경에서 실행강함
전용 샌드박스 서비스E2B 같은 관리형 격리 환경 사용매우 강함

에이전트에게 제공하는 도구 목록 자체에서 위험 도구를 제거합니다. 에이전트는 해당 도구의 존재를 알지 못하므로 호출 시도 자체가 불가능합니다.

// 읽기 전용 에이전트를 위한 도구 스키마
const readOnlyTools = [
{ name: "read_file", description: "파일 내용 읽기" },
{ name: "list_directory", description: "디렉터리 목록 조회" },
{ name: "search_files", description: "파일 내용 검색" },
];
// exec_shell, write_file, delete_file 은 스키마에 포함하지 않음
const agent = new Agent({ tools: readOnlyTools });

도구 스키마에는 포함되어 있지만, 실제 실행 시점에 권한을 확인하고 차단합니다.

def execute_tool(tool_name: str, params: dict, context: AgentContext) -> Any:
# 런타임 권한 테이블 확인
if tool_name not in context.allowed_tools:
raise PermissionError(f"{tool_name}은 이 컨텍스트에서 허용되지 않습니다")
# 경로 제한 검사
if tool_name == "write_file":
path = params.get("path", "")
if not is_within_allowed_paths(path, context.allowed_write_paths):
raise PermissionError(f"허용되지 않은 경로: {path}")
return tools[tool_name](**params)
ALLOWED_READ_PATHS = ["/workspace/src", "/workspace/tests"]
ALLOWED_WRITE_PATHS = ["/workspace/src", "/workspace/output"]
FORBIDDEN_PATHS = ["/etc", "/sys", "/proc", "/home", "~/.ssh"]
def validate_path(path: str, operation: str) -> None:
resolved = os.path.realpath(path) # symlink 해결
# 금지 경로 확인
for forbidden in FORBIDDEN_PATHS:
if resolved.startswith(forbidden):
raise SecurityError(f"금지된 경로: {path}")
# 쓰기 작업 화이트리스트 확인
if operation == "write":
allowed = any(resolved.startswith(p) for p in ALLOWED_WRITE_PATHS)
if not allowed:
raise SecurityError(f"쓰기 불가 경로: {path}")
Terminal window
# Docker로 작업 디렉터리만 마운트
docker run --rm \
-v /host/workspace:/workspace:rw \
-v /host/readonly-data:/data:ro \
--network none \
agent-image:latest

셸 명령 실행은 에이전트 도구 중 가장 강력하고 위험합니다.

import subprocess
import shlex
ALLOWED_COMMANDS = {"python", "node", "npm", "pytest", "git"}
SHELL_TIMEOUT = 30 # 초
def safe_exec(command: str) -> str:
# 명령어 파싱 및 허용 목록 확인
parts = shlex.split(command)
if not parts or parts[0] not in ALLOWED_COMMANDS:
raise SecurityError(f"허용되지 않은 명령: {parts[0] if parts else 'empty'}")
result = subprocess.run(
parts,
capture_output=True,
text=True,
timeout=SHELL_TIMEOUT,
cwd="/workspace", # 작업 디렉터리 제한
env={"PATH": "/usr/bin"}, # 환경 변수 제한
)
# 출력 크기 제한 (토큰 폭발 방지)
return result.stdout[:10_000]
격리 수준구현 방법허용 범위
완전 차단--network none (Docker)없음
내부망만 허용iptables / 방화벽 규칙사내 API만
도메인 화이트리스트프록시 서버 경유허용된 외부 API만
전체 허용제한 없음모든 인터넷 (위험)
FROM python:3.12-slim
# 최소 권한 사용자
RUN useradd -m -u 1000 agent
USER agent
WORKDIR /workspace
# 필요한 패키지만 설치
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
# 실행 시 네트워크 · 마운트 옵션은 docker run에서 제어
CMD ["python", "agent_runner.py"]
Terminal window
docker run --rm \
--user 1000:1000 \
--memory 512m \
--cpus 1 \
--network none \
--read-only \
--tmpfs /tmp:size=100m \
-v $(pwd)/workspace:/workspace:rw \
agent-sandbox:latest

E2B는 에이전트를 위한 관리형 클라우드 샌드박스입니다. 직접 Docker를 관리하지 않고 안전한 코드 실행 환경을 제공합니다.

import { Sandbox } from '@e2b/code-interpreter';
const sandbox = await Sandbox.create();
// 에이전트가 생성한 코드를 격리된 환경에서 실행
const result = await sandbox.runCode(`
import pandas as pd
df = pd.read_csv('/data/input.csv')
print(df.describe())
`);
console.log(result.text);
await sandbox.kill();

샌드박싱은 스키마 레벨(도구 제거), 런타임 검사(실행 시 권한 확인), 컨테이너 격리(Docker), 관리형 서비스(E2B) 네 계층으로 구성됩니다. 파일 시스템 경로 제한, 셸 명령 화이트리스트, 네트워크 차단을 조합하여 에이전트가 의도치 않게 호스트 시스템에 영향을 미치는 것을 차단합니다.