LabHub

컨테이너 보안 · 이미지 취약점 · 실습

인벤토리, SBOM, 그리고 게이트

LabHub 에서 이어서 보기

이 실습은 진짜 VM 에서 돕니다

이 상자는 파드가 아니라 KubeVirt 가 띄운 가상머신입니다. 리눅스 커널이
따로 돌고 systemd 가 실제로 서비스를 관리하며, docker 는 흉내가 아니라
진짜 도커 엔진입니다. docker run 으로 띄운 컨테이너는 실제로 프로세스가
되고 docker execdocker logs 도 그대로 동작합니다.

예전에는 이 실습이 파드 안에서 돌았습니다. 커널 권한을 전부 내려놓은 상자라
컨테이너를 띄우는 단계가 막혀 있었고, 그래서 이미지 아카이브를 직접 풀어
보는 우회로 배웠습니다. 이제 우회가 필요 없습니다.

알아 둘 것이 둘 있습니다.

목표

스캐너가 실제로 하는 일(패키지 인벤토리 → DB 대조)을 손으로 재현합니다. 베이스와
런타임 이미지의 패키지 목록을 뽑아 늘어난 공격 표면을 숫자로 세고, SBOM 을 직접
만들고, 정책 게이트 스크립트를 작성한 뒤, 이미지에 박제된 시크릿을 찾아 고칩니다.

왜 중요한가

스캐너를 마법 상자로 두면 두 가지 잘못된 결론에 빠집니다. "깨끗하니 안전하다"와
"1,247건 전부 고쳐야 한다". 스캐너는 이미지를 실행하지도 코드를 분석하지도 않고,
설치된 패키지의 이름·버전을 취약점 DB 와 대조할 뿐입니다. 그래서 curl | tar xz
로 넣은 바이너리는 아예 보이지 않고, 한 번도 호출하지 않는 패키지의 취약점은
그대로 올라옵니다. 이 원리를 손으로 재현해 보면 "무엇을 고칠 것인가"보다
"왜 이 패키지가 이미지에 있는가" 가 먼저 나와야 한다는 것이 분명해집니다.
애플리케이션이 링크하는 공유 라이브러리가 8개인데 이미지에 패키지가 432개
들어 있다면, 문제는 취약점이 아니라 이미지 구성입니다.

단계

1. /root/sec2 디렉터리를 만들고, alpine:3.20 에 설치된 패키지를 이름-버전 한 줄 형식으로 /root/sec2/alpine-pkgs.txt 에 저장합니다. 10줄 이상이어야 하고 musl 이 들어 있어야 합니다.
2. 같은 형식으로 nginx:1.27-alpine 의 패키지 목록을 /root/sec2/nginx-pkgs.txt 에 저장합니다. 10줄 이상이어야 하고 nginx 가 들어 있어야 하며 1단계보다 줄 수가 많아야 합니다.
3. 두 목록을 버전을 뗀 패키지 이름 기준으로 비교해, nginx 쪽에만 있는 패키지 개수를 /root/sec2/extra-count.txt숫자만 저장합니다 (오차 2 이내 허용).
4. /root/sec2/sbom.json 을 만듭니다. 최상위 image 값은 nginx:1.27-alpine, packages 는 배열이며 항목 수가 2단계 파일의 줄 수와 같아야 합니다. 각 항목에는 비어 있지 않은 nameversion 이 있어야 합니다.
5. /root/sec2/deny.txt 에 금지 패키지 이름을 한 줄에 하나씩 적습니다(반드시 curl 포함). 그리고 실행 권한이 있는 /root/sec2/gate.sh 를 작성합니다. 첫 번째 인자로 받은 패키지 목록 파일에 금지 패키지가 없으면 종료코드 0, 있으면 0 이 아닌 종료코드로 끝나면서 걸린 패키지 이름을 출력해야 합니다.
6. ARG 로 받은 값을 ENV APP_TOKEN 으로 넘기는 Dockerfile 로 labhub/leak:v1 을 빌드하고, 이미지 설정에서 그대로 읽히는 토큰 값을 /root/sec2/leak.txt 에 저장합니다.
7. 같은 앱을 토큰 없이 빌드해 labhub/leak:v2 를 만듭니다(이미지 Env 에 APP_TOKEN 이 없어야 합니다). 그리고 labhub/leak:v2sec-runtime 컨테이너를 띄우되 APP_TOKEN실행 시점에 주입합니다.
8. /root/sec2/scan.md 에 다음 세 줄을 정확히 이 형식으로 적습니다.

참고

단계 8개

  1. 베이스 이미지 패키지 인벤토리
  2. 런타임 이미지와 비교
  3. 늘어난 공격 표면 세기
  4. SBOM 직접 만들어 보기
  5. 정책 게이트 스크립트
  6. ENV 로 넣은 토큰은 이미지에 박제된다
  7. 이미지는 깨끗하게, 시크릿은 실행 시점에
  8. 스캔 요약