LabHub

컨테이너 보안 · 탈출 경로와 그것을 막는 법 · 이론

컨테이너를 여는 네 개의 문

LabHub 에서 이어서 보기

한 줄 요약

컨테이너 탈출은 대개 커널 취약점이 아니라 우리가 직접 열어 둔 설정에서
일어납니다. 네 가지 패턴을 알면 리뷰에서 30초 만에 잡을 수 있습니다.

> 이 레슨은 방어를 위한 것입니다. 각 항목마다 "왜 위험한가"와
> "무엇으로 막는가"를 짝지어 다룹니다.

왜 이게 필요했나

컨테이너가 비root인지 확인하는 것만으로는 호스트 경계를 증명할 수 없습니다.
도커 소켓, 호스트 파일시스템, PID 네임스페이스나 과도한 capability를 열면
컨테이너 안의 낮은 권한 프로세스도 호스트 권한을 우회해 획득할 수 있습니다.
따라서 이미지 사용자뿐 아니라 런타임에 연결한 자원과 커널 권한을 함께 리뷰해야 합니다.

문 1 — 도커 소켓 마운트

volumes:  - /var/run/docker.sock:/var/run/docker.sock

CI 러너나 모니터링 에이전트에서 흔히 보이는 줄입니다. 이 소켓은 도커
데몬의 API 이고, 데몬은 호스트의 root 로 돕니다. 소켓에 접근할 수 있으면
호스트 루트를 통째로 마운트한 특권 컨테이너를 새로 띄울 수 있습니다.
즉 이 한 줄은 사실상 호스트 root 권한을 주는 것과 같습니다.

막는 법 — 소켓을 컨테이너에 주지 않습니다. 컨테이너 빌드가 필요하면
데몬이 필요 없는 빌더(kaniko, buildah)를 쓰고, 정보 조회가 목적이면
읽기 전용 프록시를 앞에 두어 허용 엔드포인트를 화이트리스트로 제한합니다.
LabHub 의 이미지 빌드가 kaniko 를 쓰는 이유가 이것입니다.

문 2 — --privileged

--privileged 는 capability 를 전부 주고, 디바이스 접근을 열고,
seccomp/AppArmor 를 사실상 해제합니다. 이 상태에서는 호스트 디스크를
/dev/sda 로 열어 마운트하는 것이 가능합니다.

막는 법 — 필요한 capability 만 개별로 줍니다. 예를 들어 낮은 포트
바인딩이 목적이면 NET_BIND_SERVICE 하나면 됩니다. 쿠버네티스라면
Pod Security Admission 의 baseline 이상으로 특권 파드를 아예 거부합니다.

문 3 — 호스트 경로 마운트

volumes:  - /:/host          # 최악  - /etc:/etc-host   # 나쁨  - /var/log:/logs   # 상황에 따라

/ 는 말할 것도 없고, /etc 만 써도 shadow·sudoers·cron 파일에
닿습니다. 쓰기 가능이면 그대로 호스트 침해입니다.

막는 법 — 마운트 경로를 최소 범위로 좁히고 :ro 를 붙입니다.
호스트 경로 대신 명명 볼륨을 쓰고, 쿠버네티스에서는 정책 엔진으로
hostPath 자체를 금지하는 편이 확실합니다.

문 4 — 공유된 네임스페이스

--pid=host 는 호스트의 모든 프로세스를 보이게 하고, --net=host
호스트의 네트워크 스택을 그대로 씁니다. 전자는 /proc/<pid>/root 를 통해
다른 프로세스의 파일시스템에 접근할 길을 열고, 후자는 localhost 로만
열어 둔 관리 포트에 닿게 합니다.

막는 법 — 기본값(격리)을 유지합니다. 모니터링처럼 정말 필요한 경우에도
읽기 전용 + 최소 capability 로 좁힙니다.

한눈에

| 설정 | 실질적 의미 | 대안 |
| --- | --- | --- |
| docker.sock 마운트 | 호스트 root | kaniko/buildah, 읽기 전용 프록시 |
| --privileged | 모든 capability + 디바이스 | 필요한 cap 만, PSA baseline |
| -v /:/host | 호스트 파일시스템 | 범위 축소 + :ro, 명명 볼륨 |
| --pid=host | 다른 프로세스 접근 | 기본 격리 유지 |

그리고 방어의 층

설정을 잘 해도 런타임 취약점은 남습니다. 층을 겹쳐 둡니다.

1. UIDUSER 10001. root 로 안 돌면 대부분의 경로가 막힙니다.
2. capability — 전부 drop 하고 필요한 것만 add.
3. NO_NEW_PRIVS — setuid 로 권한을 올리는 길을 끊습니다.
4. 읽기 전용 루트--read-only + 필요한 곳만 tmpfs.
5. seccomp — 위험한 시스템콜을 커널 입구에서 차단.

LabHub 의 실습 파드는 이 다섯을 모두 적용합니다. 그래서 여러분이 실습
안에서 root 로 무엇을 하든 호스트에는 닿지 않습니다.

현장에서 만나는 모습

다음 확인에서 볼 것

이어지는 퀴즈에서는 Docker 소켓·호스트 마운트·PID 공유가 여는 경로와 이를
막는 최소 capability·NoNewPrivs·seccomp의 역할을 구분합니다. 앞 실습에서 확인한
커널 권한 값을 근거로 단일 방어책이 충분하다는 오답을 걸러내세요.