Docker 레지스트리 자체 서명 SSL 인증서 설정 방법

DockerBeginner
지금 연습하기

소개

Docker 는 개발자 및 DevOps 팀에게 필수적인 도구가 되었으며, 컨테이너화된 애플리케이션의 원활한 배포 및 관리를 가능하게 합니다. 개인 Docker 레지스트리를 사용할 때, 컨테이너 이미지를 보호하기 위해 Docker 클라이언트와 레지스트리 서버 간의 통신을 안전하게 유지하는 것이 중요합니다.

이 Lab 에서는 로컬 Docker 레지스트리를 설정하고 자체 서명된 SSL 인증서를 사용하여 보안을 유지하는 방법을 배웁니다. 이 방법은 신뢰할 수 있는 인증 기관에서 인증서를 구매하지 않고도 안전한 레지스트리가 필요한 개발 환경, 테스트 및 학습 시나리오에 적합합니다.

이 튜토리얼을 마치면, 안전한 통신을 위해 HTTPS 를 사용하는 작동하는 Docker 레지스트리를 갖게 되어 개발 환경 내에서 Docker 이미지를 안전하게 푸시하고 풀할 수 있습니다.

기본 Docker 레지스트리 설정

SSL 로 Docker 레지스트리를 보호하기 전에, 먼저 Docker 레지스트리가 무엇인지 이해하고 작동할 기본 레지스트리를 설정해 보겠습니다.

Docker 레지스트리란 무엇인가요?

Docker 레지스트리는 Docker 컨테이너 이미지를 위한 저장 및 배포 시스템입니다. 이를 통해 다음을 수행할 수 있습니다.

  • Docker 이미지를 중앙 위치에 저장
  • 팀 또는 조직과 이미지 공유
  • 이미지에 대한 접근 제어
  • 다양한 환경에서 이미지로부터 컨테이너 배포

Docker Hub 는 가장 잘 알려진 공개 레지스트리이지만, 많은 조직에서 보안, 성능 및 제어를 위해 개인 레지스트리를 갖는 것이 필수적입니다.

기본 레지스트리 설정

간단하고 안전하지 않은 Docker 레지스트리를 실행하는 것으로 시작해 보겠습니다.

  1. 레지스트리 데이터를 저장할 디렉토리를 생성합니다.

    mkdir -p ~/project/registry-data
    
  2. 공식 이미지를 사용하여 기본 Docker 레지스트리를 실행합니다.

    docker run -d -p 5000:5000 --restart=always --name registry -v ~/project/registry-data:/var/lib/registry registry:2
    

    이 명령어는 다음을 수행합니다.

    • 분리 모드 (-d) 로 레지스트리 컨테이너를 실행합니다.
    • 호스트의 포트 5000 을 컨테이너의 포트 5000 에 매핑합니다.
    • 컨테이너가 중지되면 자동으로 다시 시작하도록 설정합니다.
    • 컨테이너 이름을 "registry"로 지정합니다.
    • 레지스트리 데이터를 저장하기 위해 생성한 디렉토리를 마운트합니다.
  3. 레지스트리가 실행 중인지 확인합니다.

    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
    
  4. 샘플 이미지를 푸시하여 레지스트리를 테스트합니다.

    먼저 작은 이미지를 풀합니다.

    docker pull hello-world
    

    로컬 레지스트리에 대해 태그를 지정합니다.

    docker tag hello-world localhost:5000/hello-world
    

    레지스트리에 푸시합니다.

    docker push localhost:5000/hello-world
    

    이미지가 레지스트리에 푸시되는 것을 보여주는 출력을 볼 수 있습니다.

  5. 다음 단계에서 보안을 유지하기 전에 레지스트리 컨테이너를 중지합니다.

    docker stop registry
    docker rm registry
    

이 기본 레지스트리는 작동하지만 중요한 제한 사항이 있습니다. 안전하지 않은 HTTP 를 사용합니다. Docker 클라이언트는 기본적으로 안전하지 않은 레지스트리에서 푸시하거나 풀하는 것을 거부합니다. 다음 단계에서는 SSL 로 레지스트리를 보호합니다.

자체 서명된 SSL 인증서 생성

Docker Registry 의 기본 사항을 이해했으므로, 자체 서명된 SSL 인증서를 생성하여 보안을 유지해 보겠습니다. 이 인증서는 레지스트리와의 HTTPS 통신을 가능하게 합니다.

