🚨 왜 /var/run/docker.sock 마운트는 ‘자살 행위’인가? #
도커 환경을 운영하다 보면 Docker Socket Proxy의 필요성을 절실히 느끼는 순간이 옵니다. 보통 Traefik이나 Portainer, Watchtower 같은 도구들은 실시간으로 컨테이너 상태를 감시하거나 제어하기 위해 /var/run/docker.sock 파일에 접근해야 합니다. 하지만 아무런 보호 장치 없이 이 소켓 파일을 컨테이너 내부에 직접 볼륨 마운트하는 것은, 해당 컨테이너를 장악한 해커에게 호스트 서버의 Root 권한을 통째로 바치는 것과 다름없습니다.
실제로 컨테이너 내부에서 도커 소켓에 접근할 수 있다면, 해커는 호스트의 파일 시스템을 마운트한 새로운 컨테이너를 띄워 중요 데이터를 탈취하거나 시스템 전체를 마비시킬 수 있습니다. 이러한 Privilege Escalation 공격을 막기 위한 최선의 대안이 바로 API 방화벽 역할을 수행하는 Docker Socket Proxy입니다.

🛠️ Docker Socket Proxy 구축을 위한 Compose 설정 #
단순히 프록시를 띄우는 것보다 중요한 것은 네트워크 격리입니다. 호스트 포트(2375)를 외부로 노출하지 않고, 오직 내부 네트워크(socket_proxy)를 통해서만 통신하도록 설정해야 합니다. 아래는 실무에서 바로 적용 가능한 최적화된 docker-compose.yml 예시입니다.
services:
socket-proxy:
container_name: socket-proxy
image: tecnativa/docker-socket-proxy
networks:
socket_proxy:
ipv4_address: 192.168.91.254
security_opt:
- no-new-privileges:true
restart: always
# 포트포워딩 주석 처리: 외부 노출 철저 차단
# ports:
# - "2375:2375"
volumes:
- "/var/run/docker.sock:/var/run/docker.sock"
environment:
- LOG_LEVEL=info
## API 접근 권한 설정 (1=허용, 0=차단)
- EVENTS=1
- PING=1
- VERSION=1
- AUTH=0
- SECRETS=0
- CONTAINERS=1
- IMAGES=1
- INFO=1
- NETWORKS=1
- SERVICES=1
- TASKS=1
- VOLUMES=1
- POST=1 # Watchtower 등 업데이트 도구 사용 시 필요
- BUILD=0
- COMMIT=0
- CONFIGS=0
- NODES=0
- SWARM=0💡 DevOps 실무 팁:
ipv4_address를 고정하는 이유는 Traefik이나 Portainer 설정에서 엔드포인트를 지정할 때 컨테이너 재시작 후에도 IP가 바뀌지 않도록 보장하기 위함입니다.

🔐 ACL 튜닝: 최소 권한 원칙의 적용 #
Docker Socket Proxy의 핵심은 환경 변수를 통한 세밀한 ACL(Access Control List) 관리입니다. 무조건 모든 권한을 1로 설정하면 프록시를 쓰는 의미가 퇴색됩니다. 사용하는 서비스별로 필요한 최소 권한을 아래 표를 참고하여 설정하십시오.
| 서비스명 | 필요 권한 (최소) | 설명 |
|---|---|---|
| Traefik | CONTAINERS, NETWORKS | 레이블 기반 라우팅 정보 수집 |
| Portainer | INFO, VOLUMES, IMAGES… | 전반적인 대시보드 모니터링 |
| Watchtower | IMAGES, POST, CONTAINERS_DELETE | 이미지 비교 및 컨테이너 재실행 |
특히 POST=1 설정은 주의가 필요합니다. Watchtower처럼 컨테이너를 중지시키고 다시 실행해야 하는 도구를 사용할 때만 허용하고, 읽기 전용 모니터링 툴만 사용한다면 반드시 0으로 유지하는 것이 보안상 유리합니다.
🚀 실무 적용: Traefik 연동 예시 #
이제 기존에 /var/run/docker.sock을 직접 마운트하던 설정들을 모두 제거할 차례입니다. Traefik 설정 파일에서 endpoint를 프록시 서버의 내부 IP로 변경합니다.
# Traefik 컨테이너 설정 예시
command:
- "--providers.docker=true"
- "--providers.docker.endpoint=tcp://192.168.91.254:2375"
- "--providers.docker.exposedByDefault=false"
# volumes:
# - /var/run/docker.sock:/var/run/docker.sock # 과감히 삭제하세요!이렇게 설정하면 Traefik은 더 이상 호스트의 소켓 파일에 직접 접근하지 않습니다. 대신 socket-proxy를 거치게 되며, 허용되지 않은 API 호출(예: 도커 설정 변경 등)은 프록시 단에서 차단됩니다. 이는 공격자가 Traefik의 취약점을 이용해 컨테이너 내부로 침투하더라도, 호스트 서버로 권한을 확장하는 것을 물리적으로 막아주는 최후의 방어선이 됩니다.
💡 트러블슈팅 경험: 간혹 특정 앱에서 ‘Permission Denied’ 로그가 발생한다면, 프록시 컨테이너의
LOG_LEVEL=debug로 올려보세요. 어떤 API 경로(Endpoint)가 차단되었는지 정확히 파악할 수 있어 ACL 수정이 훨씬 수월해집니다.
보안은 언제나 ‘불편함’과 ‘안전함’ 사이의 저울질입니다. 하지만 도커 소켓 노출만큼은 타협의 대상이 되어서는 안 됩니다. Docker 공식 보안 가이드에서도 강조하듯, 권한 분리는 컨테이너 아키텍처의 핵심입니다.
더 많은 가이드 보기를 통해 인프라 보안을 한 단계 더 업그레이드해 보세요.
