-
[Linux] unshare 과 PID Namespace 격리 알아보기System 2024. 6. 19. 07:03반응형
- 목차
들어가며.
이번 글에서는 Docker 와 같은 Container 가상화 기술의 근간이 되는 PID Namespace 에 대해서 알아봅니다.
PID Namespace 격리는 unshare 명령어를 통해서 구현할 수 있습니다.
기본적으로 Root Level 의 PID Namespace 가 존재합니다.
아래와 같이 PID 가 1번인 Root Process 를 포함하여 9 ~ 15번에 해당하는 여러 Process 가 생성될 수 있습니다.
UID PID PPID C STIME TTY TIME CMD root 1 0 0 23:58 pts/0 00:00:00 bash root 9 1 0 23:58 pts/0 00:00:00 sleep 1000 root 10 1 0 23:58 pts/0 00:00:00 sleep 1000 root 11 1 0 23:59 pts/0 00:00:00 sleep 1000 root 12 1 0 23:59 pts/0 00:00:00 sleep 1000 root 13 1 0 23:59 pts/0 00:00:00 sleep 1000 root 14 1 0 23:59 pts/0 00:00:00 sleep 1000 root 15 1 0 23:59 pts/0 00:00:00 ps -ef
그리고 이러한 Process 들은 동일한 PID Namespace 에 존재하게 됩니다.
반면, 새로운 PID Namespace 를 생성하고, 새로운 PID Namespace 내부에 Process 들을 생성하게 되면,
이 새로운 Process 들은 다른 PID Namespace 의 Process 들을 확인할 수 없습니다.
하나의 예시로써 아래와 같이 unshare 를 활용하여 새로운 PID Namespace 생성과 함께 Process 를 생성하게 되면 기존과 다른 새로운 Process ID 들을 확인할 수 있습니다.
unshare --fork --pid --mount-proc bash -c " sleep 100 & \ sleep 100 & \ sleep 100 & \ sleep 100 & \ ps -ef "
UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:02 pts/0 00:00:00 bash -c sleep 100 & sleep 100 & sleep 100 & sleep 100 & root 2 1 0 00:02 pts/0 00:00:00 sleep 100 root 3 1 0 00:02 pts/0 00:00:00 sleep 100 root 4 1 0 00:02 pts/0 00:00:00 sleep 100 root 5 1 0 00:02 pts/0 00:00:00 sleep 100 root 6 1 0 00:02 pts/0 00:00:00 ps -ef
이어지는 내용에서 PID Namespace 격리에 대해서 자세히 알아보도록 하겠습니다.
부모 PID Namespace 와 자식 PID Namespace 의 관계.
PID Namespace 는 Process ID 의 공간을 격리시키는 방식입니다.
이는 부모와 자식의 수직적인 관계를 가집니다.
이는 다른 식으로 표현하면 부모 PID Namespace 공간에서는 자식 PID Namespace 의 Process 들을 확인할 수 있습니다.
반면 자식 PID Namespace 에서는 부모 PID Namespace 의 Process 들을 확인할 수 없습니다.
아래의 상태는 갓 생성된 부모 PID Namespace 에서의 ps 목록입니다.
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:05 pts/0 00:00:00 bash root 11 1 0 00:05 pts/0 00:00:00 ps -ef
그리고 unshare 명령어를 통해서 자식 PID Namespace 를 생성할 수 있습니다.
unshare --fork --pid --mount-proc bash
그리고 부모 PID Namespace 에서 ps 목록을 확인하게 되면,
아래와 같이 unshare 명령어로 인해 생성된 bash Process 를 확인할 수 있습니다.
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:05 pts/0 00:00:00 bash root 12 1 0 00:06 pts/0 00:00:00 unshare --fork --pid --mount-proc bash root 13 12 0 00:06 pts/0 00:00:00 bash root 25 0 0 00:06 pts/1 00:00:00 bash root 33 25 0 00:06 pts/1 00:00:00 ps -ef root@6f6f6c689020:/#
그리고 아래의 ps 목록은 자식 PID Namespace 에서 확인한 ps 의 목록입니다.
주목할 점은 자식 PID Namespace 에서 생성된 bash Process 는 자신이 1번 Process 로 지정된다는 사실입니다.
그 외의 PID Namespace 의 Process 들은 확인되지 않습니다.
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:06 pts/0 00:00:00 bash root 4 1 0 00:07 pts/0 00:00:00 ps -ef
이는 부모 PID Namespace 에서 bash Process 는 13번 ID 를 가지지만, 새로운 PID Namespace 에서는 1번 ID 를 가지는 Root Process 가 됩니다.
PID Namespace 확인하기.
/proc 디렉토리는 실행 중인 Process 의 상태를 저장하는 공간입니다.
이는 실제 파일 시스템은 아니고 커널에 의해서 제공되는 메모리 상의 가상 파일 시스템입니다.
아래와 같이 ls -l 명령어를 통해서 PID Namespace 의 고유값을 확인할 수 있습니다.
ls -l /proc/$$/ns/pid
아래는 기존의 PID Namespace 와 새로운 PID Namespace 에서 확인한 PID Link File 의 값입니다.
이는 각각 동일한 PID Namespace 의 Link File 을 가리킵니다.
자식 PID Namespace 의 1번 프로세스와 부모 PID Namespace 의 13번 Process 는 동일한 Process 입니다.
반면, 부모 PID Namespace 의 1번 Process 는 Root Process 에 해당합니다.
// 자식 PID Namespace 에서 확인한 PID ls -l /proc/1/ns/pid lrwxrwxrwx 1 root root 0 Jan 31 00:10 /proc/1/ns/pid -> 'pid:[4026532694]' // 부모 PID Namespace 에서 확인한 PID ls -l /proc/13/ns/pid lrwxrwxrwx 1 root root 0 Jan 31 00:11 /proc/13/ns/pid -> 'pid:[4026532694]' // 부모 PID Namespace 에서 확인한 ROOT PID ls -l /proc/1/ns/pid lrwxrwxrwx 1 root root 0 Jan 31 00:13 /proc/1/ns/pid -> 'pid:[4026532563]'
위 결과처럼 새로운 PID Namespace 에서 Process 와 기존의 Root Process 는 서로 다른 PID Namespace 를 가집니다.
/proc 확인해보기.
아래의 사진은 부모와 자식의 PID Namespace 에서의 /proc 디렉토리 하위의 파일을 나타냅니다.
첫번째 사진은 자식 PID Namespace 에서의 /proc 디렉토리 상태입니다.
그리고 두번째 사진은 부모 PID Namespace 에서의 /proc 디렉토리의 상태입니다.
두 Namespace 에서 관리 중인 Process 는 아래와 같이 서로 다르게 표현됩니다.
서로 Process ID 가 다를 뿐더러 확인할 수 있는 Process 도 상이합니다.
이러한 방식으로 서로 다른 PID Namespace 는 Process 간의 노출과 접근이 제한됩니다.
unshare 명령어 알아보기.
unshare 명령어를 통해서 PID Namespace 를 격리할 수 있습니다.
unshare 명령어를 사용해서 새로운 PID Namespace 의 생성과 Process 실행 방법에 대해서 알아보겠습니다.
기본적인 사용법은 아래와 같습니다.
--fork, --pid, --mount-proc 와 같은 Flag 와 함께 실행하고자하는 Process 를 명시합니다.
unshare --fork --pid --mount-proc bash
--fork.
--fork Flag 는 Fork System Call 과 같이 새로운 자식 Process 를 생성하는 목적으로 사용됩니다.
아래와 같이 --fork Flag 만을 사용하여 새로운 Process 를 생성합니다.
그리고 ps 목록을 출력해보면 아래와 같은 ps 목록이 출력됩니다.
아래와 같이 unshare Process 와 unshare Process 의 자식 Process 인 sleep Process 가 실행됩니다.
unshare --fork sleep 1000
ps aux USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND root 1 0.0 0.0 3752 2828 pts/0 Ss+ 00:05 0:00 bash root 25 0.0 0.0 3752 2724 pts/1 Ss 00:06 0:00 bash root 62 0.0 0.0 1952 984 pts/0 S 00:28 0:00 unshare --fork sleep 1000 root 63 0.0 0.0 1948 1104 pts/0 S 00:28 0:00 sleep 1000 root 65 0.0 0.0 5480 2244 pts/1 R+ 00:28 0:00 ps aux
하지만 --fork 만 수행하고 --pid Flag 를 생략한 경우에는 아래와 같이 새로운 PID 가 생성되지 않습니다.
동일한 PID Namespace 를 공유하게 됩니다.
root@6f6f6c689020:/# ls -l /proc/1/ns/pid >> /proc/1/ns/pid -> 'pid:[4026532563]' root@6f6f6c689020:/# ls -l /proc/63/ns/pid >> /proc/63/ns/pid -> 'pid:[4026532563]'
--pid.
--pid Flag 는 새로운 PID Namespace 를 생성하기 위한 Flag 입니다.
unshare --fork --pid bash
생성된 ps 목록은 아래와 같습니다.
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:05 pts/0 00:00:00 bash root 25 0 0 00:06 pts/1 00:00:00 bash root 118 1 0 00:35 pts/0 00:00:00 unshare --fork --pid bash root 119 118 0 00:35 pts/0 00:00:00 bash root 123 119 0 00:35 pts/0 00:00:00 ps -ef
그리고 1번 Process 와 119 Process 는 서로 다른 PID Namespace 를 다룹니다.
root@6f6f6c689020:/# ls -l /proc/119/ns/pid >> /proc/119/ns/pid -> 'pid:[4026532693]' root@6f6f6c689020:/# ls -l /proc/1/ns/pid >> /proc/1/ns/pid -> 'pid:[4026532563]'
그리고 새로운 PID Namespace 내부에서 Process ID 는 아래와 같이 119번이 아닌 1번 Process 로 인식됩니다.
echo $$ >> 1
--mount-proc.
--mount-proc 는 새로운 /proc 디렉토리를 생성하는 Flag 입니다.
사실상 --mount-proc 를 생략하게 되면 PID Namespace 가 서로 다르더라도 모든 Process 를 확인할 수 있습니다.
ps 명령어는 /proc 디렉토리를 기준으로 ps 목록을 제공하기 때문에 --mount-proc 를 사용해서 PID Namespace 별로 /proc 를 새롭게 구성해야합니다.
참고로 /proc 는 커널에서 제공하는 Process 의 상태이며, Namespace 에 따라서 커널에 알맞은 Process 정보를 제공하게 됩니다.
unshare --fork --pid --mount-proc bash
저는 부모 PID Namespace 에서 sleep Process 를 10개 정도 생성하였습니다.
이는
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:05 pts/0 00:00:00 bash root 25 0 0 00:06 pts/1 00:00:00 bash root 131 1 0 00:41 pts/0 00:00:00 unshare --fork --pid --mount-proc bash root 132 131 0 00:41 pts/0 00:00:00 bash root 136 25 0 00:41 pts/1 00:00:00 sleep 10000 root 137 25 0 00:41 pts/1 00:00:00 sleep 10000 root 138 25 0 00:41 pts/1 00:00:00 sleep 10000 root 139 25 0 00:41 pts/1 00:00:00 sleep 10000 root 140 25 0 00:41 pts/1 00:00:00 sleep 10000 root 141 25 0 00:41 pts/1 00:00:00 sleep 10000 root 142 25 0 00:41 pts/1 00:00:00 sleep 10000 root 143 25 0 00:41 pts/1 00:00:00 sleep 10000 root 144 25 0 00:41 pts/1 00:00:00 sleep 10000 root 145 25 0 00:41 pts/1 00:00:00 sleep 10000 root 146 25 0 00:41 pts/1 00:00:00 sleep 10000 root 147 25 0 00:41 pts/1 00:00:00 sleep 10000 root 148 25 0 00:41 pts/1 00:00:00 sleep 10000 root 149 25 0 00:41 pts/1 00:00:00 sleep 10000 root 150 25 0 00:41 pts/1 00:00:00 sleep 10000 root 151 25 0 00:41 pts/1 00:00:00 sleep 10000 root 152 25 0 00:41 pts/1 00:00:00 sleep 10000 root 153 25 0 00:41 pts/1 00:00:00 sleep 10000 root 154 25 0 00:41 pts/1 00:00:00 sleep 10000 root 155 25 0 00:41 pts/1 00:00:00 ps -ef
이는 /proc 디렉토리 하위에서 개별 파일로써 관리됩니다.
반면 이는 자식 PID Namespace 에서는 확인되지 않습니다.
ps -ef UID PID PPID C STIME TTY TIME CMD root 1 0 0 00:41 pts/0 00:00:00 bash root 4 1 0 00:42 pts/0 00:00:00 ps -ef
반응형'System' 카테고리의 다른 글
[Linux] cgroup cpu.max 설정 알아보기 (0) 2024.06.20 심볼릭 링크 알아보기 ( Symbolic Link ) (0) 2024.06.09 Standard Input (표준입력) 이해하기 (0) 2023.10.16 RPC (Remote Procedure Call) 알아보기 (0) 2023.10.14 IPC Signal 알아보기 (0) 2023.10.07