소개
Docker 는 개발자 및 DevOps 팀에게 필수적인 도구가 되었으며, 컨테이너화된 애플리케이션의 원활한 배포 및 관리를 가능하게 합니다. 개인 Docker 레지스트리를 사용할 때, 컨테이너 이미지를 보호하기 위해 Docker 클라이언트와 레지스트리 서버 간의 통신을 안전하게 유지하는 것이 중요합니다.
이 Lab 에서는 로컬 Docker 레지스트리를 설정하고 자체 서명된 SSL 인증서를 사용하여 보안을 유지하는 방법을 배웁니다. 이 방법은 신뢰할 수 있는 인증 기관에서 인증서를 구매하지 않고도 안전한 레지스트리가 필요한 개발 환경, 테스트 및 학습 시나리오에 적합합니다.
이 튜토리얼을 마치면, 안전한 통신을 위해 HTTPS 를 사용하는 작동하는 Docker 레지스트리를 갖게 되어 개발 환경 내에서 Docker 이미지를 안전하게 푸시하고 풀할 수 있습니다.
기본 Docker 레지스트리 설정
SSL 로 Docker 레지스트리를 보호하기 전에, 먼저 Docker 레지스트리가 무엇인지 이해하고 작동할 기본 레지스트리를 설정해 보겠습니다.
Docker 레지스트리란 무엇인가요?
Docker 레지스트리는 Docker 컨테이너 이미지를 위한 저장 및 배포 시스템입니다. 이를 통해 다음을 수행할 수 있습니다.
- Docker 이미지를 중앙 위치에 저장
- 팀 또는 조직과 이미지 공유
- 이미지에 대한 접근 제어
- 다양한 환경에서 이미지로부터 컨테이너 배포
Docker Hub 는 가장 잘 알려진 공개 레지스트리이지만, 많은 조직에서 보안, 성능 및 제어를 위해 개인 레지스트리를 갖는 것이 필수적입니다.
기본 레지스트리 설정
간단하고 안전하지 않은 Docker 레지스트리를 실행하는 것으로 시작해 보겠습니다.
레지스트리 데이터를 저장할 디렉토리를 생성합니다.
mkdir -p ~/project/registry-data공식 이미지를 사용하여 기본 Docker 레지스트리를 실행합니다.
docker run -d -p 5000:5000 --restart=always --name registry -v ~/project/registry-data:/var/lib/registry registry:2이 명령어는 다음을 수행합니다.
- 분리 모드 (
-d) 로 레지스트리 컨테이너를 실행합니다. - 호스트의 포트 5000 을 컨테이너의 포트 5000 에 매핑합니다.
- 컨테이너가 중지되면 자동으로 다시 시작하도록 설정합니다.
- 컨테이너 이름을 "registry"로 지정합니다.
- 레지스트리 데이터를 저장하기 위해 생성한 디렉토리를 마운트합니다.
- 분리 모드 (
레지스트리가 실행 중인지 확인합니다.
docker ps다음과 유사한 출력을 볼 수 있습니다.
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES a7d8098de3a2 registry:2 "/entrypoint.sh /etc…" 5 seconds ago Up 4 seconds 0.0.0.0:5000->5000/tcp registry샘플 이미지를 푸시하여 레지스트리를 테스트합니다.
먼저 작은 이미지를 풀합니다.
docker pull hello-world로컬 레지스트리에 대해 태그를 지정합니다.
docker tag hello-world localhost:5000/hello-world레지스트리에 푸시합니다.
docker push localhost:5000/hello-world이미지가 레지스트리에 푸시되는 것을 보여주는 출력을 볼 수 있습니다.
다음 단계에서 보안을 유지하기 전에 레지스트리 컨테이너를 중지합니다.
docker stop registry docker rm registry
이 기본 레지스트리는 작동하지만 중요한 제한 사항이 있습니다. 안전하지 않은 HTTP 를 사용합니다. Docker 클라이언트는 기본적으로 안전하지 않은 레지스트리에서 푸시하거나 풀하는 것을 거부합니다. 다음 단계에서는 SSL 로 레지스트리를 보호합니다.
자체 서명된 SSL 인증서 생성
Docker Registry 의 기본 사항을 이해했으므로, 자체 서명된 SSL 인증서를 생성하여 보안을 유지해 보겠습니다. 이 인증서는 레지스트리와의 HTTPS 통신을 가능하게 합니다.
자체 서명된 인증서란 무엇인가요?
자체 서명된 인증서는 신뢰할 수 있는 인증 기관 (CA) 에서 서명하지 않은 SSL 인증서입니다. 공용 인터넷에 노출된 프로덕션 환경에는 적합하지 않지만, 자체 서명된 인증서는 개발, 테스트 및 내부 애플리케이션에 완벽합니다.
인증서 및 키 생성
널리 사용되는 암호화 도구인 OpenSSL 을 사용하여 인증서를 생성합니다.
인증서를 저장할 디렉토리를 생성합니다.
mkdir -p ~/project/registry-certs cd ~/project/registry-certs개인 키를 생성합니다.
openssl genrsa -out registry.key 2048이 명령어는 2048 비트 RSA 개인 키를 생성합니다. 성공하면 출력이 표시되지 않습니다.
개인 키를 사용하여 인증서 서명 요청 (CSR) 을 생성합니다.
openssl req -new -key registry.key -out registry.csr인증서에 포함될 정보를 입력하라는 메시지가 표시됩니다.
Country Name (2 letter code) [AU]:US State or Province Name (full name) [Some-State]:California Locality Name (eg, city) []:San Francisco Organization Name (eg, company) [Internet Widgits Pty Ltd]:Example Company Organizational Unit Name (eg, section) []:IT Common Name (e.g. server FQDN or YOUR name) []:localhost Email Address []:admin@example.com참고:
Common Name에는 로컬 머신에서 레지스트리에 연결할 것이므로localhost를 입력합니다.다음도 요청받게 됩니다.
Please enter the following 'extra' attributes to be sent with your certificate request A challenge password []: An optional company name []:Enter 키를 눌러 비워둘 수 있습니다.
CSR 을 사용하여 자체 서명된 인증서를 생성합니다.
openssl x509 -req -days 365 -in registry.csr -signkey registry.key -out registry.crt이 명령어는 365 일 동안 유효한 자체 서명된 인증서를 생성합니다.
다음과 유사한 출력을 볼 수 있습니다.
Signature ok subject=C = US, ST = California, L = San Francisco, O = Example Company, OU = IT, CN = localhost, emailAddress = admin@example.com Getting Private key인증서 및 키 파일이 생성되었는지 확인합니다.
ls -l세 개의 파일이 표시됩니다.
total 12 -rw-r--r-- 1 labex labex 1220 [date] registry.crt -rw-r--r-- 1 labex labex 1054 [date] registry.csr -rw-r--r-- 1 labex labex 1679 [date] registry.key
이제 Docker 레지스트리를 보호하는 데 필요한 파일이 있습니다. 다음 단계에서는 HTTPS 통신에 이 인증서를 사용하도록 레지스트리를 구성합니다.
SSL 인증서로 Docker Registry 구성
이제 자체 서명된 인증서가 있으므로, 안전한 통신을 위해 SSL 을 사용하도록 Docker 레지스트리를 구성할 수 있습니다.
보안 레지스트리 설정
먼저, 레지스트리를 위한 간단한 구성 파일을 생성해 보겠습니다. 이 파일은 HTTPS 설정을 지정합니다.
mkdir -p ~/project/registry-config cd ~/project/registry-config nano config.yml파일에 다음 구성을 추가합니다.
version: 0.1 storage: filesystem: rootdirectory: /var/lib/registry http: addr: 0.0.0.0:5000 tls: certificate: /certs/registry.crt key: /certs/registry.key이 구성은 레지스트리에 다음을 지시합니다.
- 스토리지를 위해 파일 시스템을 사용합니다.
- 포트 5000 에서 모든 인터페이스를 수신 대기합니다.
- 인증서 및 키를 사용하여 TLS(HTTPS) 를 사용합니다.
Ctrl+X,Y를 누른 다음Enter를 눌러 저장하고 종료합니다.이제 SSL 인증서로 레지스트리를 실행해 보겠습니다.
docker run -d -p 5000:5000 --restart=always --name registry \ -v ~/project/registry-data:/var/lib/registry \ -v ~/project/registry-certs:/certs \ -v ~/project/registry-config/config.yml:/etc/docker/registry/config.yml \ registry:2이 명령어는 다음을 수행합니다.
- 인증서 및 키 디렉토리를 마운트합니다.
- 구성 파일을 마운트합니다.
- 이전에 생성한 동일한 데이터 디렉토리를 사용합니다.
레지스트리가 실행 중인지 확인합니다.
docker ps레지스트리 컨테이너가 실행 중임을 보여주는 출력을 볼 수 있습니다.
인증서를 신뢰하도록 Docker 클라이언트 구성
기본적으로 Docker 클라이언트는 자체 서명된 인증서를 신뢰하지 않습니다. Docker 가 인증서를 신뢰하도록 지시해야 합니다.
Docker 가 신뢰할 수 있는 인증서를 저장할 디렉토리를 생성합니다.
sudo mkdir -p /etc/docker/certs.d/localhost:5000이 디렉토리에 인증서를 복사합니다.
sudo cp ~/project/registry-certs/registry.crt /etc/docker/certs.d/localhost:5000/ca.crt변경 사항을 적용하기 위해 Docker 서비스를 다시 시작합니다.
sudo systemctl restart docker완료하는 데 몇 초가 걸릴 수 있습니다.
Docker 를 다시 시작하면 레지스트리 컨테이너가 중지되므로 다시 시작해 보겠습니다.
docker start registry레지스트리가 다시 실행 중인지 확인합니다.
docker ps
이제 Docker 레지스트리는 자체 서명된 인증서로 HTTPS 를 사용하도록 구성되었으며, Docker 클라이언트는 localhost:5000 에 연결할 때 이 인증서를 신뢰하도록 구성되었습니다.
보안 Docker Registry 테스트
이제 SSL 로 Docker 레지스트리가 실행되고 있으므로, 이미지를 푸시하고 풀하여 테스트해 보겠습니다. 이렇게 하면 모든 것이 올바르게 작동하는지 확인할 수 있습니다.
샘플 이미지로 테스트
먼저, 테스트에 사용할 샘플 이미지를 풀해 보겠습니다.
docker pull alpine:latestDocker 가 Alpine Linux 이미지를 다운로드하는 것을 보여주는 출력을 볼 수 있습니다.
보안 레지스트리에 대한 이미지를 태그합니다.
docker tag alpine:latest localhost:5000/alpine:latest이 명령어는 로컬 레지스트리를 가리키는 새 태그를 생성합니다.
이미지를 보안 레지스트리에 푸시합니다.
docker push localhost:5000/alpine:latest이미지 레이어가 레지스트리에 푸시되는 것을 보여주는 출력을 볼 수 있습니다.
The push refers to repository [localhost:5000/alpine] 213ec9aee27d: Pushed latest: digest: sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f size: 528레지스트리에서 풀하고 있는지 확인하기 위해 로컬 이미지를 제거합니다.
docker rmi localhost:5000/alpine:latest docker rmi alpine:latest보안 레지스트리에서 이미지를 풀합니다.
docker pull localhost:5000/alpine:latestDocker 가 레지스트리에서 이미지를 다운로드하는 것을 보여주는 출력을 볼 수 있습니다.
latest: Pulling from alpine 213ec9aee27d: Pull complete Digest: sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f Status: Downloaded newer image for localhost:5000/alpine:latest localhost:5000/alpine:latest
레지스트리 내용 확인
Docker Registry API 를 사용하여 레지스트리 내용을 살펴보겠습니다.
레지스트리의 모든 저장소를 나열합니다.
curl -X GET https://localhost:5000/v2/_catalog --cacert ~/project/registry-certs/registry.crt다음과 같은 출력을 볼 수 있습니다.
{ "repositories": ["alpine", "hello-world"] }이것은 레지스트리에 푸시한 모든 이미지를 보여줍니다.
alpine 저장소의 모든 태그를 나열합니다.
curl -X GET https://localhost:5000/v2/alpine/tags/list --cacert ~/project/registry-certs/registry.crt다음과 같은 출력을 볼 수 있습니다.
{ "name": "alpine", "tags": ["latest"] }
우리가 달성한 것 이해하기
우리가 한 일을 검토해 보겠습니다.
- 자체 서명된 SSL 인증서를 사용하여 HTTPS 로 Docker 레지스트리를 설정했습니다.
- 이 인증서를 신뢰하도록 Docker 클라이언트를 구성했습니다.
- 보안 레지스트리에 이미지를 성공적으로 푸시하고 풀했습니다.
이 설정은 다음을 제공합니다.
- 암호화된 통신: Docker 클라이언트와 레지스트리 간에 전송되는 모든 데이터는 암호화됩니다.
- 인증 기반: SSL 은 인증을 구현하기 위한 첫 번째 단계입니다.
- Docker 클라이언트 호환성: Docker 클라이언트는 기본적으로 로컬 호스트가 아닌 레지스트리에 대해 HTTPS 를 요구합니다.
이제 이 보안 레지스트리를 개발 및 테스트 요구 사항에 사용할 수 있습니다. 프로덕션 환경의 경우 일반적으로 자체 서명된 인증서 대신 신뢰할 수 있는 인증 기관의 인증서를 사용합니다.
요약
축하합니다! 자체 서명된 SSL 인증서를 사용하여 보안 Docker 레지스트리를 성공적으로 설정했습니다. 다음은 수행한 작업입니다.
- 기본 Docker 레지스트리를 설정하고 그 목적과 기능을 이해했습니다.
- 레지스트리 보안을 위해 자체 서명된 SSL 인증서를 생성했습니다.
- 인증서로 HTTPS 를 사용하도록 Docker 레지스트리를 구성했습니다.
- 자체 서명된 인증서를 신뢰하도록 Docker 클라이언트를 구성했습니다.
- 이미지를 푸시하고 풀하여 보안 레지스트리를 성공적으로 테스트했습니다.
이러한 기술을 통해 개발 및 테스트 환경을 위한 보안 개인 레지스트리를 만들 수 있습니다. 개인 레지스트리는 Docker 이미지가 저장되는 위치와 액세스할 수 있는 사용자를 제어할 수 있도록 하며, SSL 암호화는 전송 중에 데이터가 안전하게 유지되도록 보장합니다.
프로덕션 환경의 경우 일반적으로 신뢰할 수 있는 인증 기관의 인증서를 사용하지만, 구성 프로세스는 이 랩에서 배운 것과 유사합니다.
이제 컨테이너화된 애플리케이션의 보안을 강화하여 자체 프로젝트 및 개발 워크플로우에서 보안 Docker 레지스트리를 자신 있게 구현할 수 있습니다.



