지난 가이드에서는 Docker 데몬을 외부에서 접속할 수 있도록 TCP 포트를 여는 방법을 알아보았습니다. 하지만 당시 강조했듯이, 암호화되지 않은 Docker API를 외부에 노출하는 것은 매우 위험합니다.
오늘은 이 문제를 해결하기 위해, 자체 서명된 인증 기관(CA)을 만들고, TLS 인증서를 발급하여 Docker 서버와 클라이언트 간의 모든 통신을 암호화하는 방법을 단계별로 상세히 안내합니다. 이 절차를 통해 서버는 신뢰된 클라이언트의 접속만 허용하고, 클라이언트는 신뢰된 서버에만 접속하여 중간자 공격(Man-in-the-middle attack)을 방지하는 안전한 환경을 구축할 수 있습니다.
사전 준비#
- OpenSSL: 인증서 생성을 위한 도구입니다. 대부분의 Linux 배포판에 기본 설치되어 있으며, 없다면
sudo apt-get install openssl
명령어로 설치합니다.
인증서 생성#
모든 인증서 파일을 한곳에서 관리하기 위해 작업 디렉토리를 생성하고 그 안에서 모든 작업을 진행합니다.
# 변수 설정 (자신의 환경에 맞게 수정)
export SERVER_HOSTNAME="docker.example.com"
export SERVER_IP="192.168.0.100"
# 작업 디렉토리 생성 및 이동
mkdir ~/docker-certs
cd ~/docker-certs
인증 기관(CA) 키 및 인증서 생성#
먼저, 우리의 서버 및 클라이언트 인증서를 발급할 최상위 인증 기관(CA)을 만듭니다.
# 1. CA 개인키 생성
openssl genrsa -aes256 -out ca-key.pem 4096
# 2. CA 인증서 생성 (ca.pem)
# Common Name(CN)은 구분을 위해 "My Docker CA" 와 같이 자유롭게 입력합니다.
openssl req -new -x509 -days 3650 -key ca-key.pem -sha256 -out ca.pem
서버 키 및 인증서 생성#
이제 Docker 데몬(서버)이 사용할 개인키와 인증서를 생성합니다. 이 인증서는 CA에 의해 서명됩니다.
# 1. 서버 개인키 생성
openssl genrsa -out server-key.pem 4096
# 2. 서버 인증서 서명 요청(CSR) 생성
# ※ 중요: Common Name(CN)에 반드시 서버의 DNS 호스트명을 입력해야 합니다.
openssl req -subj "/CN=${SERVER_HOSTNAME}" -sha256 -new -key server-key.pem -out server.csr
# 3. 서버 인증서가 IP 주소와 호스트명 모두에서 유효하도록 설정 파일 생성
echo "subjectAltName = DNS:${SERVER_HOSTNAME},IP:${SERVER_IP}" >> extfile.cnf
# 4. CA를 이용해 서버 인증서 서명 (server-cert.pem)
openssl x509 -req -days 3650 -sha256 -in server.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out server-cert.pem -extfile extfile.cnf
클라이언트 키 및 인증서 생성#
원격에서 서버에 접속할 클라이언트가 사용할 개인키와 인증서를 생성합니다. 이 인증서 역시 CA에 의해 서명되어야 서버가 신뢰할 수 있습니다.
# 1. 클라이언트 개인키 생성
openssl genrsa -out key.pem 4096
# 2. 클라이언트 인증서 서명 요청(CSR) 생성
# Common Name(CN)은 "client" 등 식별 가능한 이름으로 입력합니다.
openssl req -subj "/CN=client" -new -key key.pem -out client.csr
# 3. 클라이언트 인증 용도로 확장 키 사용 설정
echo "extendedKeyUsage = clientAuth" > extfile-client.cnf
# 4. CA를 이용해 클라이언트 인증서 서명 (cert.pem)
openssl x509 -req -days 3650 -sha256 -in client.csr -CA ca.pem -CAkey ca-key.pem \
-CAcreateserial -out cert.pem -extfile extfile-client.cnf
생성된 파일 정리 및 권한 설정#
이제 불필요한 파일(CSR, .cnf 등)을 정리하고, 개인키 파일의 권한을 소유자만 읽을 수 있도록 변경하여 보안을 강화합니다.
# 불필요한 파일 삭제
rm -v client.csr server.csr extfile.cnf extfile-client.cnf ca.srl
# 개인키 파일 권한 설정 (읽기 전용)
chmod -v 0400 ca-key.pem key.pem server-key.pem
# 인증서 파일 권한 설정 (읽기 전용)
chmod -v 0444 ca.pem server-cert.pem cert.pem
Docker 데몬 설정#
생성된 서버용 인증서를 Docker가 읽을 수 있는 위치로 복사하고, daemon.json
파일을 수정하여 TLS를 활성화합니다.
인증서 복사
sudo mkdir -p /etc/docker/certs
sudo cp -v ca.pem server-cert.pem server-key.pem /etc/docker/certs/
/etc/docker/daemon.json
파일 수정
TLS를 강제하고, 인증서 경로를 지정하며, 보안 포트인 2376을 사용하도록 변경합니다.
{
"hosts": ["tcp://0.0.0.0:2376", "unix:///var/run/docker.sock"],
"tlsverify": true,
"tlscacert": "/etc/docker/certs/ca.pem",
"tlscert": "/etc/docker/certs/server-cert.pem",
"tlskey": "/etc/docker/certs/server-key.pem"
}
Docker 재시작
sudo systemctl restart docker
원격 클라이언트 설정 및 접속#
원격으로 접속할 클라이언트 PC로 아래 세 개의 파일을 안전하게 전송합니다.
ca.pem
(인증 기관 인증서)cert.pem
(클라이언트 인증서)key.pem
(클라이언트 개인키)
클라이언트 PC의 ~/.docker
디렉토리에 전송받은 파일들을 저장합니다. 이 디렉토리는 Docker가 기본적으로 인증서를 찾는 위치입니다.
아래 명령어를 사용하여 원격 서버에 안전하게 접속되는지 테스트합니다.
docker --tlsverify \
--tlscacert=~/.docker/ca.pem \
--tlscert=~/.docker/cert.pem \
--tlskey=~/.docker/key.pem \
-H=${SERVER_HOSTNAME}:2375 version
환경 변수 설정으로 편리하게 사용하기
매번 긴 명령어를 입력하는 대신, 클라이언트 PC의 셸 설정 파일(.bashrc, .zshrc 등)에 아래 환경 변수를 추가하면 docker ps와 같은 일반 명령어로 바로 원격 서버에 접속할 수 있습니다.
export DOCKER_HOST=tcp://${SERVER_HOSTNAME}:2375
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=~/.docker
마무리하며#
이것으로 Docker 원격 연결을 TLS로 암호화하는 모든 과정이 완료되었습니다. 이제 여러분의 Docker 서버는 지정된 CA가 서명한 유효한 클라이언트 인증서를 가진 사용자만 접속을 허용하는 안전한 상태가 되었습니다. 이 방식은 프로덕션 환경이나 신뢰할 수 없는 네트워크에서 원격으로 Docker를 관리할 때 필수적인 보안 조치입니다.
참조
- Docker 공식 문서 - Protect the Docker daemon socket: https://docs.docker.com/engine/security/protect-access/