Proteger las contraseñas en Docker es un aspecto fundamental para preservar la seguridad de una aplicación en contenedores. Los servicios y bases de datos externos a menudo requieren autenticación de contraseña. La falta de una protección adecuada podría comprometer la seguridad de los datos.

En este tutorial, explicaremos diferentes formas de proteger las contraseñas en Docker.

La importancia de guardar secretos

Las contraseñas son una forma común de autenticar servicios o bases de datos externos. Los servicios en la nube, las bases de datos y otros servicios de terceros requieren autenticación constantemente. Sin embargo, si estas contraseñas no están debidamente protegidas, pueden verse comprometidas por usuarios no autorizados. En consecuencia, los datos confidenciales pueden estar expuestos a personas no autorizadas.

Los entornos en contenedores suelen durar poco tiempo y son efímeros, lo que hace que proteger las contraseñas sea aún más crítico.

Usando variables de entorno

La forma más fácil de pasar contraseñas a un contenedor es usar variables ENV. Las variables de entorno se pueden configurar en tiempo de ejecución usando el indicador -e cuando se ejecuta un contenedor. Para ilustrar, podemos usar el siguiente comando para pasar la contraseña como una variable ENV:

Por ejemplo:

$ docker run --name mysql -p 3306:3306 -e MYSQL_ROOT_PASSWORD=mi-password-secreto -d mysql

En esta imagen mysql, la contraseña se obtiene de la variable de entorno MYSQL_ROOT_PASSWORD. Para establecer la contraseña de la cuenta raíz, pasamos la variable env al comando de ejecución de la ventana acoplable.

Las variables de entorno no se almacenan en la imagen en sí, por lo que no se pueden confirmar accidentalmente en un repositorio de código fuente. No necesitamos modificar la imagen para cambiar el ENV. Las variables de entorno no son confiables en entornos de recursos compartidos, donde varios contenedores comparten un host y un entorno. Cualquier proceso que se ejecute dentro del contenedor puede acceder a él. Por lo tanto, no deberíamos usarlo para el almacenamiento de datos confidenciales.

Uso de un sistema de gestión de secretos

Podemos gestionar y almacenar contraseñas de forma segura mediante un sistema de gestión de secretos como Vault. Estos sistemas suelen proporcionar una API segura para almacenar y recuperar secretos. Además, podemos integrarlo con nuestro entorno en contenedores para proporcionar estos secretos al contenedor en tiempo de ejecución.

Usar el vault

Podemos gestionar y almacenar contraseñas de forma segura mediante un sistema de gestión de secretos como Vault. Estos sistemas suelen proporcionar una API segura para almacenar y recuperar secretos. Además, podemos integrarlo con nuestro entorno en contenedores para proporcionar estos secretos al contenedor en tiempo de ejecución.

$ docker run -itd --cap-add=IPC_LOCK -e 'VAULT_DEV_ROOT_TOKEN_ID=myroot' -e 'VAULT_DEV_LISTEN_ADDRESS=0.0.0.0:8200'
  -p 8200:8200 --name vault vault

En el comando anterior, VAULT_DEV_ROOT_TOKEN_ID se establece en myroot y VAULT_DEV_LISTEN_ADDRESS en 0.0.0.0:8200, por lo que todas las interfaces de red disponibles escucharán en el puerto 8200. La opción -p del comando docker run expone el puerto 8200 del servidor del vault externamente en el puerto 8200 del host. Veamos cómo crear una contraseña secreta en el bóveda:

$ export VAULT_ADDR='http://127.0.0.1:8200'

El comando anterior le dice a la herramienta de línea de comandos de la bóveda que se comunique con el servidor que se ejecuta en 127.0.0.1 en el puerto 8200. Iniciemos sesión en el servidor de la bóveda y creemos una contraseña secreta:

$ vault login myroot
$ vault kv put secret/test password=mysecretpasswordtest

El inicio de sesión de Vault intenta iniciar sesión en el servidor con el token myroot. Este token maneja la autenticación y autorización para los usuarios. El comando vault kv put crea el secreto en la ruta secret/test con un par clave-valor. Esto nos permite almacenar información confidencial en el servidor y recuperarla más tarde.

Recuperando los secretos

Ejecutemos otro contenedor que recupere la contraseña del servidor de bóveda anterior:

$ docker run --rm --network=host -e 'VAULT_ADDR=http://127.0.0.1:8200' -e 'VAULT_TOKEN=myroot'
  vault sh -c 'apk add --update curl jq && vault login -method=token token=${VAULT_TOKEN}
  && PASSWORD=$(vault kv get -field=password secret/test) && echo ${PASSWORD}'

Al ejecutar el comando anterior, se crea un nuevo contenedor con la imagen del almacén y se establecen las variables de entorno VAULT_ADDR y VAULT_TOKEN. Además, se conecta al servidor vault en localhost que se ejecuta en el puerto 8200. Luego, se autentica en el servidor vault, obtiene el valor de la clave de contraseña de secret/test y luego lo imprime. Las partes autorizadas solo pueden acceder a los secretos que brindan una capa adicional de seguridad. Pero los sistemas de gestión de secretos son complejos de configurar y gestionar. Además, añade un coste a nuestra aplicación.

Uso de los secretos de Docker

Docker secrets es una característica del modo Docker Swarm que nos permite gestionar de forma segura información confidencial, como contraseñas, en nuestro entorno Docker. Con los secretos de Docker, podemos mantener los archivos de configuración, la información confidencial y los argumentos de la línea de comandos fuera de las imágenes. Esto en general reduce el riesgo de exposición.

Crear secretos de Docker

Primero, necesitamos inicializar el enjambre de Docker para usar los secretos de Docker:

$ docker swarm init

Como siguiente paso, usaremos echo para canalizar la contraseña en docker secret create:

$ echo "testpassword" | docker secret create mysql_external_secret -

El comando anterior crea un secreto único llamado “mysql_external_secret” con el valor “testpassword”. Con un docker-compose.yml, podemos instalar un servidor MySQL en un servicio de Docker con la variable de entorno MYSQL_ROOT_PASSWORD_FILE pasada a través de los secretos de Docker:

version: '3.1'
services:
  mysql:
    image: mysql
    secrets:                    # scretos para mysql
     - mysql_external_secret 
    environment:
      - MYSQL_ROOT_PASSWORD_FILE=/run/secrets/mysql_external_secret
secrets:                        # secretos generales
  mysql_external_secret:
    external: true

El bloque de secretos indica que mysql_external_secret es un secreto externo que ya está presente en nuestra máquina host.

Los secretos de Docker crean los secretos en la máquina host y los pasan al contenedor en tiempo de ejecución. Este mecanismo eventualmente reduce el riesgo de exposición. Para ejecutar el servicio, hacemos un deploy:

$ docker stack deploy --compose-file=docker-compose.yml mysql_secret_test

El comando anterior implementa el stack definido en el archivo docker-compose.yml y crea el servicio mysql_secret_test. Con este método, podemos administrar de forma segura información confidencial, como contraseñas, en nuestro entorno Docker.

Categorized in: