블로그

멀티 테넌트 호스팅을 위한 실용적인 Docker 격리 보안 체크리스트

이 실용적인 체크리스트로 멀티 테넌트 Docker 호스팅을 보호하세요: 비루트 사용자, 캐퍼빌리티, seccomp, 사용자 네임스페이스, 리소스 제한, 읽기 전용 파일 시스템.

요약

멀티 테넌트 Docker 호스팅은 컨테이너 이스케이프를 방지하기 위해 강력한 격리가 필요합니다. 이 글에서는 여섯 가지 핵심 영역을 다루는 실용적인 보안 체크리스트를 제공합니다: 비루트로 실행, 캐퍼빌리티 제거, seccomp 프로필 적용, 사용자 네임스페이스 리매핑 활성화, 리소스 제한 설정, 읽기 전용 루트 파일 시스템 사용. 각 단계에는 Docker Compose를 위한 구체적인 구성 예시가 포함되어 있습니다. 또한 사용자 네임스페이스의 커널 호환성 문제와 seccomp 적용 시 성능 트레이드오프 같은 일반적인 함정도 배우게 됩니다. 이 체크리스트를 따르면 불필요한 복잡성을 추가하지 않고도 공격 표면을 크게 줄일 수 있습니다. 글은 프로덕션 멀티 테넌트 환경을 위한 권장 기준 구성을 통해 마무리됩니다.

멀티 테넌트 Docker 환경을 운영한다면 컨테이너 이스케이프 공격의 그림자가 밤잠을 설치게 할 것입니다. 하나의 커널 익스플로잇이 컨테이너를 뚫고 나와 호스트와 다른 모든 테넌트의 데이터에 무제한 접근 권한을 부여할 수 있습니다. Docker는 네임스페이스, cgroups, 캐퍼빌리티와 같은 강력한 격리 프리미티브를 제공하지만, 잘못된 구성은 허점을 남깁니다. 이 글에서는 오늘 바로 적용할 수 있는 단계별 보안 체크리스트를 제시합니다. 각 단계에는 작동하는 Docker Compose 스니펫과 주요 주의사항이 포함되어 있습니다. 끝날 무렵에는 보안과 성능의 균형을 맞춘 강화된 기준을 갖추게 됩니다.

1. 비루트 사용자로 컨테이너 실행

컨테이너는 기본적으로 컨테이너 내부에서 루트로 실행됩니다. 공격자가 컨테이너 내에서 루트 권한을 획득하면 이스케이프에 유리한 위치를 점하게 됩니다. Dockerfile에서 항상 비루트 사용자를 정의하세요.

FROM alpine:3.18
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

Compose에서는 사용자를 직접 설정할 수도 있습니다:

services:
  app:
    image: myapp
    user: "1000:1000"

주의사항: 일부 애플리케이션은 합법적인 작업(예: 1024 미만 포트 바인딩)을 위해 루트가 필요합니다. 전체 컨테이너를 루트로 실행하는 대신 CAP_NET_BIND_SERVICE를 사용하세요. 격리 기본 사항에 대한 자세한 내용은 Docker에서 진정한 멀티 테넌트 격리 달성 가이드를 참조하세요.

2. 모든 캐퍼빌리티 제거 및 필요한 것만 추가

리눅스 캐퍼빌리티는 컨테이너에 세분화된 권한을 부여합니다. 기본적으로 Docker는 일련의 캐퍼빌리티를 부여합니다. 모든 것을 제거하고 필요한 것만 허용하세요.

services:
  app:
    image: myapp
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # 필요 시

주의사항: SYS_ADMIN 또는 NET_RAW 같은 캐퍼빌리티는 거의 필요하지 않습니다. 애플리케이션을 감사하여 최소 집합을 결정하세요. 모든 캐퍼빌리티를 제거하면 많은 이스케이프 벡터를 차단할 수 있습니다.

3. Seccomp 프로필 적용

Seccomp(보안 컴퓨팅 모드)는 컨테이너에서 사용 가능한 시스템 호출을 필터링합니다. Docker는 특정 플래그가 있는 clone과 같은 위험한 syscall을 차단하는 기본 seccomp 프로필과 함께 제공됩니다. 추가로 사용자 지정할 수 있습니다.

services:
  app:
    image: myapp
    security_opt:
      - seccomp=/path/to/custom-profile.json

강화된 프로필은 unshare, ptrace, mount를 차단할 수 있습니다. Docker의 기본 프로필로 시작하여 더 제한하세요. 주의사항: 지나치게 엄격한 프로필은 애플리케이션을 손상시킬 수 있습니다. 스테이징 환경에서 철저히 테스트하세요. 컨테이너 이스케이프 방어에 대한 자세한 내용은 컨테이너 이스케이프 방어를 읽어보세요.

4. 사용자 네임스페이스 리매핑 활성화

사용자 네임스페이스는 컨테이너의 루트 사용자를 권한이 없는 호스트 사용자에게 매핑합니다. 즉, 공격자가 컨테이너 내에서 루트를 획득하더라도 호스트에서 특별한 권한이 없습니다.

/etc/docker/daemon.json을 편집하여 Docker 데몬에서 활성화:

{
  "userns-remap": "default"
}

그런 다음 Docker를 다시 시작하세요. 주의사항: 사용자 네임스페이스 리매핑에는 두 가지 단점이 있습니다. 신중하게 구성하지 않으면 볼륨 마운트가 깨질 수 있고(파일이 리매핑된 사용자 소유로 변경됨), 구형 커널의 overlay2와 같은 일부 스토리지 드라이버와 호환되지 않습니다. 철저히 테스트하세요.

5. Cgroups로 리소스 제한 설정

리소스 제한은 손상된 컨테이너가 호스트에 대한 서비스 거부 공격을 시작하는 것을 방지합니다. cgroups를 사용하여 CPU, 메모리 및 디스크 I/O를 제한하세요.

services:
  app:
    image: myapp
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M

Docker Compose v3의 경우 deploy 섹션을 사용합니다(swarm 또는 compose v2에서 작동). 일반 Docker의 경우 --memory--cpus를 사용하세요. 주의사항: 제한을 너무 낮게 설정하면 OOM 종료가 발생할 수 있습니다. 사용량을 모니터링하고 그에 따라 조정하세요.

6. 읽기 전용 루트 파일 시스템 사용

읽기 전용 루트 파일 시스템은 공격자가 컨테이너 내부에 악성 바이너리를 쓰거나 구성 파일을 수정하는 것을 방지합니다.

services:
  app:
    image: myapp
    read_only: true
    tmpfs:
      - /tmp:noexec,nosuid,size=64m

쓰기 액세스가 필요한 디렉토리(예: /tmp)에는 tmpfs를 마운트하세요. 이렇게 하면 모든 쓰기 가능한 데이터가 일시적으로 유지됩니다. 주의사항: 일부 애플리케이션은 영구 스토리지가 필요합니다. 이를 위해 명명된 볼륨을 사용하세요.

일반적인 함정

  • 커널 호환성: 사용자 네임스페이스 리매핑 및 일부 seccomp 규칙은 최신 Linux 커널(4.14+)이 필요합니다. 커널 버전을 확인하세요.
  • 성능 영향: Seccomp 및 사용자 네임스페이스는 약간의 오버헤드를 추가하지만 대부분의 워크로드에는 미미합니다. 특정 앱을 벤치마킹하세요.
  • 복잡성: 여섯 가지 조치를 한 번에 모두 추가하면 문제가 발생할 수 있습니다. 하나씩 적용하고 각 변경 사항을 테스트하세요.

오케스트레이션 패턴에 대한 더 넓은 시각은 멀티 테넌트 Docker 아키텍처 설계 가이드를 참조하세요.

결론

안전한 멀티 테넌트 Docker 호스트는 특별한 도구가 필요하지 않습니다. Docker의 내장 기능을 올바르게 사용하기만 하면 됩니다. 비루트 사용자로 시작하고, 모든 캐퍼빌리티를 제거하고, seccomp 프로필을 적용하고, 사용자 네임스페이스 리매핑을 활성화하고, 리소스 제한을 설정하고, 읽기 전용 파일 시스템을 사용하세요. 이 체크리스트는 가장 일반적인 이스케이프 기술을 차단하는 강력한 기준선을 형성합니다. 구현 후 docker-bench-security와 같은 보안 도구를 실행하여 구성을 확인하세요. 기억하세요: 보안은 제품이 아니라 과정입니다. 새로운 커널 취약점이 등장하면 설정을 재검토하세요. 호스팅 서비스를 선보이는 자동 랜딩 페이지를 원한다면 Pagenza를 사용하여 몇 분 안에 사이트를 온라인으로 만드세요.

Sources (5)