Secure Docker registry

Posted on Dec 30, 2020

This article outlines the steps taken to provision a Docker registry on Debian with TLS enabled and basic HTTP authentication.

Nothing in this article is new, but just combines several sources of information for future reference.

Pre-requisites

Choose a location for configuration

mkdir /etc/registry && cd $_

Create CA and certificates

mkdir certs
pushd certs
certstrap init --common-name "CertAuth"
certstrap request-cert --common-name $HOST -ip $IP --domain $HOST
certstrap sign $HOST --CA CertAuth
popd

NOTE: either populate the $HOST and $IP environment vars with required details or replace them with the literal values.

Generate htpasswd file

mkdir auth
htpasswd -Bbn <username> <password> > auth/htpasswd

NOTE: choose username / password for login

Create docker-compose file

version: '3.8'

services:
  registry:
    restart: always
    image: registry:2
    ports:
      - 5000:5000
    environment:
      REGISTRY_HTTP_TLS_CERTIFICATE: /certs/out/<domain name>.crt
      REGISTRY_HTTP_TLS_KEY: /certs/out/<domain name>.key
      REGISTRY_AUTH: htpasswd
      REGISTRY_AUTH_HTPASSWD_PATH: /auth/htpasswd
      REGISTRY_AUTH_HTPASSWD_REALM: Registry Realm
    volumes:
      - ./data:/var/lib/registry
      - ./certs:/certs
      - ./auth:/auth

NOTE: replace <domain name> with the $HOST value used when creating the CSR

Start the service

docker-compose up -d

Running as a systemd unit

Create the following systemd unit file (/etc/systemd/system/docker-registry.service)

[Unit]
Description=docker registry service
After=docker.service

[Service]
WorkingDirectory=/etc/registry
ExecStartPre=-/usr/local/bin/docker-compose rm -vfs
ExecStart=/usr/local/bin/docker-compose up
ExecStop=-/usr/local/bin/docker-compose down -t 0
Restart=always
RestartSec=10s

[Install]
WantedBy=multi-user.target

Finally reload the systemd config, start the service, and then enable it on boot:

systemctl daemon-reload
systemctl start docker-registry
systemctl enable docker-registry

Configure docker4mac

mkdir -p ~/.docker/certs.d/<domain>[\:<port>]
# e.g.
# mkdir -p ~/.docker/certs.d/foo.bar
# mkdir -p ~/.docker/certs.d/foo.bar\:5000

Use will need the out/CertAuth.crt file generated when bootstrapping certstrap. Copy the contents to the newly created directory into a file called ca.crt (e.g. ~/.docker/certs.d/foo.bar/ca.crt)

Once the ca.crt file has been added, restart docker4mac.

If your registry hostname isn’t configured in DNS, add an entry to /etc/hosts to map the hostname to IP.

Login to the new new registry, i.e.

docker login <host>[:<port>]

Use the <username> and <password> that was input to the htpasswd utility.

You can now push/pull to the registry, e.g.

# Pull from docker hub
docker pull alpine
# re-tag to push to new registry
docker tag alpine foo.bar:5000/alpine
docker push foo.bar:5000/alpine