앞서 chroot로 생성한 격리공간에는 다음과 같은 단점이 있었다.
이러한 단점의 일부를 극복할 수 있는 pivot_root
를 통한 격리에 대해 알아보겠다.
pivrot_root란 root 파일시스템의 마운트 포인트를 변경함으로써 특정 디렉토리를 새로운 루트 디렉토리로 만드는 명령어이다.
앞서 chroot로 만든 격리공간은 root 파일시스템이 동일하였기 때문에 탈옥이 가능했던 한편, pivrot_root를 이용하면 root 파일시스템의 마운트 포인트 자체가 변경되기 때문에 탈옥 자체가 불가능하다.
위 그림과 같이 새로운 root 파일 시스템을 지정하고, 기존 root 파일시스템 마운트 포인트를 새로운 root 파일시스템 하위 폴더로 옮겨주는 작업을 진행해보자.
man pivot-root
로 매뉴얼을 보면 다음과 같이 새로운 root 경로와 기존 root 경로를 제공함으로써 격리공간을 생성하게 된다.
PIVOT_ROOT(8) System Administration PIVOT_ROOT(8)
NAME
pivot_root - change the root filesystem
SYNOPSIS
pivot_root new_root put_old
앞 실습과 마찬가지로 격리 시킬 새로운 경로를 만든 후 nginx 이미지로 환경을 구성해주자.
# mkdir jail
# docker export $(docker create nginx:latest) | tar -C jail -xvf -
chroot 테스트 때 작성한 탈옥 코드를 똑같이 복사하여 실행시켜보자.
# vi escape_chroot.c
#include <sys/stat.h>
#include <unistd.h>
int main(void)
{
mkdir(".out",0755);
chroot(".out");
chdir("../../../../../");
chroot(".");
return execl("/bin/sh","-i",NULL);
}
[격리 공간 하위로 탈옥 코드 복사]
# apt install gcc
# gcc -o jail/escape_chroot escape_chroot.c
# ls ./jail
bin dev docker-entrypoint.sh etc lib media opt root sbin sys usr
boot docker-entrypoint.d escape_chroot home lib64 mnt proc run srv tmp var
[탈옥 실행]
# chroot jail /bin/sh
# ./escape_chroot
앞 실습에서 실행했던 것과 마찬가지로 탈옥코드를 통해 격리공간을 빠져나올 수 있다.
이제 pivot_root 를 활용하여 root 파일시스템 위치를 아예 바꿈으로써 탈옥이 불가능하도록 한다.
우선 새로운 root 파일시스템이 될 새로운 폴더를 생성해준 후 tmpfs 파일시스템을 새로운 폴더에 마운트시켜준다.
# mkdir new_jail
# mount -n -t tmpfs -o size=800M none ./new_jail/
# df -h /new_jail
Filesystem Size Used Avail Use% Mounted on
none 800M 0 800M 0% /new_jail
# mount | grep new_jail
none on /new_jail type tmpfs (rw,relatime,size=819200k)
새로운 폴더(new_jail)에 기존 jail 내부 파일들을 복사한다. 그 후 pivot_root 시 기존의 root filesystem을 mount 할 mount point로 /new_jail 하위에 old_jail/ 폴더를 생성한다.
# cp -r jail/* ./new_jail/
# mkdir ./new_jail/old_jail
# tree -L 1 ./new_jail/
./new_jail/
├── bin
...
├── escape_chroot
...
├── old_jail
...
└── var
pivot_root로 root 파일시스템의 마운트 포인트를 기존 root에서 /new_jail/old_jail로 변경할 때 호스트에 영향을 주지 않기 위해서 호스트와 newjail의 마운트 네임스페이스를 분리해야 한다.
linux의 명령어 중 네임스페이스(격리공간)을 생성하는 명령어는 unshare
이다. 이 명령어를 사용하여 호스트에서부터 마운트 네임스페이스를 격리해주자.
root@ubuntu-focal:/# cd ./new_jail/
root@ubuntu-focal:/new_jail# unshare -m
마운트 네임스페이스 격리란?
프로세스와 그 자식 프로세스가 서로 다른 파일시스템 마운트 지점을 제공함으로써 자식 프로세스에서 파일 시스템을 마운트/언마운트 해도 부모 프로세스에 영향을 미치지 않는 상태를 의미한다.
마운트 네임스페이스 격리를 했으면 pivot_root명령어로 root 파일시스템의 마운트 포인트를 old_jail로 변경한다.
root@ubuntu-focal:/new_jail# pivot_root . old_jail
root@ubuntu-focal:/new_jail# cd /
root@ubuntu-focal:/# ls
bin docker-entrypoint.d etc lib64 old_jail root srv usr
boot docker-entrypoint.sh home media opt run sys var
dev escape_chroot lib mnt proc sbin tmp
탈옥 코드 명령어를 실행해도 빠져나갈 수 없는 것을 확인할 수 있다.
# ./escape_chroot
# ls
bin docker-entrypoint.d etc lib64 old_jail root srv usr
boot docker-entrypoint.sh home media opt run sys var
dev escape_chroot lib mnt proc sbin tmp
pivot_root 는 chroot로 만든 격리공간의 단점인 탈옥을 해결하였다. 그러나 나머지 단점들은 아직 해결이 안되었는데, 이는 네임스페이스라는 개념으로 해결할 수 있다.
다음 글에서는 네임스페이스 개념과 그 종류에 대해 알아보겠다.