Linux 기술 · 6 min read · Feb 03, 2026
Unionfs 및 Chroot로 로그인할 때 안전한 미러에 들어가기
Unionfs 및 Chroot로 로그인할 때 안전한 미러에 들어가기
1. 소개
LinuxFromScratch 웹사이트에서 ‘힌트’를 읽다가 unionfs의 특별한 기능을 발견했습니다. 특히 chroot와 결합했을 때 그렇습니다. 이후 Gentoo의 위키 웹사이트에서 특별한 스크립트를 셸로 사용할 때 chroot된 홈 디렉토리에 들어가는 방법에 대한 HowTo를 읽었습니다. 이 두 가지를 결합하면 특별한 사용자로 로그인할 때 들어가는 chroot된 환경을 사용할 수 있습니다. 이 환경은 여러분이 작업하는 시스템의 정확한 복사본(미러)입니다. 실제 시스템의 안전한 복사본에 있기 때문에 원하는 대로 할 수 있으며, 시스템을 변경하지 않고 모든 것이 캐시(읽기-쓰기 분기) 내에 유지됩니다.
링크:
TRIP, LFS(및 기타 리눅스 시스템)를 위한 TRIvial Packager - LFS 웹사이트의 원본 힌트
Home_directory_jail - Gentoo에서 chroot 감옥을 설정하는 가이드
2. 기본 기술
원하는 대로 하세요. 시스템에서 파일을 설치, 변경 및 제거해도 전혀 해가 없습니다. 실제 시스템은 손대지 않은 채로 유지됩니다. 마법처럼 들릴 수 있지만, 실제로는 리눅스에서 사용할 수 있는 여러 기술을 결합하여 가능한 것입니다.
Unionfs 파일 시스템, chroot 및 잘 선택된 재마운트된 디렉토리를 사용하여 이 가상 시스템을 설정할 수 있습니다.
2.1 Unionfs
가장 중요한 부분은 unionfs의 사용입니다. Unionfs는 최소한 두 개의 다른 파일 시스템의 합집합을 생성할 수 있는 가능성을 제공합니다. 자세한 정보는 www.unionfs.org를 참조하세요. 이제 새로운 파일 시스템이 원래 파일 시스템(루트)을 읽기 전용 모드로, 임시 파일 시스템(캐시)을 읽기-쓰기 모드로 합친다면, 원래 파일 시스템과 정확히 같은 모습의 파일 시스템을 가지게 되지만, 원래 시스템에 아무런 영향을 주지 않고 파일을 수정, 삭제 및/또는 추가할 수 있습니다. 이는 루트가 읽기 전용으로 마운트되기 때문에 가능합니다. 모든 수정 사항은 unionfs에 의해 캐시에 저장됩니다.
원래 시스템과 새로 생성된 시스템의 유일한 차이는 경로입니다: 새 시스템에서는 항상 union의 마운트 포인트 경로로 시작합니다. 이것이 다음 단계가 필요한 이유입니다.
특별한 주의: 오늘 [2007년 6월] unionfs가 커널에 포함될 것처럼 보입니다. 현재 unionfs는 활발한 개발 중입니다. 더 많은 정보는 웹사이트를 참조하세요.
웹사이트에서는 unionfs를 활성화하는 방법에 대한 정보를 찾을 수 있습니다. 최신 커널(2.6.19 이후)에는 커널 소스에 대한 패치가 있으며, 그렇게 최근이 아닌 커널에는 외부 모듈이 있습니다.
2.2 (재)마운팅
추가로 해야 할 일은 /dev, /proc 및 /sys와 같은 여러 중요한 디렉토리를 (재)마운트하는 것입니다. 이는 union 파일 시스템이 기존 마운트 포인트를 유지하지 않기 때문입니다.
/tmp와 소프트웨어를 빌드하는 디렉토리와 같은 일부 특별한 디렉토리를 재마운트하는 것도 권장됩니다.
2.3 Chroot
이 마운트 포인트에 chroot하면 시스템의 절대적인 복사본인 환경에 들어갑니다. 원하는 대로 할 수 있으며, 중요한 디렉토리와 파일을 제거할 수도 있습니다. 테스트해 보세요! 시스템이 멈추기 전에 얼마나 멀리 갈 수 있는지 확인해 보세요.
2.4 이 환경에 로그인하기
Home_directory_jail에서 설명한 개념처럼, unionfs와 chroot로 생성된 환경에 들어가기 위해 특별한 로그인 셸을 생성하는 것이 가능합니다.
여기서 설명하는 아이디어는 특별한 셸을 가진 특별한 사용자를 만드는 것입니다. 이 셸은 대화형 셸에 들어가기 전에 union 파일 시스템을 마운트하고, 몇 가지 중요한 디렉토리를 재마운트하며, chroot를 수행하는 등의 필요한 단계를 먼저 수행합니다.
3. 준비
3.1 캐시 파티션
캐시로 기능할 충분한 공간을 가진 파티션을 시작합니다. 이는 물리적 파티션일 필요는 없으며, 가상 드라이브일 수 있습니다.
다음 명령어로 이 드라이브를 생성합니다:
dd if=/dev/zero of=/mnt/cache.img bs=1M count=500
mkfs.ext2 /mnt/cache.img
mkdir /mnt/cache
mount /mnt/cache.img /mnt/cache -o loopchmod 777 /mnt/cachemkdir /mnt/union이렇게 하면 500M의 가상 파티션(또는 드라이브)이 생성됩니다.
(참고: 루프백 장치는 커널에서 지원되어야 합니다. 대부분의 배포판의 커널은 그렇습니다.)
3.2 특별 로그인 셸
모든 필요한 단계를 수행할 chroot-union이라는 셸 스크립트를 생성합니다:
/bin의 chroot-union 스크립트:
#!/bin/bash
function mount_unionfs {
# 임시 파일 시스템 마운트
if [ -z "$(mount -t unionfs | grep -w /mnt/union )" ]; then
sudo /bin/mount -t unionfs -o dirs=/mnt/cache:/=ro unionfs /mnt/union
fi
if [ -n "$(mount -t unionfs | grep -w /mnt/union )" ]; then
# 기본 시스템 마운트
if [ -z "$(mount | grep -w /mnt/union/dev)" ]; then
sudo /bin/mount --bind /dev /mnt/union/dev 2> /dev/null
fi
if [ -z "$(mount -t devpts | grep -w /mnt/union/dev/pts)" ]; then
sudo /bin/mount -t devpts devpts /mnt/union/dev/pts 2> /dev/null
fi
if [ -z "$(mount -t tmpfs | grep -w /mnt/union/dev/shm)" ]; then
sudo /bin/mount -t tmpfs shm /mnt/union/dev/shm 2> /dev/null
fi
if [ -z "$(mount -t sysfs | grep -w /mnt/union/sys)" ]; then
sudo /bin/mount -t sysfs sysfs /mnt/union/sys 2> /dev/null
fi
if [ -z "$(mount -t proc | grep -w /mnt/union/proc)" ]; then
sudo /bin/mount -t proc proc /mnt/union/proc 2> /dev/null
fi
if [ -z "$(mount | grep -w /mnt/union/tmp)" ]; then
sudo /bin/mount --bind /tmp /mnt/union/tmp 2> /dev/null
fi
else
echo "Mount of /mnt/union failed."
exit 2
fi
}
function umount_unionfs {
#
# /tmp 언마운트
#
if [ -n "$(mount | grep -w /mnt/union/tmp)" ]; then
sudo /bin/umount /mnt/union/tmp 2> /dev/null
fi
#
# /proc 언마운트
#
if [ -n "$(mount -t proc | grep -w /mnt/union/proc)" ]; then
sudo /bin/umount /mnt/union/proc 2> /dev/null
fi
#
# /sys 언마운트
#
if [ -n "$(mount -t sysfs | grep -w /mnt/union/sys)" ]; then
sudo /bin/umount /mnt/union/sys 2> /dev/null
fi
#
# /dev/shm 언마운트
#
if [ -n "$(mount -t tmpfs | grep -w /mnt/union/dev/shm)" ]; then
sudo /bin/umount /mnt/union/dev/shm 2> /dev/null
fi
#
# /dev/pts 언마운트
#
if [ -n "$(mount -t devpts | grep -w /mnt/union/dev/pts)" ]; then
sudo /bin/umount /mnt/union/dev/pts 2> /dev/null
fi
#
# /dev 언마운트
#
if [ -n "$(mount | grep -w /mnt/union/dev)" ]; then
sudo /bin/umount /mnt/union/dev 2> /dev/null
fi
if [ -n "$(mount | grep -w /mnt/union )" ]; then
sudo /bin/umount /mnt/union 2> /dev/null
fi
}
mount_unionfs
# chroot에 들어가기
sudo /usr/sbin/chroot /mnt/union /bin/su --shell /bin/bash --login $USER
# 임시 파일 시스템 언마운트
umount_unionfs
EOF
새로운 로그인 셸을 /etc/shells 파일에 추가합니다. PAM이 셸을 확인할 때 이 작업을 수행해야 합니다.
3.3 사용자 및 그룹 생성
이 스크립트를 셸로 사용하는 새로운 그룹과 사용자를 생성합니다:
groupadd -g 27 uniongroup
useradd -c "Chrooted union을 위한 테스트 사용자." -d /home/unionuser \
-m -s /bin/chroot-union -g uniongroup -u 27 unionuser
passwd unionuser3.4 사용자에게 충분한 권한 부여
sudo를 사용하여 새로운 사용자에게 더 많은 권한을 부여합니다. sudo의 구성 파일인 /etc/sudoers에 다음 줄을 추가합니다:
unionuser ALL=(ALL) ALL
참고: 이 사용자에게 권한을 부여하는 다른 방법도 있습니다. 현재 그 방법을 살펴보고 있습니다.
참고: 이러한 전체 권한을 부여하는 것은 일반 사용자에게는 너무 많습니다. 그러나 소프트웨어를 설치하고 시스템을 수정할 사용자의 경우에는 필요합니다.
가능한 것들
일반 사용자를 위한 안전하고 보안적인 환경
이 구조는 신뢰할 수 없는 게스트 사용자에게 매우 적합합니다. 제가 시도한 첫 번째 일은 그래픽 세션을 시작하는 것이었습니다. 아무런 문제도 없었습니다.
이 사용자로 소프트웨어 설치
이 사용자가 소프트웨어를 설치하는 또 다른 가능한 용도입니다. 이는 다음과 같이 수행할 수 있습니다:
- 이 사용자로 소프트웨어를 설치합니다. 특별한 구조 덕분에 모든 변경 사항은 캐시로 이동합니다.
- 로그아웃 후 캐시의 내용과 실제 시스템의 내용을 비교합니다.
- 제어 사용자(루트)는 캐시의 내용을 루트로 이동하여 실제 설치를 수행할 수 있습니다.
예를 들어 작은 패키지 audiofile-0.2.6의 컴파일 및 설치를 가정합니다. 소스가 /tmp에 있다고 가정합니다. 먼저 로그인:
[root@hostname ]# login
hostname login: unionuser
Password:
Last login: Wed Jun 20 19:58:32 CEST 2007 on pts/0
[unionuser@hostname ]$이제 패키지를 컴파일하고 설치합니다:
[unionuser@hostname ]$ cd /tmp/audiofile-0.2.6
[unionuser@hostname ]$ ./configure –prefix=/usr
[unionuser@hostname ]$ make
[unionuser@hostname ]$ sudo make install
이제 세션을 종료하고 캐시의 내용을 확인합니다:
[unionuser@hostname ]$exit
[root@hostname ]# cd /mnt/cache
[root@hostname ]# ls -Al
drwxr-xr-x 3 root root 1024 2007-06-05 17:32 home
drwxr-xr-x 6 root root 1024 2007-06-05 17:37 usr
drwxr-xr-x 3 root root 1024 2007-06-05 17:32 var
[root@hostname ]#
홈 디렉토리는 여기 나타나며, Bash 셸이 .bash_history 파일을 변경했기 때문에 그렇습니다. var 디렉토리는 /var/run/utmp 파일과 /var/run/sudo 디렉토리의 변경으로 인해 나타납니다. 이는 제대로 작동하고 있음을 증명합니다.
이제 /usr 디렉토리에서 소프트웨어를 설치한 변경 사항을 살펴보면:
[root@hostname ]# find usr -type f
usr/lib/pkgconfig/audiofile.pc
usr/lib/libaudiofile.la
usr/lib/libaudiofile.a
usr/lib/libaudiofile.so.0.0.2
usr/include/audiofile.h
usr/include/aupvlist.h
usr/include/af_vfs.h
usr/bin/audiofile-config
usr/bin/sfconvert
usr/bin/sfinfo
usr/share/aclocal/audiofile.m4
[root@hostname ]# find usr -type d
usr
usr/lib
usr/lib/pkgconfig
usr/include
usr/bin
usr/share
usr/share/aclocal
보시다시피 모든 것이 /mnt/cache/usr 디렉토리에 있습니다.
이것의 백업을 만들 수 있습니다:
[root@hostname ]# find usr | sort -u > /tmp/filelist-audiofile-0.2.6
[root@hostname ]# tar --create --files-from=/tmp/filelist-audiofile-0.2.6 \
--file=/tmp/install-audiofile-0.2.6.tar --directory=/mnt/cache \
--no-recursion --absolute-names --preserve-permissions덮어쓰일 모든 파일의 백업을 만드는 것도 매우 가능합니다:
[root@hostname ]# for installfile in $(cat /tmp/filelist-audiofile-0.2.6); do \
if [ -e "/$installfile ]; then \
echo "/$installfile" >> /tmp/backup-audiofile-0.2.6 \
fi \
done
[root@hostname ]# tar --create --files-from=/tmp/backup-audiofile-0.2.6 \
--file=/tmp/backup-audiofile-0.2.6.tar --directory=/mnt/cache \
--no-recursion --absolute-names --preserve-permissions이제 모든 파일을 루트로 복사하여 실제 설치를 수행합니다:
[root@hostname ]# for installfile in $(cat /tmp/filelist-audiofile-0.2.6); do \
cp --verbose --force --recursive --parents --no-dereference \
--preserve --target-directory=/ $installfile \
done참고: 위의 명령어는 아이디어를 설명하기 위한 것입니다. 백업, 확인 및 설치를 수행하는 스크립트를 작성했으며, 매우 잘 작동합니다.
새 게시물을 받은 편지함에서 받기
스팸은 없습니다. 언제든지 구독 해지 가능합니다.