검색
← 모듈 로드맵

macOS에서 AI 코딩 에이전트 격리 실행 설정

발행 출처 Zenn · 検証屋

클로드 코드튜토리얼준전문가

나중에 보기좋아요
공유 · 인쇄
후기댓글

1. 무엇을 할 수 있게 되는가

  • AI 코딩 에이전트(Claude Code / Codex / Copilot)를 OS 수준의 격리 하에서 실행할 수 있다
  • 파일 쓰기를 작업 디렉터리로 제한하고, 네트워크 전송은 기본 거부(default-deny)로 할 수 있다
  • 만일 에이전트가 프롬프트 인젝션 등으로 탈취되더라도, 피해 범위(blast radius)를 줄일 수 있다

2. 누구의 어떤 문제를 해결하는가

대상 독자는 AI 에이전트에 Bash 실행이나 파일 편집 권한을 넘기는 데 불안함이 있으면서도, 업무용 PC에서 사용하고 싶은 실무 엔지니어와 정보시스템 담당자입니다.

이들 에이전트는 편리한 반면, curl로 데이터를 전송하거나 ~/ 아래를 읽는 등의 작업을 지시에 따라 실행할 수 있습니다. “허용 다이얼로그를 매번 누르는” 운영은 피로 때문에 승인하기 쉬워져 경계로서는 취약합니다. 그래서 이 글은 허용 다이얼로그가 아니라 OS가 강제하는 경계 (파일 스코프와 네트워크 차단)로 둘러싸는 설정을 다룹니다.

또한 원본 저장소 자체가 강하게 주의하듯, 이러한 메커니즘은 실험적이며 성숙하지 않았고, 민감한 데이터를 에이전트에 넘겨도 되는 상태를 만들어 주는 것이 아닙니다. 어디까지나 “사고 시 피해를 작게 만들기” 위한 다층 방어의 일부로 받아들여 주세요.

3. 전제 환경

항목요구 사항
macOS14 (Sonoma) 이상을 본문의 전제로 한다. 내장 Seatbelt만 쓸 경우는 13 (Ventura) 이상, Apple 순정 container microVM tier는 26 (Tahoe) 이상
CPUApple Silicon (arm64) 권장. Docker Sandbox / Apple container tier에서 필요
Docker DesktopDocker Sandbox ( sbx ) tier를 사용할 때 필요. 도입 버전은 verify.sh의 docker --version 출력으로 기록한다
git / gh설정 저장소를 가져오는 데 사용. 버전은 verify.sh에서 기록한다
대상 CLI 중 하나Claude Code / Codex CLI / Copilot CLI 중 1개 이상. --version 값은 verify.sh에서 기록한다
sandbox-execmacOS 기본 포함(Apple은 deprecated 취급하지만 현행 OS에 존재). 내장 Seatbelt 격리 데모에서 사용

이 저장소는 3계층 방어를 제시합니다. Tier 1은 각 도구의 표준 샌드박스를 강화하는 것이고, Tier 2는 Docker Sandbox / container microVM을 이용한 범용 격리, Tier 3은 MDM에 의한 조직 강제입니다. 이 글에서는 우선 입구로서 설정 저장소의 획득·확인 과, 내장 Seatbelt에 의한 격리 동작 시연 (추가 도구 불필요)까지 절차화합니다.

4. 절차

4-1. 작업 디렉터리를 준비하고 설정 저장소를 가져온다

gh repo clone은 인증이 필요할 수 있으므로, 공개 저장소는 git clone(HTTPS)으로 가져옵니다.

코드
mkdir -p ~/work && cd ~/work
git clone --depth 1 https://github.com/navapbc/ai-coding-assistant-sandboxing.git
cd ai-coding-assistant-sandboxing

4-2. 포함된 ready-to-use config의 위치를 확인한다

각 도구용 설정은 configs/ 아래에 있습니다.

코드
ls -la configs/claude-code/settings.user.json
ls -la configs/codex/config.toml
ls -la configs/copilot/vscode-settings.json
ls -la configs/docker-sandbox/apply-policy.sh

내용은 반드시 직접 검토하세요. Claude Code용 설정은 다음으로 확인할 수 있습니다.

코드
cat configs/claude-code/settings.user.json

4-3. 설정을 적용한다(자동 적용하지 말고, 절차를 이해한 뒤)

이 저장소에는 setup.sh가 포함되어 있으며, 도구를 자동으로 감지해 ~/.claude 등으로 설정을 반영합니다. 다만 사용자의 홈 아래를 변경하므로, 바로 실행하지 말고 반드시 내용을 읽은 뒤 --dry-run으로 반영 내용을 확인합니다.

코드
# まず中身を読む
less ./setup.sh

# 反映内容を「表示だけ」して確認する(実際には書き換えない)
./setup.sh --dry-run

수동으로 반영할 경우의 대응 관계는 다음과 같습니다(기존 설정은 미리 백업해 두세요).

코드
# Claude Code: 既存設定をバックアップしてから内容を確認・手動マージ
cp ~/.claude/settings.json ~/.claude/settings.json.bak 2>/dev/null || true
# 反映後、Claude Code 側で /sandbox コマンドを実行して有効化

