Docker seccomp 프로파일: 허용 syscall 화이트리스트
seccomp(Secure Computing Mode)로 컨테이너가 호출할 수 있는 Linux syscall을 제한하는 방법, 기본 프로파일 구조, 커스텀 화이트리스트 JSON 작성, 필요한 syscall 자동 탐지 방법을 설명합니다.
지난 글에서 Linux Capability를 최소화하는 방법을 살펴봤다. Capability가 “어떤 종류의 권한을 가지는가”를 제어한다면, seccomp는 “어떤 시스템 호출(syscall)을 사용할 수 있는가”를 제어한다. 두 메커니즘은 상호 보완적이다.
seccomp란
seccomp(Secure Computing Mode)는 Linux 커널 기능으로, 프로세스가 호출할 수 있는 syscall을 BPF(Berkeley Packet Filter) 프로그램으로 필터링한다. 허용되지 않은 syscall을 호출하면 EPERM을 반환하거나 프로세스를 강제 종료한다.
# 현재 컨테이너의 seccomp 상태 확인
docker inspect mycontainer | \
python3 -c "import sys,json; c=json.load(sys.stdin)[0]; \
print(c['HostConfig']['SecurityOpt'])"
# → ['seccomp={"defaultAction":"SCMP_ACT_ERRNO",...}']
# 또는 null이면 기본 프로파일 적용 중
Docker 기본 seccomp 프로파일
Docker는 기본적으로 약 300개의 syscall을 허용하고 나머지를 차단한다. 차단된 syscall에는 커널 모듈 로드(init_module), 시스템 재부팅(reboot), 컨테이너 탈출에 쓰이는 kexec_load, perf_event_open 등이 포함된다.
# 기본 프로파일 확인 (moby GitHub에서)
# https://github.com/moby/moby/blob/master/profiles/seccomp/default.json
# 특정 syscall이 기본 프로파일에서 허용되는지 확인
docker run --rm ubuntu:22.04 sh -c \
"apt-get install -qq libseccomp2 && scmp_sys_resolver $(cat /proc/sys/kernel/random/uuid)" 2>/dev/null
기본 프로파일 비활성화
특정 상황에서는 기본 프로파일이 앱을 방해한다.
# seccomp 완전 비활성화 (보안 감소 — 필요한 경우만)
docker run --security-opt seccomp=unconfined myapp
# 특정 syscall만 차단하는 커스텀 프로파일 적용
docker run --security-opt seccomp=/path/to/profile.json myapp
커스텀 seccomp 프로파일 작성
프로파일은 JSON 파일로 작성한다.
화이트리스트 방식 (권장)
{
"defaultAction": "SCMP_ACT_ERRNO",
"syscalls": [
{
"names": [
"read", "write", "open", "openat",
"close", "stat", "fstat", "lstat",
"mmap", "mprotect", "munmap",
"brk", "rt_sigaction", "rt_sigprocmask",
"ioctl", "pread64", "pwrite64",
"access", "pipe", "select",
"sched_yield", "mremap", "msync",
"socket", "connect", "accept", "sendto",
"recvfrom", "bind", "listen",
"getsockname", "getpeername",
"clone", "fork", "execve", "wait4",
"kill", "exit", "exit_group",
"getcwd", "chdir", "getpid", "getppid",
"getuid", "geteuid", "getgid", "getegid",
"futex", "nanosleep", "clock_gettime",
"arch_prctl", "set_tid_address",
"set_robust_list", "prlimit64",
"getrandom", "rseq"
],
"action": "SCMP_ACT_ALLOW"
}
]
}
블랙리스트 방식 (위험 syscall만 차단)
{
"defaultAction": "SCMP_ACT_ALLOW",
"syscalls": [
{
"names": [
"kexec_load",
"perf_event_open",
"personality",
"init_module",
"finit_module",
"delete_module",
"reboot",
"clone",
"unshare"
],
"action": "SCMP_ACT_ERRNO"
}
]
}
블랙리스트는 새 syscall이 추가될 때 자동으로 허용되므로 화이트리스트보다 덜 안전하다.
필요한 syscall 자동 탐지
어떤 syscall이 필요한지 수동으로 파악하기 어렵다. 도구를 이용해 자동으로 추적한다.
strace로 추적
# 앱이 사용하는 syscall 목록 추출
docker run --rm --security-opt seccomp=unconfined \
myapp strace -o /tmp/syscalls.txt -e trace=all myapp-binary arg1
# 또는 실행 중인 컨테이너에서
docker exec mycontainer strace -p 1 -o /tmp/syscalls.txt
oci-seccomp-bpf-hook
eBPF를 이용해 컨테이너 실행 중 사용된 syscall을 자동으로 수집해 프로파일을 생성한다.
# 설치 (Fedora/RHEL)
dnf install oci-seccomp-bpf-hook
# syscall 추적 후 프로파일 자동 생성
podman run \
--annotation io.containers.trace-syscall=of:/tmp/profile.json \
myapp:latest
# 생성된 프로파일 확인
cat /tmp/profile.json
docker-slim으로 자동 프로파일 생성
# docker-slim으로 minimal 프로파일 자동 생성
slim build --target myapp:latest --tag myapp:slim
# → seccomp 프로파일도 자동 생성됨
SCMP_ACT_LOG로 감사 모드
프로덕션 적용 전 먼저 로그 모드로 실행해 차단될 syscall이 없는지 확인한다.
{
"defaultAction": "SCMP_ACT_LOG",
"syscalls": [
{
"names": ["kexec_load", "reboot", "init_module"],
"action": "SCMP_ACT_ERRNO"
}
]
}
# 로그 모드로 실행 후 감사 로그 확인
docker run --security-opt seccomp=/path/to/log-profile.json myapp
# 호스트에서 auditd 로그 확인
ausearch -ts recent | grep seccomp
# → type=SECCOMP msg=audit: ... syscall=xxx
Compose 설정
services:
web:
image: myapp:latest
security_opt:
- seccomp:/path/to/seccomp-profile.json
- no-new-privileges:true
기본 프로파일 + capability 조합
seccomp와 capability는 서로 다른 레이어에서 작동한다.
# 권장 조합: 기본 seccomp + cap-drop + no-new-privileges
docker run \
--cap-drop=ALL \
--cap-add=NET_BIND_SERVICE \
--security-opt=no-new-privileges \
--security-opt seccomp=/path/to/profile.json \
--read-only \
--user=1000:1000 \
myapp:latest
주의사항
- 화이트리스트 방식은 앱이 업데이트되면 새로 필요한 syscall이 추가될 수 있다. CI에서 프로파일 적합성을 테스트한다.
- Go 런타임, JVM 등은 일부 플랫폼에서 추가 syscall이 필요하다. 직접 테스트해야 한다.
- Kubernetes는 seccomp 프로파일을
RuntimeDefault또는 커스텀 프로파일로 지정할 수 있다.
# Kubernetes securityContext
spec:
securityContext:
seccompProfile:
type: RuntimeDefault # containerd/CRI의 기본 프로파일
# type: Localhost
# localhostProfile: profiles/my-profile.json
지난 글: Docker cap-drop/add: Linux Capability 최소화
다음 글: Docker AppArmor/SELinux: 강제 접근 제어 적용
읽어주셔서 감사합니다. 😊