자체 서명된 인증서란 무엇인가요?

자체 서명된 인증서는 신뢰할 수 있는 인증 기관 (CA) 에서 서명하지 않은 SSL 인증서입니다. 공용 인터넷에 노출된 프로덕션 환경에는 적합하지 않지만, 자체 서명된 인증서는 개발, 테스트 및 내부 애플리케이션에 완벽합니다.

인증서 및 키 생성

널리 사용되는 암호화 도구인 OpenSSL 을 사용하여 인증서를 생성합니다.

  1. 인증서를 저장할 디렉토리를 생성합니다.

    mkdir -p ~/project/registry-certs
    cd ~/project/registry-certs
    
  2. 개인 키를 생성합니다.

    openssl genrsa -out registry.key 2048
    

    이 명령어는 2048 비트 RSA 개인 키를 생성합니다. 성공하면 출력이 표시되지 않습니다.

  3. 개인 키를 사용하여 인증서 서명 요청 (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 키를 눌러 비워둘 수 있습니다.

  4. 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
    
  5. 인증서 및 키 파일이 생성되었는지 확인합니다.

    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 레지스트리를 구성할 수 있습니다.

보안 레지스트리 설정

  1. 먼저, 레지스트리를 위한 간단한 구성 파일을 생성해 보겠습니다. 이 파일은 HTTPS 설정을 지정합니다.

    mkdir -p ~/project/registry-config
    cd ~/project/registry-config
    nano config.yml
    
  2. 파일에 다음 구성을 추가합니다.

    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) 를 사용합니다.
  3. Ctrl+X, Y를 누른 다음 Enter를 눌러 저장하고 종료합니다.

  4. 이제 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
    

    이 명령어는 다음을 수행합니다.

    • 인증서 및 키 디렉토리를 마운트합니다.
    • 구성 파일을 마운트합니다.
    • 이전에 생성한 동일한 데이터 디렉토리를 사용합니다.
  5. 레지스트리가 실행 중인지 확인합니다.

    docker ps
    

    레지스트리 컨테이너가 실행 중임을 보여주는 출력을 볼 수 있습니다.

인증서를 신뢰하도록 Docker 클라이언트 구성

기본적으로 Docker 클라이언트는 자체 서명된 인증서를 신뢰하지 않습니다. Docker 가 인증서를 신뢰하도록 지시해야 합니다.

  1. Docker 가 신뢰할 수 있는 인증서를 저장할 디렉토리를 생성합니다.

    sudo mkdir -p /etc/docker/certs.d/localhost:5000
    
  2. 이 디렉토리에 인증서를 복사합니다.

    sudo cp ~/project/registry-certs/registry.crt /etc/docker/certs.d/localhost:5000/ca.crt
    
  3. 변경 사항을 적용하기 위해 Docker 서비스를 다시 시작합니다.

    sudo systemctl restart docker
    

    완료하는 데 몇 초가 걸릴 수 있습니다.

  4. Docker 를 다시 시작하면 레지스트리 컨테이너가 중지되므로 다시 시작해 보겠습니다.

    docker start registry
    
  5. 레지스트리가 다시 실행 중인지 확인합니다.

    docker ps
    

이제 Docker 레지스트리는 자체 서명된 인증서로 HTTPS 를 사용하도록 구성되었으며, Docker 클라이언트는 localhost:5000 에 연결할 때 이 인증서를 신뢰하도록 구성되었습니다.

보안 Docker Registry 테스트

이제 SSL 로 Docker 레지스트리가 실행되고 있으므로, 이미지를 푸시하고 풀하여 테스트해 보겠습니다. 이렇게 하면 모든 것이 올바르게 작동하는지 확인할 수 있습니다.

