Implementación de un Registro Privado de Docker con Autenticación en CentOS 7

Docker Hub es una plataforma excelente para gestionar imágenes públicas, pero en entornos empresariales es fundamental contar con un registro privado para alojar artefactos propios. Docker Registry v2, desarrlolado en Go, reemplazó a la antigua versión en Python, mejorando drásticamente el rendimiento de las operaciones de push y pull, además de optimizar el almacenamiento y la seguridad.

Las ventajas de utilizar un registro interno incluyen:

  • Reducción del consumo de ancho de banda, evitando descargas repetitivas desde internet.
  • Centralización y control de acceso a las imágenes corporativas.

Arquitectura del Entorno

Para esta implementación, utilizaremos tres nodos con CentOS 7 y Docker configurado:

  • Nodo Registry (10.0.0.50): Alojará el servicio de registro privado.
  • Nodo Cliente A (10.0.0.51): Simulará un entorno de desarrollo con acceso básico.
  • Nodo Cliente B (10.0.0.52): Simulará un entorno de producción con acceso autenticado.

Despliegue Inicial del Registro Privado

En el Nodo Registry, instalamos y arrancamos el servicio de Docker:

[root@nodo-registry ~]# yum install docker -y
[root@nodo-registry ~]# systemctl enable --now docker

Descargamos la imagen oficial de Registry en su versión 2:

[root@nodo-registry ~]# docker pull registry:2

Iniciamos el contenedor del registro, mapeando el puerto 5000 y montando un volumen para la persistencia de datos en /data/registry-storage:

[root@nodo-registry ~]# docker run -d \
  --name private-registry \
  -p 5000:5000 \
  --restart=always \
  -v /data/registry-storage:/var/lib/registry \
  registry:2

Para probar el funcionamiento, descargamos una imagen ligera, le asignamos una etiqueta apuntando a nuestro registro local y la subimos:

[root@nodo-registry ~]# docker pull nginx:alpine
[root@nodo-registry ~]# docker tag nginx:alpine 10.0.0.50:5000/nginx:alpine
[root@nodo-registry ~]# docker push 10.0.0.50:5000/nginx:alpine

Configuración de Clientes para HTTP Inseguro

Docker exige HTTPS por defecto para comunicarse con los registros. Como nuestro registro local usa HTTP, los clientes rechazarán la conexión. Para solucionarlo, debemos configurar el demonio de Docker en los nodos clientes para que confíen en nuestro registro.

En el Nodo Cliente A, creamos o editamos el archivo /etc/docker/daemon.json:

{
  "insecure-registries": ["10.0.0.50:5000"]
}

Recargamos la configuración y reiniciamos el servicio:

[root@nodo-cliente-a ~]# systemctl daemon-reload
[root@nodo-cliente-a ~]# systemctl restart docker

Ahora podemos extraer la imagen desde el registro privado sin errores:

[root@nodo-cliente-a ~]# docker pull 10.0.0.50:5000/nginx:alpine

Implementación de Autenticación Básica

Un registro sin autenticación es un riesgo de seguridad en producción. Procedemos a configurar la autenticación básica mediante htpasswd en el Nodo Registry.

Creamos el directorio para las credenciales y generamos el archivo de contraseñas para el usuario deployer:

[root@nodo-registry ~]# mkdir -p /data/registry-auth
[root@nodo-registry ~]# docker run --rm --entrypoint htpasswd registry:2 -Bbn deployer 'S3cur3P@ss!' > /data/registry-auth/htpasswd

Adicionalmente, creamos un archivo de configuración para habilitar la eliminación de imágenes y ajustar parámetros de almcaenamiento en /data/registry-config/config.yml:

version: 0.1
log:
  fields:
    service: registry
storage:
  delete:
    enabled: true
  cache:
    blobdescriptor: inmemory
  filesystem:
    rootdirectory: /var/lib/registry
http:
  addr: :5000
  headers:
    X-Content-Type-Options: [nosniff]
health:
  storagedriver:
    enabled: true
    interval: 10s
    threshold: 3

Detenemos y eliminamos el contenedor anterior, y lanzamos uno nuevo inyectando las variables de entorno para la autenticación y montando los nuevos volúmenes:

[root@nodo-registry ~]# docker stop private-registry && docker rm private-registry
[root@nodo-registry ~]# docker run -d \
  --name secure-registry \
  -p 5000:5000 \
  --restart=always \
  -v /data/registry-config:/etc/docker/registry \
  -v /data/registry-auth:/auth \
  -v /data/registry-storage:/var/lib/registry \
  -e "REGISTRY_AUTH=htpasswd" \
  -e "REGISTRY_AUTH_HTPASSWD_REALM=Registry Realm" \
  -e "REGISTRY_AUTH_HTPASSWD_PATH=/auth/htpasswd" \
  registry:2

Operaciones en el Cliente Autenticado

En el Nodo Cliente B, repetimos la configuración de daemon.json para permitir HTTP y reiniciamos Docker.

Intentamos subir una imagen sin autenticarnos para verificar que el registro nos bloquea:

[root@nodo-cliente-b ~]# docker tag nginx:alpine 10.0.0.50:5000/nginx:alpine
[root@nodo-cliente-b ~]# docker push 10.0.0.50:5000/nginx:alpine
# Esto devolverá un error de "no basic auth credentials"

Procedemos a iniciar sesión con las credenciales generadas:

[root@nodo-cliente-b ~]# docker login 10.0.0.50:5000
Username: deployer
Password: 
Login Succeeded

Una vez autenticados, la operación de push se completa correctamente:

[root@nodo-cliente-b ~]# docker push 10.0.0.50:5000/nginx:alpine

Finalmente, podemos consultar el catálogo de repositorios disponibles en el registro utilizando curl y pasando las credenciales:

[root@nodo-cliente-b ~]# curl -u deployer:'S3cur3P@ss!' http://10.0.0.50:5000/v2/_catalog
{"repositories":["nginx"]}

Etiquetas: docker-registry centos7 docker-security htpasswd Containerization

Publicado el 7-11 19:26