개인적으로 공부를 하면서 여타 블로그 들에 있는 원격 사설 레지스트리 보안 인증서 설정보다 조금 다르지만 좋은 방법이 있기에 해당 방식으로 진행한다.

도입

사설 레지스트리(Private Registry)에 이미지를 push, pull 할때 포트포워딩 해준 5000번 포트를 이미지 태그에 사용한다. --insecure-registry 옵션을 도커 데몬에 설정하면 아무런 제약없이 원격 설정을 할 수 있지만 그 만큼 보안에 취약하기에 SSL 인증서를 사용한 보안 구성을 구축해본다. 참고로 OS는 Ubuntu 기준이다.

  • 수 시간동안 다른 블로그를 보고 따라해봐도 뭔가 한번에 구현되지 못하고 에러가 있었다. 많은 삽질 경험 끝에 성공한 내용을 정리한다.

기능

구성

  • 사설 원격 레지스트리 컨테이너가 돌고 있는 서버 1PC
    • 도커엔진 사용
    • 이미지 저장소
  • 사설 원격 레지스트리에서 이미지를 pull해 와서 사용하는 도커 클라이언트 여러 PC(1대 이상)
    • 이미지를 불러와서 도커 컨테이너 사용

구현 가능한 기능

  1. 레지스트리 서버에서 도커 이미지 pull & push
  2. 다른 원격 도커 클라이언트에서 도커 이미지 pull & push
  3. SSL 인증서로 허용된 PC들만 보안 연결 구성
  4. curl을 통해 레지스트리 서버 및 도커 클라이언트 PC에서 이미지 리스트 보기

SSL 인증서 생성

  • 위치: 사설 레지스트리 서버용 PC

    준비

    서버의 home 경로에 레지스트리를 위한 디렉토리를 만든다.

    $ mkdir -p ~/docker-registry/certs
    $ mkdir -p ~/docker-registry/volume
    $ cd ~/docker-registry/certs
    
  • certs 폴더에는 ssl 인증서들이 위치한다.
  • volume 디렉토리는 레지스트리 컨테이너 실행 시 임시용 데이터 볼륨으로 붙일 예정이다.

Key 생성

아래의 명령어를 실행하여 키를 생성한다.

# openssl genrsa -des3 -out {키 파일명} 2048

$ openssl genrsa -des3 -out server.key 2048

server.key의 비밀번호는 임의로 설정한다. 셋팅 과정에만 사용하고 한번 제대로 셋팅하면 크게 필요하진 않다. 결과가 다음과 같이 출력된다.

Generating RSA private key, 2048 bit long modulus (2 primes)
..................................................+++++
.........................................+++++
e is 65537 (0x010001)
Enter pass phrase for server.key:
Verifying - Enter pass phrase for server.key:

CSR 파일 생성

키 파일을 기반으로 .csr 파일을 생성해준다. 아래 커맨드 입력 시 키를 만들 때 입력하였던 비밀번호를 입력하면 몇 가지 질문들이 나오는데 대부분 공백으로 넘겨도 되나 Common Name은 레지스트리 서버 IP 혹은 도메인을 적어줘야한다.

# openssl req -new -key {키 파일명} -out {csr 파일명}

$ openssl req -new -key server.key -out server.csr

서버 ip는 앞 포스팅에서 적어준 172.16.10.7 이라고 가정한다. Common Name을 제외하곤 전부 엔터를 눌러 넘어갔다.