샘플 이미지로 테스트

  1. 먼저, 테스트에 사용할 샘플 이미지를 풀해 보겠습니다.

    docker pull alpine:latest
    

    Docker 가 Alpine Linux 이미지를 다운로드하는 것을 보여주는 출력을 볼 수 있습니다.

  2. 보안 레지스트리에 대한 이미지를 태그합니다.

    docker tag alpine:latest localhost:5000/alpine:latest
    

    이 명령어는 로컬 레지스트리를 가리키는 새 태그를 생성합니다.

  3. 이미지를 보안 레지스트리에 푸시합니다.

    docker push localhost:5000/alpine:latest
    

    이미지 레이어가 레지스트리에 푸시되는 것을 보여주는 출력을 볼 수 있습니다.

    The push refers to repository [localhost:5000/alpine]
    213ec9aee27d: Pushed
    latest: digest: sha256:69e70a79f2d41ab5d637de98c1e0b055206ba40a8145e7bddb55ccc04e13cf8f size: 528
    
  4. 레지스트리에서 풀하고 있는지 확인하기 위해 로컬 이미지를 제거합니다.

    docker rmi localhost:5000/alpine:latest
    docker rmi alpine:latest
    
  5. 보안 레지스트리에서 이미지를 풀합니다.

    docker pull localhost:5000/alpine:latest
    

    Docker 가 레지스트리에서 이미지를 다운로드하는 것을 보여주는 출력을 볼 수 있습니다.

    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 를 사용하여 레지스트리 내용을 살펴보겠습니다.

  1. 레지스트리의 모든 저장소를 나열합니다.

    curl -X GET https://localhost:5000/v2/_catalog --cacert ~/project/registry-certs/registry.crt
    

    다음과 같은 출력을 볼 수 있습니다.

    { "repositories": ["alpine", "hello-world"] }
    

    이것은 레지스트리에 푸시한 모든 이미지를 보여줍니다.

  2. alpine 저장소의 모든 태그를 나열합니다.

    curl -X GET https://localhost:5000/v2/alpine/tags/list --cacert ~/project/registry-certs/registry.crt
    

    다음과 같은 출력을 볼 수 있습니다.

    { "name": "alpine", "tags": ["latest"] }
    

우리가 달성한 것 이해하기

우리가 한 일을 검토해 보겠습니다.

  1. 자체 서명된 SSL 인증서를 사용하여 HTTPS 로 Docker 레지스트리를 설정했습니다.
  2. 이 인증서를 신뢰하도록 Docker 클라이언트를 구성했습니다.
  3. 보안 레지스트리에 이미지를 성공적으로 푸시하고 풀했습니다.

이 설정은 다음을 제공합니다.

  • 암호화된 통신: Docker 클라이언트와 레지스트리 간에 전송되는 모든 데이터는 암호화됩니다.
  • 인증 기반: SSL 은 인증을 구현하기 위한 첫 번째 단계입니다.
  • Docker 클라이언트 호환성: Docker 클라이언트는 기본적으로 로컬 호스트가 아닌 레지스트리에 대해 HTTPS 를 요구합니다.

이제 이 보안 레지스트리를 개발 및 테스트 요구 사항에 사용할 수 있습니다. 프로덕션 환경의 경우 일반적으로 자체 서명된 인증서 대신 신뢰할 수 있는 인증 기관의 인증서를 사용합니다.

요약

축하합니다! 자체 서명된 SSL 인증서를 사용하여 보안 Docker 레지스트리를 성공적으로 설정했습니다. 다음은 수행한 작업입니다.

  1. 기본 Docker 레지스트리를 설정하고 그 목적과 기능을 이해했습니다.
  2. 레지스트리 보안을 위해 자체 서명된 SSL 인증서를 생성했습니다.
  3. 인증서로 HTTPS 를 사용하도록 Docker 레지스트리를 구성했습니다.
  4. 자체 서명된 인증서를 신뢰하도록 Docker 클라이언트를 구성했습니다.
  5. 이미지를 푸시하고 풀하여 보안 레지스트리를 성공적으로 테스트했습니다.

이러한 기술을 통해 개발 및 테스트 환경을 위한 보안 개인 레지스트리를 만들 수 있습니다. 개인 레지스트리는 Docker 이미지가 저장되는 위치와 액세스할 수 있는 사용자를 제어할 수 있도록 하며, SSL 암호화는 전송 중에 데이터가 안전하게 유지되도록 보장합니다.

프로덕션 환경의 경우 일반적으로 신뢰할 수 있는 인증 기관의 인증서를 사용하지만, 구성 프로세스는 이 랩에서 배운 것과 유사합니다.

이제 컨테이너화된 애플리케이션의 보안을 강화하여 자체 프로젝트 및 개발 워크플로우에서 보안 Docker 레지스트리를 자신 있게 구현할 수 있습니다.