본문 바로가기
  • 오늘처럼
소프트웨어 아키텍처/Docker

Docker container 와 seccomp

by bluefriday 2022. 9. 23.
반응형

도커는 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 에 대하여 이해하고, 어플리케이션에 필요한 최소한의 권한만을 주도록 하자.

댓글