# Codex CLI: ~/.codex/config.toml へ configs/codex/config.toml の内容を手動マージ

Docker Sandbox tier(sbx)를 사용할 때의 도입 명령은, 판단한 뒤 손으로 실행하기 위해 여기서는 표시만 합니다(verify.sh 쪽에서도 표시만).

코드
# 以下はレビュー用。実行は自己判断で
# brew trust docker/tap && brew install docker/tap/sbx
# sbx login
# ./configs/docker-sandbox/apply-policy.sh

보충: 이 저장소는 “ 셸 환경 변수에 둔 비밀 정보는 샌드박스를 무력화한다 ”고 명시합니다. OS 샌드박스는 환경 변수를 격리하지 않으므로, 토큰류는 dotfile이 아니라 Keychain 등의 자격 증명 저장소에 두세요.

4-4. 일회용 테스트 저장소에서 격리 동작을 시험한다(내장 Seatbelt)

추가 도구 없이 “네트워크 기본 거부”와 “쓰기를 작업 디렉터리로 제한”을 시연합니다. macOS 기본 포함 sandbox-exec와 최소 Seatbelt 프로파일(.sb)을 사용합니다.

코드
# カレント配下に使い捨て領域を作る
mkdir -p ./sandbox-verify-tmp/workspace
WS_ABS="$(cd ./sandbox-verify-tmp/workspace && pwd)"

# 最小プロファイル: 既定許可のうえで network と workspace外書き込みを拒否
cat > ./sandbox-verify-tmp/deny.sb <<EOF
(version 1)
(allow default)
(deny network*)
(deny file-write*)
(allow file-write* (subpath "${WS_ABS}"))
EOF

# ワークスペース内書き込み(許可されるはず)
sandbox-exec -f ./sandbox-verify-tmp/deny.sb /bin/sh -c "echo ok > '${WS_ABS}/allowed.txt'"

# ワークスペース外書き込み(拒否されるはず)
OUTSIDE="$(cd ./sandbox-verify-tmp && pwd)/outside.txt"
sandbox-exec -f ./sandbox-verify-tmp/deny.sb /bin/sh -c "echo leak > '${OUTSIDE}'"

# ネットワーク送信(既定拒否されるはず。宛先は公式配布元 github.com)
sandbox-exec -f ./sandbox-verify-tmp/deny.sb /usr/bin/curl -sS -m 5 https://github.com -o /dev/null

# 後片付け
rm -rf ./sandbox-verify-tmp

Seatbelt의 규칙은 “마지막에 일치한 규칙이 우선”입니다. 워크스페이스 내 쓰기는 끝부분의 allow가 이기고, 외부 쓰기는 deny file-write*가 이기며, 통신은 deny network*가 이기는 식으로 동작함을 확인할 수 있습니다. 이것이 Tier 1(내장 강화)의 핵심 개념입니다.

5. 실행 결과

검증은 대상 CLI(Claude Code / Codex / Copilot)를 도입하지 않은 깨끗한 macOS에서 진행했습니다. 실측할 수 있었던 것은 “설정 저장소의 획득”과 “포함된 config의 내용 확인”까지였습니다. sandbox-exec를 사용한 격리 데모(4-4)는, 검증 자체를 격리 환경 안에서 실행한 사정으로 시연하지 못했습니다(이유는 “6. 막히는 지점”에 적습니다).

검증 환경

  • OS: macOS 15.0 (build 24A335)
  • 아키텍처: arm64 (Apple Silicon)
  • git: 2.39.5 (Apple Git-154)
  • gh: 2.96.0
  • docker / claude / codex / copilot: 미설치(이번 검증에서는 설정 획득과 확인까지를 대상으로 함)
  • sandbox-exec: /usr/bin/sandbox-exec에 존재

설정 저장소의 획득과 구성

git clone(HTTPS, github.com)으로 저장소를 가져올 수 있었고, 포함된 config가 4개 모두 존재함을 확인할 수 있었습니다.

  • configs/claude-code/settings.user.json
  • configs/codex/config.toml
  • configs/copilot/vscode-settings.json
  • configs/docker-sandbox/apply-policy.sh

Claude Code용 config(settings.user.json)의 내용

