
에이전트에게는 실제 샌드박스 (Sandboxes)가 필요합니다
요약
코딩 에이전트의 자율성이 높아짐에 따라 발생할 수 있는 보안 위협과 이를 방지하기 위한 격리 환경의 필요성을 다룹니다. Docker는 에이전트가 로컬 환경을 손상시키지 않도록 마이크로VM 기반의 Docker Sandboxes를 제안합니다.
핵심 포인트
- 에이전트의 자율성 증가는 보안 위협 모델의 변화를 의미함
- 프롬프트 수준의 가드레일만으로는 물리적 데이터 보호에 한계가 있음
- Docker Sandboxes를 통한 마이크로VM 기반의 격리 환경 필요성
- 에이전트의 실행 권한과 폭발 반경(blast radius) 관리의 중요성
AI DevCon London에서 저는 약간 우스꽝스러운 제목의 강연을 했습니다: "당신 말이 전적으로 맞아요, 그건 당신의 홈 디렉토리였어요!"
이 제목은 몇몇 웃음을 자아냈는데, 그 무서운 버전이 상상하기 쉽기 때문입니다. 코딩 에이전트 (coding agent)에게 작업을 부여하고, 5초마다 허가를 요청하지 않는 편리한 모드를 활성화하면, 에이전트는 자신 있게 무언가 잘못된 일을 저지릅니다.
당신의 홈 디렉토리를 삭제하는 것 같은 일 말이죠. 안녕, gpt-5.6 Sol 👋.
덜 웃긴 버전은 파일을 삭제하는 것보다 더 광범위합니다. 에이전트가 당신의 소스 코드, API 토큰, SSH 키, 브라우저 상태, 로컬 데이터베이스, 내부 문서, 테스트 자격 증명, 그리고 그 외 개발자 머신의 고고학적 유물들과 동일한 머신에 앉아 있는 상황입니다.
저는 Docker에서 AI 관련 개발자 도구(developer tooling)를 담당하고 있으며, 저희가 작업해 온 것 중 하나는 Docker Sandboxes: 코딩 에이전트를 로컬에서 실행하기 위한 격리된 마이크로VM (microVM) 환경입니다. 강연의 주제는 로컬 에이전트 격리(local agent isolation)에 관한 것이었습니다. 즉, 에이전트가 무엇을 할 수 있어야 하는지, 무엇을 건드려서는 안 되는지, 그리고 에이전트가 당신을 대신하여 행동할 수 있게 되었을 때 왜 프롬프트 수준의 가드레일 (prompt-level guardrails)만으로는 충분하지 않은지에 대한 내용이었습니다.
Tessl은 또한 이 AI DevCon 강연을 에이전트가 컨텍스트 (context)로 사용할 수 있는 기술로 변환했습니다: talk-selajev-docker-sandboxes-agents. 또는, 전통적인 방식을 선호하신다면 에이전트가 녹화 영상을 시청하게 하세요:
.
얼리 버드 할인을 받으려면 등록하세요
자율성 (Autonomy)은 위협 모델 (threat model)을 변화시킵니다
우리는 에이전트가 우리를 위해 더 많은 일을 해주기를 원합니다. 그렇지 않다면 우리는 그냥 자동 완성 (autocomplete) 기능만 계속 사용하고 끝냈을 것입니다.
하지만 에이전트 (agent)가 유용해질수록, 자동으로 맡게 되는 책임도 커집니다. "도움이 된다"는 것은 곧 "행동할 수 있다"는 것을 의미하기 때문에, 그에 따라 폭발 반경 (blast radius)도 커집니다.
생산성은 스펙트럼입니다. 한쪽 끝에는 자동 완성 (autocomplete)과 채팅 어시스턴트 (chat assistants)가 있습니다. 이들은 코드를 제안하고, 사용자는 이를 검토하며, 무엇을 붙여넣을지, 실행할지, 또는 커밋 (commit)할지를 결정합니다. 여전히 인간이 대부분의 작업을 수행합니다.
다른 쪽 끝에는 목표를 부여받고 경로를 찾아내는 에이전트 (agents)가 있습니다. 이들은 파일을 검토합니다. 명령어를 실행합니다. 패키지를 설치합니다. 서비스를 시작합니다. 무언가 실패하면 재시도합니다. 로그를 읽습니다. 코드를 다시 작성합니다. 심지어 다른 에이전트들과 협업하기도 합니다.
이러한 방향성은 유용하며, 바로 이 지점에서 기존의 로컬 개발 (local-development) 위협 모델 (threat model)이 더 이상 들어맞지 않게 됩니다.
자율성 (autonomy)이 높아진다는 것은 사용자를 대신해 더 많은 행동을 취한다는 것을 의미합니다. 승인 프롬프트 (approval prompts)가 줄어든다는 것은 무언가 이상하다는 것을 인간이 알아차릴 기회가 줄어든다는 것을 의미합니다. 로컬 실행 (Local execution)은 에이전트가 개발자들이 매일 사용하는 파일, 도구, 토큰 (tokens), 그리고 환경 (environments)에 밀접하게 접근해 있음을 의미합니다.
강연에서 Liran Tal의 보안 세션을 다시 언급했던 이유는 동일한 위험 모델이 적용되기 때문입니다. 다음 세 가지 요소가 만날 때 상황은 위험해집니다:
- 개인 데이터 (private data);
- 신뢰할 수 없는 콘텐츠 (untrusted content);
- 외부 통신 (external communication).
개인 데이터는 귀하의 코드, 로컬 파일, 자격 증명 (credentials), API 토큰 (API tokens), 설정 (config), 그리고 회사의 컨텍스트 (context)입니다. 신뢰할 수 없는 콘텐츠는 프롬프트 (prompts), 이슈 (issues), 풀 리퀘스트 (pull requests), 이메일, 문서, 리포지토리 (repositories), 또는 웹사이트로부터 올 수 있습니다. 외부 통신은 에이전트가 무언가를 푸시 (pushing), 업로드 (uploading), 게시 (posting)하거나, API를 호출 (calling APIs)하거나, 어딘가로 요청 (requests)을 보내는 것을 의미합니다.
일단 에이전트가 이 세 가지를 결합할 수 있게 되면, 프롬프트 내의 문장 하나는 보안 경계 (security boundary)가 될 수 없습니다.
에이전트는 경계가 아닙니다
프롬프트는 에이전트를 안내할 수는 있습니다. 하지만 파일 시스템 접근 (filesystem access)을 강제할 수는 없습니다. 네트워크 접근 (network access)을 강제할 수도 없습니다. 프로세스 환경 (process environment)으로부터 비밀을 지켜낼 수도 없습니다. 도구가 사용 가능하고 런타임 (runtime)이 허용한다면, 도구가 호출되는 것을 막을 수도 없습니다.
지침 (Instructions)은 유용합니다. 하지만 강제 (Enforcement)는 모델 외부에서 이루어져야 합니다.
데모의 한 부분에서 이 점이 매우 명확하게 드러났습니다. 저는 에이전트에게 CLAUDE.md 편집, 비밀 정보(secrets) 탐색, SSH 키 검사 등 위험한 일을 할 수 있는 충분한 로컬 기술 (local skills)을 부여했습니다. 그런 다음 에이전트에게 동일한 작업을 수행하는 Python 스크립트를 작성하도록 요청했습니다.
에이전트는 스크립트를 작성했습니다. 그러고 나서 그것을 실행하기를 거부했습니다.
그럴 만도 합니다. 가드레일 (guardrail)이 해당 동작의 형태를 감지했기 때문입니다. 그래서 저는 그 형태를 바꾸었습니다. 위험한 코드를 모듈 (module)에 넣은 다음, 그 모듈을 임포트 (import)하여 사용하는 지루한 main.py를 작성하게 했습니다.
에이전트는 여전히 그것을 만들어냈습니다. 그리고 여전히 실행하기를 거부했습니다.
그 후 저는 컨텍스트 (context)를 비우고 프로그램을 실행하라고 요청했습니다.
프로그램은 아주, 아주 잘 실행되었습니다.
모델이 악해진 것이 아닙니다. 그럴 필요도 없었습니다. 가드레일은 대화 (conversation) 속에 존재했고, 대화가 바뀌자 가드레일도 바뀌었습니다. 환경에는 여전히 파일과 도구, 그리고 코드를 실행할 수 있는 능력이 남아 있었습니다.
"이것을 건드리지 마세요"와 "당신은 이것을 건드릴 수 없습니다"는 서로 다른 통제 (control) 방식입니다.
개인용 기기에서 실험하는 개인에게는 이것이 스스로 인지하고 수용하는 위험일지도 모릅니다. 하지만 수많은 개발자에게 코딩 에이전트 (coding agents)를 제공하는 기업에게 "에이전트에게 행동 지침을 전달했다"는 것은 통제 수단이 될 수 없습니다.
에이전트는 에이전트 스스로가 자신에게 복종하는지에 의존하지 않는 경계 (boundary) 안에서 방해받지 않고 작업할 수 있어야 합니다.
컨테이너 (Containers)는 유용하지만, 에이전트는 특이한 워크로드 (workloads)입니다
가장 먼저 떠오르는 명확한 아이디어는 에이전트를 컨테이너 (container)에 넣는 것입니다.
Docker는 컨테이너를 매우 잘 알고 있습니다. 컨테이너는 많은 소프트웨어 문제에 대한 좋은 해답입니다. 애플리케이션을 패키징 (packaging)하고, 의존성 (dependencies)을 실행하며, 반복 가능한 환경을 만드는 데 탁월합니다.
에이전트는 패키징된 애플리케이션과는 조금 다릅니다.
일반적인 컨테이너는 보통 알려진 무언가로부터 시작됩니다. 이미지 (image)에 무엇이 들어갔는지 알고 있습니다. Dockerfile을 검사할 수 있습니다. SBOM을 생성할 수 있습니다. 실행하려는 대상에 대해 추론할 수 있습니다.
에이전트는 작업하는 동안 환경을 변경합니다. 도구(tools)를 설치합니다. 스크립트를 작성합니다. 서비스를 시작합니다. 워크스페이스(workspace)를 편집합니다. 더 많은 컨테이너(containers)를 빌드하고 실행할 수도 있습니다. 에이전트는 환경을 임시 개발 머신으로 변모시킵니다.
그다음에는 격리 경계(isolation boundary)가 있습니다. 컨테이너(Containers)는 호스트 커널(host kernel)을 공유합니다. 이는 많은 워크플로우(workflows)에서 완전히 수용 가능한 트레이드오프(tradeoff)일 수 있습니다. 하지만 민감한 개발자 환경 근처에서 실행되는 자율 에이전트(autonomous agents)에 대해 기업 보안 팀과 이야기할 때, 컨테이너(containers)만으로는 그들이 통상적으로 원하는 경계가 아닙니다.
그 지점에서 마이크로VM(microVMs)이 등장합니다.
마이크로VM(microVM)은 워크플로우(workflow)를 개발자가 기대하는 방식에 가깝게 유지하면서도 더 강력한 격리 경계(isolation boundary)를 제공합니다. 에이전트는 여전히 유용한 리눅스(Linux) 환경을 갖게 됩니다. 여전히 빌드, 테스트, 패키지 설치 및 도구 실행이 가능합니다. 하지만 호스트(host)가 단 한 번의 잘못된 도구 호출(tool call)로 인해 위험해지는 상황은 더 이상 발생하지 않습니다.
샌드박스(sandbox)는 여전히 유용해야 합니다
이 부분은 보안 담당자들이 때때로 인정하고 싶어 하는 것보다 더 중요합니다.
샌드박스(sandbox)를 사용하는 것이 고통스럽다면, 개발자들은 이를 우회할 것입니다.
유용한 에이전트 샌드박스(agent sandbox)는 에이전트가 실제 소프트웨어 작업을 수행할 수 있는 충분한 공간을 제공해야 합니다. 주어진 프로젝트를 검사하고, 빌드를 실행하며, 테스트를 수행하고, 종속된 서비스를 시작하며, 워크플로우(workflow)가 필요할 때 격리된 환경 내부에서 컨테이너(containers)를 사용할 수 있어야 합니다.
흥미로운 점은 기본적으로 허용되지 않는 부분입니다.
호스트 파일 시스템(host filesystem)에 대한 임의의 접근 권한을 가져서는 안 됩니다. 사용자가 무엇을 공유할지 선택해야 합니다. 네트워크 요청(Network requests)은 관찰 가능하고 제어 가능해야 합니다. 비밀 정보(Secrets)가 모델이 읽을 수 있는 무작위 파일로 복사되어서는 안 됩니다. 만약 에이전트가 샌드박스(sandbox)를 손상시킨다면, 그것을 버리고 새로운 것을 생성할 수 있어야 합니다.
이것이 제가 원하는 균형입니다. 사람들이 계속 사용할 수 있을 만큼 충분히 유용하면서도, 이상한 에이전트 실행이 이상한 호스트 머신 사고로 이어지지 않을 만큼 충분히 제한적인 것 말입니다.
라이브 데모에서 저는 샌드박스 (Sandbox) 내부의 익숙한 에이전트 인터페이스로 진입하는 커맨드 라인 (Command-line) 경험을 보여드렸습니다. UI가 특별해 보일 필요는 전혀 없었습니다. 에이전트는 여러분이 이미 사용 중인 에이전트와 똑같이 느껴져야 하며, 단지 여러분의 호스트 (Host) 머신보다 덜 소중한 어딘가에서 실행될 뿐이어야 합니다.
에이전트는 빌드하고, 테스트하고, 탐색하며, 난장판을 만들 수도 있습니다. 다만 그 난장판을 일회성인 어딘가에서 만들 뿐입니다.
에이전트는 권한 (Capability)을 갖는 것이지, 관리권 (Custody)을 갖는 것이 아닙
개발자 머신에는 실제 자격 증명 (Credentials)이 가득합니다. 때로는 의도적으로, 때로는 과거의 흔적으로, 때로는 2021년의 어떤 CLI 설정 가이드가 토큰을 파일에 넣으라고 말해서 아무도 그 존재를 기억하지 못하는 상태로 남아있기도 합니다.
따라서 샌드박스는 비밀 정보 (Secrets)를 에이전트가 볼 수 있는 워크스페이스 (Workspace)로 복사함으로써 인증 (Auth) 문제를 해결해서는 안 됩니다.
제가 설명한 패턴은 센티널 값 (Sentinel values)과 보안 프록시 (Security proxy)를 사용합니다. 에이전트는 필요한 권한을 가진 것처럼 동작할 수 있지만, 실제 자격 증명은 요청이 승인된 서비스로 전달될 때 샌드박스 경계 외부에서 주입됩니다.
비밀 정보가 에이전트가 읽을 수 있는 파일에 놓여 있을 필요는 없습니다.
유용한 사고 모델은 다음과 같습니다: 에이전트는 권한 (Capability)을 갖는 것이지, 관리권 (Custody)을 갖는 것이 아닙니다.
동일한 아이디어를 더 큰 신뢰 워크플로우 (Trusted workflows)에도 적용할 수 있습니다. 커밋 (Commits), 코드 서명 (Code signing), 출처 메타데이터 (Provenance metadata), 그리고 기타 민감한 작업들은 샌드박스 외부에서 또는 제어된 경로를 통해 수행될 수 있습니다. 에이전트는 작업을 완료하기에 충분한 힘을 얻고, 조직은 가장 민감한 자료를 모델이 볼 수 있는 환경으로부터 격리하여 유지합니다.
이것이 에이전트에게 모든 것을 넘겨주지 않으면서도 에이전트를 유용하게 만드는 방법입니다.
빈 샌드박스는 개발자와 접촉하는 순간 살아남지 못합니다
개발자들은 수년에 걸쳐 자신의 머신을 형성해 옵니다. 컴파일러 (Compilers), 패키지 매니저 (Package managers), CLI, 캐시 (Caches), 자격 증명 (Credentials), 닷파일 (Dotfiles), 프로젝트 컨벤션 (Project conventions), 그리고 세 번 전 직장에서 curl | bash로 설치했던 바로 그 도구까지 말입니다. 깨끗한 샌드박스는 매번 아무것도 없는 상태에서 시작하는 것처럼 느껴질 수 있습니다.
만약 사용자 경험이 그러하다면, 사람들은 압박을 받는 순간 샌드박스 밖에서 에이전트를 실행하게 될 것입니다.
한 가지 해결책은 모든 것이 포함된 거대한 베이스 이미지 (base image)를 구축하는 것입니다. 이는 잠시 동안은 효과가 있을 수 있습니다. 하지만 곧 이미지가 너무 커지고, 너무 느려지며, 너무 일반적이고, 유지 관리하기에 너무 번거로워집니다.
제가 보여드린 접근 방식은 샌드박스 키트 (sandbox kits)입니다.
키트 (kit)는 샌드박스를 구성하는 선언적 (declarative) 방식입니다. 실행할 명령, 환경에 배치할 파일, 시작할 프로세스, 네트워크 정책 (network policy), 그리고 비밀 정보 처리 (secret-handling) 설정을 정의할 수 있습니다. 이는 로컬에 존재할 수도 있고, OCI 아티팩트 (artifact)로 공유될 수도 있습니다.
만약 devcontainer 기능을 사용해 본 적이 있다면, 이 방식이 익숙하게 느껴질 것입니다. 즉, 베이스 위에 레이어링된 재사용 가능한 환경 구성입니다. 에이전트 (agent)의 경우, 키트는 네트워크 액세스 (network access)와 비밀 정보 (secrets)까지도 신경 써야 합니다. 여기서는 편의성만이 작업의 절반일 뿐입니다.
데모에서는 이 개념을 보여주기 위해 Testkube 키트를 사용했습니다. 더 중요한 핵심은 벤더 (vendors)와 플랫폼 팀이 개발자에게 실제로 필요한 도구들을 위한 키트를 제공할 수 있다는 점입니다. 테스트 플랫폼, 클라우드 CLI, 언어 툴체인 (language toolchains), 데이터 시스템, 내부 서비스 등 샌드박스를 실제로 작업할 수 있는 공간처럼 느끼게 만드는 것이라면 무엇이든 가능합니다.
docker/sbx-kits-contrib에 공개된 예시들이 있으며, Docker 문서에도 키트 예시 (kit examples)와 에이전트 키트 구축 (building an agent kit)을 위한 가이드가 마련되어 있습니다.
샌드박싱은 기존 도구에 녹아들어야 합니다
샌드박스가 별도의 의식 (ritual)이 되어서는 안 됩니다.
개발자들은 이미 터미널 (terminals), 에디터 (editors), 이슈 트래커 (issue trackers), CLI, 그리고 풀 리퀘스트 (pull requests) 환경에서 생활하고 있습니다. 만약 에이전트를 안전하게 실행하는 것이 그 흐름을 벗어나 번거로운 절차를 거치는 것을 의미한다면, 사람들은 데모를 위해서 한 번은 수행하겠지만 그 이후에는 멈출 것입니다.
커맨드 라인 인체공학 (Command-line ergonomics)이 중요합니다. IDE 통합도 중요합니다. 개발자가 VS Code, IntelliJ IDEA, Zed 또는 다른 에디터에서 에이전트 창을 열었을 때, 에이전트는 호스트 (host)에서 직접 실행되는 대신 샌드박스 내부에서 실행될 수 있어야 합니다.
사용자 경험은 평소와 다름없이 유지되어야 합니다. 내부의 격리 경계(isolation boundary)만 변경되어야 합니다.
컨테이너 (Containers)가 이미 우리에게 이를 가르쳐 주었습니다. 컨테이너가 널리 채택된 이유는 결국 실용적이고, 반복 가능하며, 일상적인 개발 워크플로우 (workflows)에 통합되었기 때문입니다. 에이전트 샌드박스 (Agent sandboxes) 역시 자율적인 작업 (autonomous work)에 부합하는 더 강력한 경계와 제어 기능을 갖추면서도, 동일한 인체공학적 편의성 (ergonomics)을 제공해야 합니다.
샌드박스는 모든 위험이 아닌, 폭발 반경 (blast radius)을 제한합니다
샌드박싱 (Sandboxing)은 경계를 제공합니다. 저는 강연에서 이 점을 주의 깊게 다루려고 노력했습니다.
샌드박스는 로컬 머신 (local-machine)의 폭발 반경 (blast radius)을 줄이는 데 도움을 줍니다. 파일 시스템 접근 (filesystem access), 네트워크 경로 (network paths), 자격 증명 처리 (credential handling), 그리고 일회성 실행 (disposable execution)을 강제할 수 있는 공간을 제공합니다.
애플리케이션 수준의 권한 (Application-level permissions) 또한 여전히 중요합니다.
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기