본문 바로가기
일반IT/IT보안

🔐 SSH로 Docker 소켓에 안전하게 접근하기 — 포트 2375 열지 마세요!

by gasbugs 2026. 3. 31.

Docker 소켓을 인터넷에 직접 노출하는 것은 서버에 root 계정을 공개하는 것과 다름없습니다.

🎯 이 글에서 다루는 것

  • Docker 소켓(/var/run/docker.sock)이 왜 위험한지
  • SSH 터널로 Docker 소켓에 안전하게 접근하는 3가지 방법
  • DOCKER_HOST 환경변수 vs docker context 비교
  • CI/CD 파이프라인에서의 실전 활용
  • 놓치기 쉬운 보안 실수 모음

📌 도입 / 배경

원격 서버의 Docker를 관리하고 싶을 때 가장 먼저 떠오르는 방법이 있습니다. Docker 데몬의 TCP 포트(2375 또는 2376)를 열고 외부에서 접근하는 것이죠.

 

하지만 잠깐, 이건 정말 위험한 선택입니다.

Docker 데몬은 기본적으로 로컬 클라이언트의 요청만 받는 Unix 소켓에서 수신 대기합니다. 그런데 이걸 TCP로 열어버리면 어떻게 될까요?

 

Docker 데몬은 호스트 시스템에서 root 권한으로 실행되기 때문에, 인증 없이 그 API에 접근할 수 있다는 것은 서버에 대한 root 접근권한을 세상에 공개하는 것과 동일합니다.

 

실제로 인터넷에 2375 포트를 열어놓은 서버는 수분 내로 봇에 의해 발견되고, 악성 컨테이너가 배포됩니다. 암호화폐 채굴, 랜섬웨어, 백도어 설치까지 이어지는 사례가 적지 않습니다.

 

그렇다면 원격에서 Docker를 안전하게 관리하려면 어떻게 해야 할까요? 정답은 바로 SSH 터널입니다.


🔍 Docker 소켓과 SSH 터널의 기본 개념

Docker 소켓이란?

Docker CLI(docker 명령어)가 Docker 데몬과 통신하는 채널입니다. 기본 경로는 /var/run/docker.sock이며, 이 Unix 소켓 파일을 통해 모든 Docker 명령이 처리됩니다.

[docker CLI] ──── /var/run/docker.sock ──── [dockerd 데몬]

SSH 터널이란?

SSH 연결 위에 다른 프로토콜의 트래픽을 안전하게 실어 나르는 기법입니다. SSH가 이미 암호화, 인증, 무결성 검증을 모두 처리해주기 때문에 별도의 TLS 설정 없이도 안전한 통신이 가능합니다.


💻 방법 1: SSH 로컬 포워딩으로 소켓 터널링 (가장 기본적인 방법)

원격 서버의 Docker 소켓을 로컬 포트로 포워딩하는 방식입니다.

# 로컬 포트 2375를 원격 서버의 Docker 소켓으로 포워딩
ssh -L localhost:2375:/var/run/docker.sock user@REMOTE_HOST -fN

 

각 옵션 설명:

  • -L localhost:2375:/var/run/docker.sock : 로컬 2375 포트를 원격 소켓으로 연결
  • -f : 백그라운드에서 실행
  • -N : 원격 명령 실행 없이 터널만 유지

 

터널이 열린 후에는 환경변수를 설정해 Docker CLI가 이 터널을 사용하게 합니다:

export DOCKER_HOST=tcp://localhost:2375
docker ps       # 원격 서버의 컨테이너 목록 출력
docker images   # 원격 서버의 이미지 목록 출력

 

이 방식의 장점은 인터넷에 포트를 노출하지 않으면서, SSH의 검증된 인증 방식(키, MFA 등)을 그대로 활용한다는 것입니다.

터널 종료 시:

# 터널 프로세스 찾기
ps aux | grep ssh

# PID로 종료
kill $PID

# DOCKER_HOST 해제
unset DOCKER_HOST

💻 방법 2: DOCKER_HOST에 ssh:// 스킴 사용 (Docker 18.09+)

Docker 18.09 버전부터는 SSH를 네이티브로 지원합니다. 터널을 별도로 만들 필요 없이 DOCKER_HOST 환경변수에 바로 SSH 주소를 지정할 수 있습니다.

# 환경변수 방식 (임시)
export DOCKER_HOST=ssh://docker-user@host1.example.com
docker ps
docker run -d nginx

# 사용 후 원래대로 복원
unset DOCKER_HOST

이 방식은 context를 별도로 생성하지 않아도 되므로 다른 엔진과 임시로 연결할 때 유용합니다.

⚠️ 중요: ssh:// 방식은 반드시 SSH 키 인증이 필요합니다. 패스워드 인증은 Docker에서 지원되지 않으며, DOCKER_HOST 기반 설정에서는 불가능합니다.

SSH 키 등록:

# 키 생성
ssh-keygen -t ed25519 -C "docker-remote-key"

# 원격 서버에 공개 키 등록
ssh-copy-id docker-user@host1.example.com

# ssh-agent에 키 추가
ssh-add ~/.ssh/id_ed25519

 

SSH 연결 최적화 (~/.ssh/config):

Host docker-remote
    HostName host1.example.com
    User docker-user
    IdentityFile ~/.ssh/id_ed25519
    ControlMaster auto
    ControlPath ~/.ssh/control-%C
    ControlPersist yes

 

