kenichi

@kenichishibata

Create a private local docker registry

On your machines inside a VPN, there are use-cases where a private docker registry is handy especially if you want to have a customized image built for your stack.

The caveat is that docker automatically assumes that all your connections are encrypted via https . And that means you need to have domain to encrypt your traffic on https protocol. This guide will help you setup a registry without having a DNS and a valid SSL/TLS Certificate:

Question:

Ahm.. Ken there is already a Tutorial on docker official docs about creating a private registry

Answer:

The docker official docs are a good enough starting point when you want to learn the basics and the theory. However you will need to dig around if you want to make it registry work without a proper SSL Certificate and DNS.

Also my stuff are easy to follow and copy paste-able

Approach: Self Signed Certificate

Since our machines are already inside VPN using a self signed certificate is good enough method for securing your Docker Registry.

1. On your Host Machine and Client Machine install Docker Engine

sudo apt-get install \
apt-transport-https \
ca-certificates \
curl \
software-properties-common
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
sudo apt-key fingerprint 0EBFCD88
sudo apt-get update
sudo apt-get install docker-ce 

2. Get a self signed certificate for your docker registry

# Important
# Add your IP in subjectAltName in the openssl.cnf before generating # certs
sudo vi /etc/ssl/openssl.cnf
# Add this line
#subjectAltName=IP:192.168.0.2
mkdir -p /certs
openssl req \
-newkey rsa:4096 -nodes -sha256 -keyout certs/domain.key \
-x509 -days 365 -out certs/domain.crt
# Press enter to everything except CN add your ip address there
Generating a 4096 bit RSA private key
...............................................................................................................................................................................................................................++
............................................................++
writing new private key to 'certs/domain.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) []:192.168.0.2
Email Address []:

What it did is it created two files and in /certs directory. domains.crt and domains.key

3. Create your docker registry

sudo docker run -d -p 5000:5000 --restart=always --name registry \
-v /certs:/certs \
-e REGISTRY_HTTP_TLS_CERTIFICATE=/certs/domain.crt \
-e REGISTRY_HTTP_TLS_KEY=/certs/domain.key \
registry:2

What this does is it. First downloads the registry:2 image. Second it mounts the /certs directory that we just created in host machine to a /certs directory on the docker machine. Also this command adds 2 environment variables REGISTRY_HTTP_TLS_CERTIFICATE and REGISTRY_HTTP_TLS_KEY to the docker machine to use the newly created certificates. Finally it binds the application running on 5000 in docker machine and exposes it to 5000 in host machine. --restart=always means that this docker machine too will restart if the docker daemon restarts

To check if it is running properly:

sudo docker ps
# Should display
CONTAINER ID        IMAGE               COMMAND  ...                4b6bcbadf307        registry:2          entrypoint...
# now get the container id
sudo docker logs <container-id>
# if you didn't see any obvious error messages then you are good to go

4. Test the docker registry

Get a sample image, tag then push to the registry.

# get busybox image from public dockerhub
sudo docker pull busybox 
# check the busybox image id
sudo docker images 
# tag the image for pushing
sudo docker tag <image-id> 192.168.0.2:5000/busybox
# test pushing the image
sudo docker push 192.168.0.2:5000/busybox
#! ERROR
The push refers to a repository [192.168.0.2:5000/busybox]
Get https://192.168.0.2:5000/v1/_ping: x509: certificate signed by unknown authority

What happened?

Since our certificate is self signed the connection encryption is not trusted by docker.

How do we make docker engine trust our x509 certicate?

Go back to /certs/domain.crt and copy it to docker’s trusted certificate

mkdir -p /etc/docker/certs.d/192.168.0.2:5000
cd /certs
cp /certs/domain /etc/docker/certs.d/192.168.0.2:5000/
cd /etc/docker/certs.d/192.168.0.2:5000/
mv domains.crt ca.crt
#reload docker daemon to use the certificate
sudo service docker reload

Essentially this forces docker to verify our self signed certificate even though it is not signed by a known authority.

It doesn’t work

However if you saw error message about IP Sans. unable to ping registry endpoint…x509: cannot validate certificate for … because it doesn’t contain any IP SANs . It means you skipped adding subjectAltName on openssl.cnf on Step two. So you have to follow back step 2 again

Working now!

If it worked you should be able to see message similar to below

4ac76077f2c7: Pushed
latest: digest: sha256:c79345819a6882c31b41bc771d9a94fc52872fa651b36771fbe0c8461d7ee558 size: 527

Congrats! You now have a private docker repository :)

Please feel free to leave comments and feedback below

More by kenichi

Topics of interest

More Related Stories