가져온 settings.user.json에는 OS 수준의 샌드박스와, 자격 증명 읽기 거부·egress allowlist·환경 변수 scrub이 한꺼번에 정의되어 있었습니다. 핵심만 발췌합니다.

  • sandbox.enabled: true / autoAllowBashIfSandboxed: true / allowUnsandboxedCommands: false(샌드박스 밖 실행을 허용하지 않음)
  • sandbox.filesystem.denyRead(읽기를 거부할 경로): ~/.ssh ~/.aws ~/.azure ~/.config/gcloud ~/.kube ~/.gnupg ~/.netrc ~/.npmrc ~/.pypirc ~/.docker ~/Library/Keychains ~/.config/sops ~/.bash_history ~/.zsh_history
  • sandbox.network.allowedDomains(이 목록 외 통신은 기본 거부=default-deny인 allowlist): api.anthropic.com claude.ai platform.claude.com downloads.claude.ai raw.githubusercontent.com github.com api.github.com codeload.github.com objects.githubusercontent.com
  • sandbox.network.allowLocalBinding: false(로컬에 대한 리스닝도 차단함)
  • permissions.ask(그때그때 확인하는 작업): Bash(git push *) Bash(gh pr create *) Bash(gh repo *) Bash(npm publish *)
  • permissions.deny(금지): Read(~/.ssh/**) Read(~/.aws/**) Read(~/.config/gcloud/**) Read(~/.config/sops/**) Read(~/.bash_history) Read(~/.zsh_history) Read(~/.netrc) Read(**/*.key) Read(**/*.sw[a-p])
  • env: CLAUDE_CODE_DISABLE_NONESSENTIAL_TRAFFIC=1 / CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1(서브프로세스로 전달할 환경 변수를 제거함)

「파일 스코프(denyRead) + egress의 allowlist(allowedDomains) + 서브프로세스의 환경 변수 scrub(env)」이라는 다층적 사고방식을 설정 파일의 실제 예시로 확인할 수 있습니다. denyRead와 permissions.deny로 키 디렉터리를 이중으로 막고 있는 점, 외부로 나가거나 파괴적인 작업(push / PR 생성 / publish)만 ask로 돌려놓은 점은 그대로 자신의 설정의 밑바탕으로 삼을 수 있습니다.

6. 걸리기 쉬운 지점

샌드박스는 중첩할 수 없다

이번 검증은, 쓰기 대상을 작업 폴더로 제한하고 홈 디렉터리의 읽기를 금지한 격리 환경 안에서 실행했습니다. 그 안에서 4-4의 sandbox-exec를 실행하려고 했더니, 세 번 모두 다음 오류로 실패했습니다.

코드
sandbox-exec: sandbox_apply: Operation not permitted

즉, 이미 샌드박스 안에 있는 프로세스에서 추가로 sandbox-exec으로 중첩 샌드박스를 만들 수는 없습니다. 이 제약 때문에 격리 환경 안에서는 4-4 데모를 직접 시연할 수 없었습니다. 4-4는 샌드박스화되어 있지 않은 일반 셸에서 실행하세요.

이건 실무에서도 영향을 줍니다. CI 러너 안이나, 이미 샌드박스 아래에서 동작 중인 AI 에이전트 내부에서 sandbox-exec으로 추가 격리를 넣으려고 해도 같은 벽에 부딪힙니다. 중첩 격리가 필요한 경우에는 Seatbelt(Tier 1) 대신 Docker Sandbox나 container microVM(Tier 2) 같은 다른 계층의 가상화를 선택하게 됩니다.

환경 변수에 둔 비밀 정보는 격리 밖에 있다

원 리포지토리가 강조하듯이, OS 샌드박스는 환경 변수를 격리하지 않습니다. 셸 환경 변수에 토큰을 넣어두면 격리된 프로세스에서도 그대로 읽을 수 있습니다. 실제로 확보한 settings.user.json에서도 CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1로 서브프로세스에 전달할 환경 변수를 제거하고 있어, “파일의 denyRead만으로는 부족하고 환경 변수 scrub도 필요하다”는 점을 설정에서 읽어낼 수 있습니다. 토큰류는 dotfile이나 환경 변수가 아니라 Keychain 같은 자격 증명 저장소에 두세요.

sandbox-exec는 deprecated 취급이다

sandbox-exec는 Apple이 deprecated로 두었지만, 현재의 macOS에도 함께 포함되어 있습니다(이번 검증에서도 /usr/bin/sandbox-exec에 존재). 지금은 사용할 수 있지만, 향후 OS 업데이트에서 동작이 바뀔 가능성은 염두에 두어야 합니다. 지속적으로 사용할 격리는 각 도구의 기본 샌드박스 설정(이번 settings.user.json 등)이나 Tier 2의 가상화 쪽으로 맞추는 것이 안전합니다.

7. 정리

  • OS 수준의 격리(파일 스코프 + egress 기본 거부)는 허가 다이얼로그보다 강한 경계가 된다
  • 우선 설정 리포지토리를 가져와 검토하고, sandbox-exec의 최소 프로파일로 동작을 체감해보는 것이 안전한 진입점이다
  • 다만 이 방식은 실험적이며 “결정적인 공격자를 가두는” 것은 아니다. 기밀 데이터를 다루는 작업에는 사용하지 않는다

8. 참고

  • 위 리포지토리의 configs/(각 도구 설정) 및 docs/(위협 모델·각 도구 가이드·강제 배포 설명) 디렉터리

출처

  • 원문: https://zenn.dev/kenshoya/articles/20260927-ai-coding-assistant-sandboxing (2026-09-27 · 検証屋)

자료 변경 기록을 불러오는 중입니다.

다음 자료를 불러오는 중입니다.

후기

아직 후기가 없습니다

직접 적용한 결과와 주의할 점을 공유하는 공간입니다.

로그인하고 후기 쓰기

참고 자료 · 도구와 릴리스 노트

댓글