ControlMaster와 ControlPersist 설정을 통해 하나의 SSH 연결을 여러 docker CLI 호출에서 재사용할 수 있어, 매번 핸드셰이크를 반복하지 않아도 됩니다.

이후 훨씬 간결하게 사용 가능합니다:

export DOCKER_HOST=ssh://docker-remote
docker ps

💻 방법 3: docker context로 원격 엔진 관리 (운영 추천)

여러 원격 서버를 자주 오가며 관리한다면 docker context가 가장 깔끔한 방법입니다.

# 원격 컨텍스트 생성
docker context create my-remote-engine \
  --docker "host=ssh://docker-user@host1.example.com" \
  --description "Production Server"

# 컨텍스트 목록 확인
docker context ls

# 컨텍스트 전환
docker context use my-remote-engine

# 이제 모든 docker 명령이 원격 서버에서 실행됨
docker ps
docker run -d --name web nginx

# 로컬로 복귀
docker context use default

 

원격 엔진 컨텍스트를 생성한 뒤 docker context use로 활성화하면 VS Code 및 Docker CLI 모두 해당 원격 머신 컨텍스트를 사용하게 됩니다.


💻 방법 4: CI/CD 파이프라인에서 활용

GitHub Actions, GitLab CI, Jenkins 등에서 원격 Docker 호스트에 배포할 때 유용한 패턴입니다.

#!/bin/bash
# deploy.sh — CI/CD 원격 배포 스크립트

SSH_USER="deploy"
SSH_HOST="prod.example.com"

# 환경변수만 설정하면 끝 (SSH 키는 CI 시크릿에 등록)
export DOCKER_HOST="ssh://${SSH_USER}@${SSH_HOST}"

# 이미지 pull 및 컨테이너 재배포
docker pull myapp:latest
docker stop myapp || true
docker rm myapp || true
docker run -d \
  --name myapp \
  --restart unless-stopped \
  -p 80:8080 \
  myapp:latest

echo "✅ 배포 완료"
unset DOCKER_HOST

 

GitLab CI 예시:

# .gitlab-ci.yml
deploy:
  stage: deploy
  image: docker:latest
  before_script:
    - eval $(ssh-agent -s)
    - echo "$SSH_PRIVATE_KEY" | ssh-add -
    - mkdir -p ~/.ssh
    - ssh-keyscan $PROD_HOST >> ~/.ssh/known_hosts
  script:
    - export DOCKER_HOST="ssh://deploy@$PROD_HOST"
    - docker pull $CI_REGISTRY_IMAGE:latest
    - docker run -d --name app $CI_REGISTRY_IMAGE:latest

⚠️ 주의사항 / 흔한 실수

① known_hosts 미등록 오류

처음 연결 시 호스트 키 검증 실패로 연결이 거부됩니다.

# 반드시 먼저 known_hosts에 등록
ssh-keyscan -H host1.example.com >> ~/.ssh/known_hosts
# 또는 한 번 직접 SSH 접속하여 확인
ssh docker-user@host1.example.com

 

② SSH 키 패스프레이즈 문제

키에 패스프레이즈가 설정되어 있으면 docker 명령마다 비밀번호를 요청합니다. ssh-agent에 미리 키를 등록해야 합니다.

eval $(ssh-agent -s)
ssh-add ~/.ssh/id_ed25519
# 등록 확인
ssh-add -l

 

③ 원격 사용자의 docker 그룹 미등록

원격 호스트에서 SSH_USER는 Docker 소켓에 접근 권한이 있는 사용자여야 합니다 (예: docker 그룹 멤버).

# 원격 서버에서 실행
sudo usermod -aG docker docker-user
# 그룹 변경 적용 (로그아웃 후 재접속 필요)

 

④ TCP 포트를 인터넷에 직접 노출하지 말 것

# ❌ 절대 금지 — 포트를 모든 IP에 오픈
"hosts": ["unix:///var/run/docker.sock", "tcp://0.0.0.0:2375"]

# ✅ 루프백만 허용 (로컬 SSH 터널 용도)
"hosts": ["unix:///var/run/docker.sock", "tcp://127.0.0.1:2375"]

✅ 정리 / 마무리

방법 장점 적합한 상황
ssh -L 포트 포워딩 가장 유연, 세밀한 제어 일시적 연결, 레거시 환경
DOCKER_HOST=ssh:// 설정 간단, 추가 소프트웨어 불필요 빠른 임시 연결, CI/CD
docker context 멀티 서버 관리에 최적화 운영 환경, 일상적 원격 관리

 

핵심을 다시 한번 정리하면:

  • Docker 소켓은 절대 인터넷에 직접 노출하지 않는다
  • SSH 터널은 추가 인프라 없이 바로 사용 가능한 가장 안전한 원격 접근 방법
  • Docker 18.09 이상에서는 ssh:// 스킴이 네이티브로 지원되어 구성이 매우 단순해졌다
  • 운영 환경에서는 docker context로 원격 호스트를 체계적으로 관리하자

다음 단계로는 TLS 상호 인증 방식 또는 Tailscale/ZeroTier 같은 Zero-Trust 네트워크를 활용한 Docker 원격 접근 방식도 검토해 볼 만 합니다.