Seguridad de la Conectividad Remota del Daemon de Docker

Anteriormente en este capítulo, vimos cómo configurar el daemon de Docker para aceptar conexiones remotas. Sin embargo, con el enfoque que seguimos, cualquier persona puede conectarse a nuestro daemon de Docker. Podemos asegurar nuestra conexión con Seguridad de Capa de Transporte (http://en.wikipedia.org/wiki/Transport_Layer_Security).

Podemos configurar TLS utilizando la Autoridad de Certificación (CA) existente o creando la nuestra. Para simplificar, crearemos la nuestra, lo que no se recomienda para producción. En este ejemplo, asumimos que nuestro host que ejecuta el daemon de Docker es dockerhost.example.com.

Preparación

Asegúrate de tener la biblioteca openssl instalada.

Cómo hacerlo…

  1. Crea un directorio en tu host para poner nuestra CA y otros archivos relacionados:
$ mkdir -p /etc/docker/keys
$ cd /etc/docker/keys
  1. Crea la clave privada y pública de la CA:
$ openssl genrsa -aes256 -out ca-key.pem 4096 
$ openssl req -new -x509 -days 365 -key ca-key.pem \
                  -sha256 -out ca.pem

Diagrama

  1. Ahora, creemos la clave del servidor y la solicitud de firma de certificado. Asegúrate de que el nombre común coincida con el nombre de host del sistema del daemon de Docker. En nuestro caso, es dockerhost.example.com:
$ openssl genrsa -out server-key.pem 4096 
$ openssl req -subj "/CN=dockerhost.example.com" \
                  -new -key server-key.pem -out server.csr

Diagrama

  1. Los clientes pueden conectarse al daemon de Docker utilizando el nombre de DNS o la dirección IP del host de Docker. Por lo tanto, el nombre de DNS y la dirección IP deben estar incluidos en el certificado como una extensión. Además, agregue los atributos de uso extendido de la clave del daemon de Docker para que se utilicen solo para autenticación de servidor. Ambas piezas de información se capturan en el archivo extfile.cnf, como se muestra aquí:

Diagrama

Aquí, 192.168.33.101 y 10.0.2.15 son las direcciones IP de dos interfaces de red, y 127.0.0.1 es la dirección de bucle invertido.

  1. Continúa para generar la clave:
$ openssl x509 -req -days 365 -sha256 -in server.csr \
                    -CA ca.pem -CAkey ca-key.pem -CAcreateserial \
                   -out server-cert.pem -extfile extfile.cnf

Diagrama

  1. Para la autenticación del cliente, crea una clave del cliente y una solicitud de firma de certificado:
$ openssl genrsa -out key.pem 4096 
$ openssl req -subj '/CN=client' -new -key key.pem \
                  -out client.csr

Diagrama

  1. Para hacer que la clave sea adecuada para la autenticación del cliente, crea un archivo de configuración de extensión y firma la clave pública:
$ echo extendedKeyUsage = clientAuth > client-extfile.cnf 
$ openssl x509 -req -days 365 -sha256 -in client.csr \
                   -CA ca.pem -CAkey ca-key.pem -CAcreateserial \
                   -out cert.pem -extfile client-extfile.cnf

Diagrama

  1. Después de generar cert.pem y server-cert.pem, podemos eliminar con seguridad ambas solicitudes de firma de certificado:
$ rm -rf client.csr server.csr
  1. Para proteger las claves de daños accidentales, elimina los permisos de escritura de estos archivos de clave: ca-key.pem, key.pem y server-key.pem. Además, limita el permiso de lectura de estos archivos solo para el root:
$ chmod 0400 ca-key.pem key.pem server-key.pem

Los archivos de certificado ca.pem, server-cert.pem y cert.pem necesitan un acceso de lectura más amplio, así que da acceso de lectura para todos estos archivos de certificado, como se muestra aquí:

$ chmod 0444 ca.pem server-cert.pem cert.pem
  1. Detén el daemon si está ejecutándose en dockerhost.example.com utilizando el comando systemctl stop docker. Luego, inicia el daemon de Docker manualmente desde /etc/docker/keys:
$ dockerd --tlsverify \
              --tlscacert=ca.pem \
              --tlscert=server-cert.pem \
              --tlskey=server-key.pem \
              -H=0.0.0.0:2376
  1. Desde otra terminal, ve a /etc/docker/keys. Ejecuta el siguiente comando para conectarte al daemon de Docker:
$ cd /etc/docker/keys
$ docker --tlsverify \
           --tlscacert=ca.pem \
           --tlscert=cert.pem \
           --tlskey=key.pem \
           -H=127.0.0.1:2376 version

El cliente de Docker puede conectarse sin problemas al daemon de Docker a través de TLS y obtener la versión del servidor.

Cómo funciona…

Una vez que configuramos el daemon de Docker para utilizar TLS como transporte, solo acepta conexiones TLS seguras para el cliente y cumple con la solicitud del cliente.

Hay más…

En esta receta, utilizamos las opciones --tlscacert, --tlscert y --tlskey del comando docker para conectarnos al daemon de Docker habilitado para TLS. Invocar el comando docker utilizando una lista tan larga de opciones es bastante incómodo. Sin embargo, podemos evitar este problema haciendo lo siguiente:

  1. Copia los archivos ca.pem, cert.pem y key.pem al directorio $HOME/.docker del usuario.

  2. Modifica la propiedad del archivo para que pertenezca al usuario utilizando el comando chown.

  3. Establece DOCKER_HOST en la dirección del daemon, como se muestra aquí:

$ export DOCKER_HOST=tcp://127.0.0.1:2376
  1. Establece DOCKER_TLS_VERIFY en 1, como se muestra aquí:
$ export DOCKER_TLS_VERIFY=1

Ahora, puedes ejecutar el comando docker como si estuvieras ejecutándolo en el socket de Unix.

En esta receta, lanzamos el daemon de Docker desde la línea de comandos, lo que es bueno para pruebas. Sin embargo, el daemon de Docker debe estar configurado para iniciarse con Systemd. Puedes lograr esto editando el archivo de unidad del servicio de Docker, como se describe en la receta Configuración del daemon de Docker para conectividad remota, con la siguiente excepción notada para ExecStart:

ExecStart=/usr/bin/dockerd \
             --tlsverify \
             --tlscacert=/etc/docker/keys/ca.pem \
             --tlscert=/etc/docker/keys/server-cert.pem \
             --tlskey=/etc/docker/keys/server-key.pem \
             -H=0.0.0.0:2376

Aquí, hemos separado el comando en varias líneas para mejorar la legibilidad. Sin embargo, debe estar en una sola línea en el archivo de unidad.

  • El comando curl también puede conectarse de forma segura al daemon de Docker habilitado para TLS, como se muestra aquí:
$ curl --cacert ${HOME}/.docker/ca.pem \
    --cert ${HOME}/.docker/cert.pem \
    --key ${HOME}/.docker/key.pem \
    https://127.0.0.1:2376/version

Ver también