소프트웨어 아키텍처/Docker

Docker container 와 seccomp

bluefriday 2022. 9. 23. 13:06
반응형

도커는 Linux 기반 기술을 사용하여, 어플리케이션에 대해 격리된 공간을 만들어주는 가상화 서비스다. 여기에는 cgroup, chroot 등의 기반 기술들이 포함되는데, 추가로 보안을 위하여 커널에서 제공하는 보안 컴퓨팅 모드(seccomp) 또한 사용할 될 수 있다.

seccomp filter

Docker 에는 호스트 커널에 SECCOMP가 활성화되어 있는 경우 컨테이너를 생성할 때마다 기본적으로 사용하는 내장 SECCOMP 필터가 있다. 

이를 확인하기 위해 간단한 도커 컨테이너를 구동해본다.

root@localhost~$ docker run -it --rm ubuntu /bin/sh
# 
# date -s '23 OCT 2022 13:46:00'
date: cannot set date: Operation not permitted

컨테이너 안에 접속하여 date 명령으로 os 의 시간을 변경하려고 하면 변경할 수 없다고 나온다. (컨테이너 바깥에서 실행할 경우 정상적으로 시간이 변경되는 것도 확인할 수 있다.)

더 자세히 확인하기 위해 현재 접속해 있는 /bin/sh (PID 1)의 상태를 확인해본다.

# ps -ef 
UID          PID    PPID  C STIME TTY          TIME CMD
root           1       0  0 13:47 pts/0    00:00:00 /bin/sh
root           8       1  0 13:47 pts/0    00:00:00 ps -ef
# 
# pidof sh
1
# 
# cat /proc/1/status | grep Seccomp
Seccomp:        2
Seccomp_filters:        1

1번 프로세스의 Seccomp 값이 2로 설정되어 있다. Seccomp 의 모드는 다음과 같다.

  타입   의미    설명
  mode0   <DISABLED>    비활성화
  mode1   <STRICT>   read(), write(), exit(), sigreturn() 을 제외한 모든 syscall 거부
  mode2   <FILTERED>   선택적 필터링. 지정한 정책에 따라 syscall 마다 승인/거부

seccomp 의 값이 2로 설정되어 있으므로, 시스템콜이 제한적으로 필터링되어 거부될 수 있다. 도커는 seccomp 에 대한 profile 을 이용하여 mode2에 대한 선별적 시스템콜 허용/거부를 수행한다.


whitelist profile 과 blacklist profile

잠시 간단한 seccomp profile 을 보면 다음과 같다.

{
   "defaultAction": "SCMP_ACT_ERRNO",
   "architectures" : [
      "SCMP_ARCH_X86_64",
      "SCMP_ARCH_X86",
      "SCMP_ARCH_X32"
   ],
   "syscalls": [ 
   {
      "names": [
         "mount",
         "chmod",
         "chown"
      ],
      "action": "SCMP_ACT_ALLOW"
      }
   ]
}

seccomp profile 은 위와 같은 yaml 파일의 형식을 갖는다.

최상위 기준으로 3개의 필드가 존재하는데, "architectures" 필드의 경우 이 profile 이 사용될 수 있는 아키텍처를 표시한다.

그리고 "syscalls" 필드의 경우 배열로 이루어져 있으며, 각 배열에는 특정 시스템콜이 허용/거부 정책을 표시한다. 위 예에서는 mount, chmod, chown 시스템 콜에 대하여 "SCMP_ACT_ALLOW" 와 같이 허용하고 있다.

마지막으로 "defaultAction" 의 경우, 하단 syscall 에서 지정되지 않은 모든 시스템콜에 대한 허용/거부 정책을 정하는데 여기서는 모두 거부(SCMP_ACT_ERRNO) 하는 것을 볼 수 있다.

즉, 위 profile 은 mount, chmod, chown 을 허용하고 그 외에 모든 시스템 콜을 거부하는 프로파일이다. "defaultAction" 에 따라 프로파일의 성격이 정해지며, 이 파일의 경우 기본적으로 모두 거부하고 있기에 <whitelist type profile> 이라고 불린다.

반대로 <blacklist type profile> 도 생각해볼 수 있다. 예시는 아래와 같다.

{
   "defaultAction": "SCMP_ACT_ALLOW",
   "architectures" : [
      "SCMP_ARCH_X86_64",
      "SCMP_ARCH_X86",
      "SCMP_ARCH_X32"
   ],
   "syscalls": [
      {
         "names": [
            "fchdir",
            "flock",
            "getuid"
          ],
         "action": "SCMP_ACT_ERRNO"
      }
   ]
}

위 profile 은 fchdir, flock, getuid 시스템 콜을 제외한 모든 시스템 콜을 허용하는 profile 이다.

추가로, docker 의 기본 seccomp profile 은 [여기에서] 확인 가능하다.

상단에 컨테이너 안에서 date 명령이 허용되지 않았던 건 docker 의 default seccomp profile 이 whitelist 방식이며, clock_settime 시스템콜이 조건적으로만 허용되고, 기본적으로는 거부되어 있기 때문이다.

docker default seccomp profile
...
		{
			"names": [
				"settimeofday",
				"stime",
				"clock_settime",
				"clock_settime64"
			],
			"action": "SCMP_ACT_ALLOW",
			"includes": {
				"caps": [
					"CAP_SYS_TIME"
				]
			}
		},
...

위와 같이 CAP_SYS_TIME 플래그가 있을 경우에만 허용되는 것을 볼 수 있다. 

# docker run -it --rm --cap-add CAP_SYS_TIME ubuntu /bin/sh
# 
# date -s '23 OCT 2022 13:46:00'
Sun Oct 23 13:46:00 UTC 2022
# date
Sun Oct 23 13:46:04 UTC 2022
#

위와 같이 플래그를 추가하여 새로 만든 컨테이너에서는 clock_settime() 시스템콜의 권한을 획득하여 date 명령을 정상적으로 사용할 수 있다. 위 docker default seccomp 페이지에서 특정 시스템콜 함수를 사용하기위한 플래그들을 확인할 수 있다.

 

사용자 정의 seccomp profile

docker run -it --rm --security-opt seccomp=/root/custom.json \
    ubuntu /bin/sh


위와 같이, 직접 custom profile 을 생성한 후 이를 이용하여 컨테이너를 구동할 수도 있다.

docker run -it --rm --security-opt seccomp=unconfined \
    ubuntu /bin/sh

위와 같이 '--security-opt' 의 옵션으로 'seccomp=unconfined' 를 줄 경우, 모든 시스템콜 함수를 허용하게 된다.

보안성을 높이기 위하여 seccomp 기능과 profile 에 대하여 이해하고, 어플리케이션에 필요한 최소한의 권한만을 주도록 하자.