2016년 '500줄 리눅스 컨테이너' 글이 해커뉴스에 다시 올라와, 댓글은 Firecracker·gVisor 격리 논쟁
- 2016년 공개된 리지오(lizzie.io)의 Linux containers in 500 lines of code는 네임스페이스, 케퍼빌리티, cgroup, setrlimit, seccomp를 조합해 신뢰할 수 없는 코드를 돌리는 최소 제약 집합을 리터레이트 코드로 보여줌. 원래 500줄이었으나 개정을 거치며 약 70줄 늘어남
contained.c는sudo ./contained -m ~/misc/busybox-img/ -u 0 -c /bin/sh형태로 이미지 디렉터리, uid, 명령을 지정해 실행하며, 저자는 커널 4.7.10 grsec x86_64에서 검증함- 저자는 컨테이너를 보안 경계로 다루지 않고 중첩 유저 네임스페이스를 막으며, 유저 네임스페이스가 있을 때만 사용함. 유저 네임스페이스를 켜면 커널 전역 케퍼빌리티 의미가 바뀌고 권한 상승 버그가 다수 나왔다는 NCC Group 백서를 근거로 듦
- 해커뉴스에는 2017년 440점(댓글 53개), 2020년 267점(29개), 2022년 250점(27개)으로 세 번 올라왔고, 댓글은 Firecracker, gVisor, Kata Containers, Podman libkrun을 대안으로 언급함
- 댓글에서는 컨테이너가 보안 경계인지 두고 의견이 갈림. 한쪽은 컨테이너가 'curl 파이프가 내 dotfile을 망가뜨리지 않게' 막는 수준이라며 VM 기반 샌드박스를 권하고, 다른 쪽은 보안 경계도 상대적 강도일 뿐이라고 반박함
Hacker News 의견들
저자는 신뢰할 수 없는 코드 돌릴 최소 제약 집합을 찾는다는데, 난 컨테이너를 보안 경계로 보면 안 된다고 봄. VM도 탈출당한 사례가 수도 없이 있으니 근본적으로 다른 접근이 필요함
그런 용도면 Firecracker, gVisor, Kata Containers가 답이라고 봄. VM 프리미티브 쓰면서 코드베이스도 가볍더라. Kata가 Firecracker를 백엔드로 쓸 수 있으니 격리 기준으로는 Firecracker나 gVisor 둘 중 하나임. gVisor는 유저스페이스 커널에 가까움
공유 커널 쓰는 리눅스 컨테이너는 지금 믿을 게 못 됨. 올해만 LPE랑 컨테이너 탈출 취약점이 너무 많이 나왔음. 커널이 훨씬 단단해지면 모를까 Firecracker 쪽이 보안상 낫다
Podman은 libkrun으로 KVM 기반 컨테이너를 돌릴 수 있음. podman run --runtime=krun 이거. 만능 보안 경계는 아니어도 낫긴 함
위협 모델 나름임. 보안은 흑백이 아니고, 컨테이너는 'curl 파이프가 내 dotfile을 다 뒤엎지는 않게' 막아주는 수준임. VM도 부족한 위협 모델이라면 뭐가 충분한지 궁금함
CHERI 같은 하드웨어 기반 격리가 널리 깔리기 전까지는 VM 탈출 CVE가 계속 나올 거라고 봄. 근시일 내에 그럴 가능성은 거의 없어 보이고
컨테이너도 보안 경계임. 다른 것들처럼 완벽하지 않을 뿐임. 이 정의대로면 세상에 보안 경계라는 게 없고 그냥 '보안을 어렵게 만드는 것'만 있음
난 코딩 에이전트용으로 프로젝트마다 bubblewrap 스크립트를 씀
비슷한 걸 예전에 쓴 적 있음. 컨테이너를 밑바닥부터 만드는 글이었음
2016년 글인데 지금 쓰면 뭐가 달라질까? cgroups v2나 새 seccomp 기능이 크게 바꿀까 궁금함
새 세대 샌드박싱 기술도 궁금함. nolabs-ai/nono 같은 거
요즘 claude code에 토이 프로젝트 시키다가 '도커 위에서' 말고 '도커처럼'이라고 잘못 프롬프트했는데 토큰 다 태우면서 도커 클론을 만들어버렸음. 대단하긴 한데
어젯밤에 Graphviz를 신뢰할 수 없는 입력에 돌릴 방법을 찾고 있었음. Harfbuzz, Pango, libfribidi, libthai, libgraphite2에 자체 파서까지 CVE 이력이 장난 아님. Pango는 멀티스레드라 비결정적이기까지 함. ldd로는 안 보이고 런타임에 dlopen함
결국 Bubblewrap으로 500줄도 안 되게 감쌌음. 메모리 64MB, CPU 5초 제한으로 dot을 돌려서 stdin 받고 PNG를 stdout으로 냄. 64메가면 충분하고 21메가는 부족했음