MicroPython·WASM으로 샌드박스에서 파이썬 코드 실행
Source: Hacker News
2026년 6월 6일
몇 년 동안 샌드박스에서 코드를 실행하는 다양한 접근 방식을 실험해 왔지만, 이번 시도가 내가 찾고 있던 모든 특성을 finally 갖춘 것처럼 느껴집니다. 알파 패키지인 micropython-wasm을 공개했으며, 이를 Datasette Agent용 코드 실행 샌드박스 플러그인인 datasette-agent-micropython에도 사용하고 있습니다.
왜 샌드박스가 필요한가?
내 주요 오픈소스 프로젝트—Datasette, LLM, 심지어 sqlite-utils—모두 플러그인을 지원합니다.
플러그인은 소프트웨어를 확장하는 메커니즘으로서 나는 정말 사랑합니다. 신중하게 설계된 플러그인 시스템은 새로운 시도를 할 때 발생할 위험을 거의 없애 줍니다—가장 기발한 아이디어라도 코어 애플리케이션 자체에 지속적인 영향을 남기지 않죠. 내 소프트웨어는 하룻밤 사이에 새로운 기능을 추가할 수 있고, 나는 풀 리퀘스트를 검토할 필요조차 없습니다!
하지만 한 가지 큰 단점이 있습니다: 내 플러그인 시스템은 모두 Python과 Pluggy를 사용하고, 플러그인 코드는 내 애플리케이션 안에서 완전한 권한으로 실행됩니다. 버그가 있거나 악의적인 플러그인은 모든 것을 망치거나 개인 데이터를 유출할 수 있습니다.
승인되지 않은 파일을 읽거나, 네트워크에 연결하거나, 애플리케이션이나 사용자의 컴퓨터에 위험하거나 해로운 방식으로 동작하지 못하도록, 플러그인 스타일 코드를 격리된 환경에서 실행하고 싶습니다.
관심은 플러그인에만 국한되지 않습니다. 특히 Datasette에서는 임의 코드 실행이 유용할 수 있는 기능이 많이 있습니다. 이미 Datasette Enrichments에서 코드를 사용해 테이블에 저장된 값을 변환하는 실험을 해봤습니다. 승인된 위치에서 JSON을 가져와, 작은 코드를 실행해 딕셔너리 리스트로 재포맷한 뒤, 이를 SQLite 데이터베이스 테이블에 행으로 삽입하는 스케줄러 메커니즘을 만들고 싶습니다.
샌드박스에 기대하는 것
내 목표는 내 Python 애플리케이션 안에서 코드를 안전하게 실행하는 것입니다. 필요한 조건은 다음과 같습니다:
-
PyPI에서 깔끔하게 설치 가능한 의존성, 필요하다면 여러 플랫폼용 바이너리 휠도 포함. 사용자가 내 패키지를 직접 설치하는 것 외에 추가적인 절차를 밟게 하고 싶지 않습니다.
-
실행되는 코드는 메모리와 CPU 제한을 받아야 합니다.
while True: s += "longer string"같은 무한 루프로 내 애플리케이션이나 사용자의 컴퓨터가 다운되는 일을 원하지 않습니다. -
파일 접근은 엄격히 통제되어야 합니다. 파일 시스템 접근을 전혀 허용하지 않거나, 읽을 수 있는 파일과 쓸 수 있는 파일을 정확히 정의하고 싶습니다.
-
네트워크 접근도 통제되어야 합니다. 샌드박스 코드가 내가 완전히 제어하는 레이어를 거치지 않고는 외부와 통신할 수 없어야 합니다.
-
호스트 함수와의 상호작용을 지원해야 합니다. 선택된 플랫폼 기능을 코드에 안전하게 노출하지 못한다면 샌드박스는 별 의미가 없습니다.
-
견고하고, 지원이 지속되며, 명확히 문서화된 것이어야 합니다. 유지보수가 중단된 샌드박스 프로젝트를 본 적이 너무 많습니다!
WebAssembly가 여기서 정말 유망해 보인다
웹 브라우저는 악성 코드에 대해 상상할 수 있는 가장 적대적인 환경에서 동작합니다. 브라우저의 역할은 거의 모든 페이지 로드 시 신뢰할 수 없는 코드를 다운로드하고 실행하는 것이기 때문이죠.
이 점에서 JavaScript 엔진은 샌드박스로서 훌륭한 후보가 될 수 있습니다. 안타깝게도 이러한 엔진은 매우 복잡하고, 다른 프로젝트에 쉽게 임베드하도록 설계되지 않았습니다. 제가 본 대부분의 V8‑in‑Python 프로젝트는 유지보수가 드물고, 완전히 신뢰할 수 없는 코드와 함께 사용하지 말라는 경고가 붙어 있습니다.
WebAssembly는 훨씬 더 좋은 후보입니다. 처음부터 내가 중요하게 생각하는 모든 특성을 지원하도록 설계되었고, 거의 10년 동안 브라우저에서 검증되었습니다. wasmtime Python 라이브러리는 WASM을 Python에 도입하고, 활발히 유지보수되며 바이너리 휠도 제공합니다.
WebAssembly에서의 MicroPython
wasmtime 같은 WebAssembly 엔진은 WebAssembly 바이너리를 실행합니다. Rust와 같이 직접 WebAssembly로 컴파일하기 쉬운 언어도 있지만, JavaScript나 Python 같은 동적 언어는 eval() 같은 언어 원시 기능을 지원하기 때문에 런타임에 전체 인터프리터가 필요합니다.
Python을 실행하려면 WebAssembly로 컴파일된 전체 Python 인터프리터가 필요하고, 코드를 주입하고 호스트 함수를 연결하며 결과에 접근하기 쉬운 형태로 구성되어야 합니다.
Pyodide는 브라우저에서 WebAssembly를 이용해 Python을 실행하는 훌륭한 패키지를 제공하지만, 서버‑사이드 Python에서 Pyodide를 사용하는 것은 지원되지 않습니다. 가장 최신의 정보는 2024년 10월 에서 “Pyodide는 Emscripten 툴체인으로 빌드되며 브라우저나 Node.js에서만 실행될 수 있다”는 것이었습니다.
그때 나는 이 목적을 위해 MicroPython을 살펴보기로 했습니다. MicroPython 사이트는 이렇게 말합니다:
MicroPython은 Python 3 프로그래밍 언어의 가볍고 효율적인 구현으로, Python 표준 라이브러리의 작은 부분만 포함하고 마이크로컨트롤러와 제한된 환경에서 실행되도록 최적화되었습니다.
WebAssembly는 바로 그런 제한된 환경이라고 생각합니다!
첫 번째 버전 만들기
나는 GPT‑5.5 Pro에게 조사를 맡겼습니다(링크). 그 결과 Yamamoto Takahashi 가 만든 “Experimental WASI support for ports/unix”라는 제목의 MicroPython PR을 찾았습니다.
그 후 이 research.md 문서를 만들었고, Codex Desktop과 GPT‑5.5에게 자유롭게 작업을 시켰습니다(예시):
research.md 문서를 읽고 이것을 빌드하세요. 프로젝트의 일환으로 MicroPython 코드를 /tmp 디렉터리로 가져와 맞춤형 WASM 버전을 컴파일하는 스크립트를 작성해야 할 수도 있습니다.
결과는 성공했습니다. 이제 WebAssembly 샌드박스 안에서 Python 코드를 실행할 수 있는 프로토타입 Python 라이브러리가 생겼습니다!
가장 까다로운 문제는 인터프리터 상태의 지속성이었습니다. 현재 사용 중인 WASM 빌드는 인터프리터를 시작하고 코드를 실행한 뒤 종료하는 단일 진입점을 제공합니다.
이는 일회성 스크립트에는 잘 동작하지만, Datasette Agent에서는 변수와 함수를 메모리에 유지해 여러 번의 코드 실행 호출에서 재사용하고 싶습니다.
코딩 에이전트를 활용하면 아이디어 단계에서 프로토타입까지 빠르게 진행할 수 있다는 점이 매력적입니다.