BubbleWrap으로 개발 환경과 LLM 에이전트를 격리해 시스템을 의존성과 악성 코드로부터 어느 정도 보호하면서도 기존 개발 경험을 거의 유지하는 방법을 소개합니다.
홈»글»BubbleWrap으로 개발 환경과 에이전트 격리하기
2026-03-25·4분·
좋아요, 세상은 무너지고 있고, 모든 것이 해킹당하고 있으며, 모든 의존성은 아마 키를 훔치고 암호화폐를 채굴하고 있을 것이고, 슬롭은 어디에나 있고, 나도 그 문제의 일부입니다.
그럼 나는 뭘 할까요? 격리하겠습니다!
이건 오래전부터 생각하고 있었지만, 최근에야 LLM 에이전트가 충분히 쓸 만해져서, 그들이 실행하려는 모든 명령을 일일이 지켜보지 않아도 실제로 유용하다고 느끼게 되었습니다.
그래서 목표는 다음과 같습니다:
마지막 항목 때문에, 별도의 사용자 계정이나 별도의 VM을 쓰거나 Docker를 가지고 놀 생각은 없습니다.
제가 하려는 것은 BubbleWrap을 사용해서 호스트 시스템과 홈 디렉터리의 일부만 다시 마운트하고, 그중 대부분은 읽기 전용 모드로 두는 것입니다. 이렇게 하면 제 도구와 전반적인 DX는 거의 완전히 동일하게 유지되지만, Slopus가 정신이 나가거나 암호화폐 채굴 악성코드를 끌어오더라도, 가할 수 있는 피해에는 한계가 생깁니다.
그래서 이 시스템의 핵심은 isolate 스크립트입니다:
#!/usr/bin/env bash
set -euo pipefail
# Skip re-isolating if already inside an isolated environment
if [[ -n "${ISOLATE_ENV:-}" ]]; then
>&2 echo "warning: already isolated"
exec "$@"
fi
tiocsti_path="/proc/sys/dev/tty/legacy_tiocsti"
if [ ! -f "$tiocsti_path" ] || [ "$(cat "$tiocsti_path")" != "0" ]; then
>&2 echo "warning: TIOCSTI not disabled"
fi
args=()
args+=(
--dev-bind /dev /dev \
--proc /proc \
--tmpfs /tmp \
--tmpfs /run \
--setenv PROMPT_ENV_INDICATOR "isolated" \
--setenv ISOLATE_ENV "$(pwd)"
)
for p in \
/bin \
/usr/bin \
/etc \
/nix \
/run/current-system \
"$HOME/bin" \
"$HOME/.config" \
"$HOME/nix/dot" \
"$HOME/.gitconfig" \
"$HOME/.nix-profile" \
"$HOME/.local/share/direnv/allow/" \
; do
args+=(--ro-bind "$p" "$p")
done
for p in \
"$HOME/.cargo" \
"$HOME/.claude" \
"$HOME/.claude.json" \
"$HOME/nix/dot/.claude" \
"$XDG_RUNTIME_DIR/gnupg/S.gpg-agent" \
"$(pwd)"\
; do
args+=(--bind "$p" "$p")
done
if [[ -n "${NIRI_SOCKET:-}" && -S "$NIRI_SOCKET" ]]; then
args+=(--bind "$NIRI_SOCKET" "$NIRI_SOCKET")
args+=(--setenv NIRI_SOCKET "$NIRI_SOCKET")
fi
args+=(
--dir "$HOME/.gnupg" \
--chmod 0700 "$HOME/.gnupg" \
)
# Source extra config (e.g. set by auto-isolate) to allow
# project-specific additions to args
if [[ -n "${ISOLATE_EXTRA_CONFIG:-}" && -f "$ISOLATE_EXTRA_CONFIG" ]]; then
source "$ISOLATE_EXTRA_CONFIG"
# Hide the config file inside the sandbox by overlaying /dev/null
args+=(--ro-bind /dev/null "$ISOLATE_EXTRA_CONFIG")
fi
exec bwrap \
"${args[@]}" \
"$@"
여기서 모든 세부 사항을 설명하느라 시간을 쓰지는 않겠습니다. Bubblewrap 문서를 읽거나, 가까운 LLM에게 물어보세요.
하지만 이와 같거나 비슷한 방식을 하려는 독자라면, 각 경로를 하나씩 살펴보며 그 의미를 검토해보는 것이 좋을 것입니다. 예를 들어 저는 제법 복잡한 Yubikey SSH/GPG 설정을 사용하고 있고, 어딘가에 ssh할 때마다 하드웨어 yubikey를 직접 터치해야 합니다. 그래서 ssh/gpg 소켓을 격리된 환경에 마운트하는 것을 두려워하지 않습니다.
어쨌든 요약하면, isolate는 주어진 명령을 현재 작업 디렉터리만 거의 유일하게 쓰기 가능한 환경에서 실행합니다. 나머지는 동작에 필요한 최소한의 부분만, 그것도 대부분 읽기 전용 모드로 제공합니다. 대충, 거의 그렇습니다. 여기서의 목표는 DX를 거의 희생하지 않으면서도 충분히 괜찮은 수준의 보안성과 견고함을 얻는 것입니다.
Nix를 쓰고 있기 때문에, 제가 이 isolate 스크립트로 가장 먼저 감쌀 대상은 Slopus입니다. 그 친구에게 중요한 것들에 대한 전체 접근 권한을 직접 주어서는 절대 안 됩니다.
제 시스템의 flake.nix 안 메인 오버레이에는 대략 이런 식의 코드가 있습니다:
claude-code =
let
orig = pkgs-unstable.claude-code;
in
final.writeShellScriptBin "claude" ''
exec env CARGO_TERM_QUIET=true PATH="${final.not-git}/bin:$PATH" ${./dot/bin/isolate} ${orig}/bin/claude "$@"
'';
이렇게 하면 Slopus는 항상 격리된 환경에서 시작하므로, 제가 깜빡할 수가 없습니다. 또 git을 Jujutsu를 사용하고 있다고 Slopus에게 상기시키는 래퍼로 바꾸고, cargo build는 기본적으로 덜 시끄럽게 만들어 토큰을 조금이라도 아낄 수 있게 합니다.
그다음에는 작업 중인 모든 프로젝트에서 격리된 환경에 들어가는 일을 자동화하고 싶었습니다.
그걸 위해 auto-isolate가 있습니다:
#!/usr/bin/env bash
set -euo pipefail
if [[ ! -x "$HOME/bin/isolate" ]]; then
>&2 echo "warning: $HOME/bin/isolate not found, skipping isolation"
exec "$@"
fi
dir="$(pwd)"
while true; do
if [[ -f "$dir/.isolate" ]]; then
exec env ISOLATE_EXTRA_CONFIG="$dir/.isolate" $HOME/bin/isolate "$@"
fi
if [[ "$dir" == "/" ]]; then
break
fi
dir="$(dirname "$dir")"
done
exec "$@"
auto-isolate는 현재 작업 디렉터리나 그 상위 디렉터리들 어디에서든 .isolate를 찾을 수 있으면, 주어진 명령에 대해 자동으로 isolate를 호출합니다.
셸 시작 파일에 연결할 수도 있겠지만, 저는 CLI 작업 흐름이 tmux에 깊게 뿌리내린 전체 시스템을 갖고 있기 때문에 ~/.config/tmux/tmux.conf에 이렇게 넣을 생각입니다:
set-option -g default-command "$HOME/bin/auto-isolate ${SHELL}"
# in case I want to actually do something outside of the isolated env constrains
bind E new-window "${SHELL}"
이렇게 하면 tmux에서 새 pane을 시작할 때마다 auto-isolate가 실행됩니다. 이제 touch ~/lab/.isolate만 해두면, 제 모든 개발 프로젝트가 항상 ~/lab 안에 있기 때문에 프로젝트를 isolate하는 걸 사실상 절대 잊을 수 없습니다.
앞서 눈치챘을지 모르겠지만, isolate 스크립트는 ISOLATE_EXTRA_CONFIG를 지원해서 격리된 환경에 프로젝트별 수정 사항을 추가할 수 있습니다. 예를 들어 제가 작업 중인 작은 GUI 프로젝트에서는 다음과 같은 .isolate 파일을 만들어야 했습니다:
if [[ -n "$WAYLAND_DISPLAY" ]]; then
args+=(--ro-bind "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY" "$XDG_RUNTIME_DIR/$WAYLAND_DISPLAY")
fi
args+=(
--bind /dev/dri/ /dev/dri/ \
--bind /dev/shm /dev/shm \
--bind /tmp/.X11-unix/ /tmp/.X11-unix/ \
--bind /run/opengl-driver/lib/ /run/opengl-driver/lib/
)
그래야 cargo r를 실행할 때 UI를 보여줄 수 있습니다.