Enter pass phrase for server.key:
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [AU]:
State or Province Name (full name) [Some-State]:
Locality Name (eg, city) []:
Organization Name (eg, company) [Internet Widgits Pty Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (e.g. server FQDN or YOUR name) []:172.16.10.7
Email Address []:

Please enter the following 'extra' attributes
to be sent with your certificate request
A challenge password []:
An optional company name []:

Key 파일 암호 해제

키를 만들어 주었을 때 입력한 암호는 더 이상 사용하지 않는다.

# openssl req -in {키 파일명} -out {키 파일명}

$ openssl rsa -in server.key -out.server.key

결과는 다음과 같이 출력된다.

Enter pass phrase for server.key:
writing RSA key

Config 파일 생성

# echo subjectAltName=IP:{레지스트리IP},IP:127.0.0.1 > extfile.cnf

$ echo subjectAltName=IP:172.16.10.7,IP:127.0.0.1 > extfile.cnf

자체서명인증서(crt) 생성

# openssl x509 -req -days {기간} -signkey {키 파일명} -in {csr 파일명} -out {crt 파일명} -extfile extfile.cnf

$ openssl x509 -req -days 10000 -signkey server.key -in server.csr -out server.crt -extfile extfile.cnf

결과는 다음과 같이 출력된다

Signature ok
subject=C = AU, ST = Some-State, O = Internet Widgits Pty Ltd, CN = 172.16.10.7
Getting Private key

SSL 인증서 생성(Registry Server)

  • 위치: 사설 레지스트리 서버용 PC

원격 도커 클라이언트 PC에서 어서 push, pull이 되는 것을 확인하고 싶을 수 있지만 일단 레지스트리 컨테이너가 도는 로컬에서부터 확인을 하는 것이 좋다.

기존 레지스트리 컨테이너 종료

혹시나 기존에 돌아가고 있는 레지스트리 컨테이너가 있다면 종료한다. 컨테이너 이름은 my_registry로 가정한다. -v 옵션은 --volumes와 같다.

$ docker stop my_registry
$ docker rm -v my_registry

레지스트리 서버 보안 인증서 적용(선택)

SSL 인증서(.crt)를 인증서 디렉토리로 옮겨서 적용하면 레지스트리 컨테이너가 적용되어 있는 서버에서는 curl 시에 조금 옵션이 다르게 나온다. 결과는 추후 확인할 수 있다.

$ sudo cp server.crt /usr/local/share/ca-certificates/
$ sudo update-ca-certificates

새로운 레지스트리 컨테이너 실행

인증서를 추가한만큼 몇가지를 적용하여 레지스트리를 실행한다. certs 디렉토리를 컨테이너의 /cert 디렉토리로 볼륨 설정해준다. /data 볼륨은 딱히 필요하지 않다면 안해도 무방하다.

docker run -d -p 5000:5000 --restart=always --name sonregistry \
-v /home/smarteye/docker-registry/volume/:/data \
-v /home/smarteye/docker-registry/certs/:/certs \
-e REGISTRY_HTTP_ADDR=0.0.0.0:5000 \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/server.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/server.key \
registry:2.6

push 후 이미지 리스트 확인

임시로 우분투 이미지를 이름 변경하여 push 후 레지스트리 API를 이용해 레지스트리에 등록 된 이미지 리스트를 확인한다.

$ docker tag ubuntu:18.04 172.16.10.7:5000/ubuntu:18.04
$ docker push 172.16.10.7:5000/ubuntu:18.04

CURL로 확인하기

아래 커맨드로 레지스트리 컨테이너에 등록된 이미지를 확인할 수 있다.

$ curl https://172.16.10.7:5000/v2/_catalog

앞서 해당과정(보안인증서 적용)을 하지 않았다면 해당 명령어를 실행 시 아래와 같은 오류가 출력된다.

curl: (60) SSL certificate problem: self signed certificate
More details here: https://curl.haxx.se/docs/sslcerts.html

curl failed to verify the legitimacy of the server and therefore could not
establish a secure connection to it. To learn more about this situation and
how to fix it, please visit the web page mentioned above.

이 때에는 https 보안을 사용하지 않는 --insecure 옵션 혹은 -k 옵션을 적용해서 확인할 수 있다.

$ curl https://172.16.10.7:5000/v2/_catalog -k

결과는 다음과 같이 정상적으로 나온다.

{"repositories":["ubuntu"]}

클라이언트 적용

  • 위치: 도커 클라이언트 PC

도커 엔진을 사용하는 다른 PC들에서 SSL 인증서를 적용하여 사설 원격 레지스트리에 존재하는 이미지들을 pull 할 수 있게 한다.

일단은 레지스트리 컨테이너 서버에서 만들어준 ~/docker-registry/certs 디렉토리를 홈 경로에 가져온다.

# scp {레지스트리 서버 호스트}@{서버 ip}:~/docker-registry/certs ~/

$ scp -r user@172.16.10.7:~/docker-registry/certs ~/

SSL 인증서 적용 (필수)

레지스트리 서버의 SSL 인증서 적용과는 비슷하면서도 조금 다른 부분이 있으니 주의하자.

인증서 복사

서버 쪽에서는 /usr/local/- 경로를 사용했지만 클라이언트는 차이가 있다.

$ cd ~/certs
$ sudo cp server.crt /usr/share/ca-certificates/

추가로 인증서 config 파일을 수정해준다. 해당 파일 제일 아래에 server.crt 내용을 추가한다.

$ echo server.crt >> /etc/ca-certificates.conf

위의 명령어가 권한 때문에 실행되지 않는다면 sudo su 명령어를 통해 루트 유저 모드에서 실행하면 된다. 그리고는 추가 된 인증서를 적용해준다. 단, 먼저 도커 서비스를 중지한 뒤 적용 후 다시 시작한다.

$ sudo service docker stop
$ sudo update-ca-certificates
$ sudo service docker start

해당 과정을 진행하지 않는다면 insecrue-registry로 설정하지 않은 이상 레지스트리 컨테이너 서버에서 이미지를 가져올 수 없다.

확인하기

pull 확인

사설 레지스트리에 아까 등록한 이미지를 가져와본다.

$ docker pull 172.16.10.7:5000/ubuntu:18.04

결과는 아래와 같이 정상적으로 출력된다.

18.04: Pulling from ubuntu
feac53061382: Pull complete 
Digest: sha256:07782...(중략)...c5dbc5386ed41a4f
Status: Downloaded newer image for 172.16.10.7:5000/ubuntu:18.04
172.16.10.7:5000/ubuntu:18.04

CURL 확인

클라이언트는 SSL 인증서를 적용했는데 본인만 겪는 문제 인지는 확실하게 파악되지 않지만 -k 옵션을 적용해야만 리스트를 받아올 수 있었다.

$ curl https://172.16.10.7:5000/v2/_catalog -k

결과는 다음과 같다.

{"repositories":["ubuntu"]}

만약 -k옵션을 주지 않으면 아까의 에러가 발생하는 것을 확인할 수 있다


이렇게 해서 도커 사설 레지스트리 서버와 클라이언트 PC들의 도커 이미지 push, pull, curl을 이용한 이미지 리스트 조회 등의 기능이 가능한 원격 사설 레지스트리를 SSL 인증서를 통한 보안이 적용된 상태까지 만들어 보았다.

에러 해결

rnd 파일에러

Can't load /home/dongle/.rnd into RNG
140104752157120:error:2406F079:random number generator:RAND_load_file:Cannot open file:../crypto/rand/randfile.c:88:Filename=/home/dongle/.rnd

위와 비슷한(경로는 다르지만) .rnd 파일에 대한 에러가 난다면 openssl 설정을 수정하여 해결할 수 있다. RANDFILE 항목을 주석처리하면 된다.

sudo vi /etc/ssl/openssl.cnf

...(주석처리)
#RANDFILE               = $ENV::HOME/.rnd
...

Leave a comment