
낯선 프로그램을 안전하게 가두는 법
어디서 받은 건지도 모르는 실행 파일 하나가 손에 들어왔다고 해볼게요. 이걸 그냥 더블클릭하면요, 최악의 경우 내 문서 폴더를 통째로 지워버리거나, 몰래 네트워크로 내 파일을 어딘가에 보내버릴 수도 있어요. 그래서 나온 개념이 바로 샌드박스(sandbox)예요. 이게 뭐냐면, 아이들이 모래놀이터 밖으로는 모래를 못 가지고 나가듯이, 프로그램도 정해진 울타리 안에서만 놀게 가둬두는 기술이거든요. 안에서 뭘 하든 바깥 세상, 그러니까 내 진짜 시스템에는 손을 못 대게 막는 거죠.
Z-Jail은 이 샌드박스를 좀 특이한 방식으로 만든 프로젝트예요. 크기가 겨우 130KB밖에 안 되고, 다른 라이브러리에 하나도 기대지 않은 순수 C99 코드로만 짜여 있어요. 요즘 스마트폰 사진 한 장보다도 훨씬 작은 용량인데, 그 안에 무려 7겹의 방어벽이 들어있다는 게 이 프로젝트의 자랑거리예요.
7겹 방어벽, 하나씩 뜯어볼게요
사실 리눅스 커널에는 원래부터 프로그램을 가둬두는 도구들이 여기저기 흩어져 있어요. Z-Jail은 이걸 하나만 쓰는 게 아니라 겹겹이 쌓아 올려서, 한 겹이 뚫려도 다음 겹이 막아주는 구조를 만들어요. 이런 걸 심층 방어(defense in depth)라고 부르거든요.
첫 번째 핵심은 네임스페이스(namespace)예요. 이게 뭐냐면, 프로그램한테 "너만의 세상"을 새로 하나 만들어주는 거예요. 예를 들어 PID 네임스페이스를 씌우면 그 프로그램은 자기가 세상에 혼자 있는 1번 프로세스인 줄 알아요. 네트워크 네임스페이스를 주면 인터넷 연결 자체를 아예 못 보게 되고요. 마운트 네임스페이스로는 볼 수 있는 폴더를 확 줄여버리죠. 우리가 많이 쓰는 도커(Docker) 컨테이너의 핵심 원리가 바로 이 네임스페이스예요.
두 번째는 seccomp라는 기능이에요. 프로그램이 커널한테 뭔가 부탁할 때 쓰는 게 시스템 콜(system call)인데요. 파일 열기, 네트워크 접속, 메모리 요청 같은 게 전부 시스템 콜이에요. seccomp는 여기서 "이 프로그램은 딱 이 목록에 있는 시스템 콜만 써, 나머지 위험한 걸 부르는 순간 강제로 죽여버릴 거야"라고 화이트리스트를 걸어두는 거예요. 공격자가 커널을 건드리는 통로 자체를 좁혀버리는 거죠.
여기에 더해서 cgroups로는 CPU와 메모리를 얼마까지만 쓰게 상한선을 걸어요. 악성 코드가 무한 루프로 메모리를 다 먹어치우는 사고를 막는 거죠. capability 떨구기는 원래 통짜였던 루트(관리자) 권한을 잘게 쪼갠 다음, 필요 없는 권한은 다 버려서 위험한 작업을 아예 못 하게 만드는 거고요. no_new_privs는 실행 도중에 새 권한을 몰래 얻는 걸 잠가버려요. 마지막으로 pivot_root 같은 걸로 루트 디렉토리를 가짜로 바꿔치기해서, 진짜 파일 시스템을 아예 구경도 못 하게 하죠.
'작고 의존성 없음'이 왜 중요할까
여기서 궁금할 수 있어요. 도커도 있고 좋은 도구 많은데 왜 굳이 130KB짜리를 만들었을까요? 핵심은 공격 표면(attack surface)이에요. 코드가 많으면 그만큼 버그가 숨어있을 자리도 많아지거든요. 보안 도구인데 정작 그 도구 자체에 구멍이 있으면 말이 안 되잖아요. Z-Jail은 코드가 워낙 작아서 사람이 직접 한 줄 한 줄 다 읽고 검증(audit)하기가 쉬워요. 의존성이 0개라는 것도 큰데요, 남의 라이브러리를 안 갖다 쓰니까 그 라이브러리에서 터지는 취약점에 휘말릴 일이 없어요.
비슷한 도구로는 구글이 만든 gVisor(시스템 콜을 통째로 가로채는 방식), nsjail, 그리고 Flatpak 앱들이 쓰는 bubblewrap, 데스크톱용 Firejail 같은 게 있어요. 이것들과 비교하면 Z-Jail은 기능이 화려하다기보다는, 극단적으로 작고 단순해서 어디든 끼워 넣기 쉽다는 쪽으로 승부를 보는 프로젝트예요.
한국 개발자에게 주는 시사점
이런 경량 샌드박스는 생각보다 쓸 데가 많아요. 온라인 코딩 테스트나 백준 같은 채점 서버는 사용자가 제출한 코드를 서버에서 실행해야 하잖아요? 그 코드가 무슨 짓을 할지 모르니까 반드시 가둬서 돌려야 해요. 요즘 뜨거운 AI 에이전트도 마찬가지예요. LLM이 만들어낸 코드를 실제로 실행시켜야 할 때, 이런 샌드박스가 안전벨트 역할을 해주거든요. CTF 문제 서버나 서버리스 함수 실행 환경에서도 딱이고요.
무엇보다 이 프로젝트는 리눅스 보안의 밑바닥을 공부하기에 정말 좋은 교재예요. 네임스페이스, seccomp, cgroups 같은 개념은 도커를 그냥 쓸 때는 안 보이다가, 문제가 터지면 반드시 발목을 잡는 것들이거든요. 코드가 작으니까 한번 통독해보면서 "컨테이너가 실제로 어떻게 격리를 만드는가"를 눈으로 확인해볼 만해요.
한줄 정리: 화려한 기능 대신 극단적인 단순함과 검증 가능성으로 승부하는, 리눅스 격리 기술의 정수를 담은 130KB짜리 교과서 같은 프로젝트예요.
여러분은 신뢰할 수 없는 코드를 실행해야 할 때 도커 같은 무거운 컨테이너를 쓰나요, 아니면 이런 경량 샌드박스가 더 매력적으로 느껴지나요? 실무에서 격리 때문에 고생했던 경험이 있다면 나눠주세요.
🔗 출처: Hacker News