29 de Marzo, 2004

MySQL y el chroot de Apache

No es un problema, pero cuando se trabaja con una máquina tan vieja como blackshell los servicios tardan mucho en arrancar.

En OpenBSD el sistema va preparado para correr el servidor web Apache en un chroot. ¿Qué es eso de un chroot?

Una vez que se ejecuta el proceso, éste cambia la raiz (root, de ahí chroot change root) en el sistema de archivos para ese proceso a otro lugar. En este caso Apache corre con la raiz en /var/www/, de forma que si hay un problema con ese proceso y un atacante intenta explotarlo, se verá confinado en un sistema de archivos limitado a esa localización y sin poder acceder a los archivos del resto del sistema.

El problema se plantea cuando necesitamos que Apache acceda a algo que queda fuera del entorno chroot. En este caso el socket de MySQL con el que nuestras aplicaciones web en PHP o Perl, por ejemplo, acceden a esta base de datos.

Por supuesto que se puede acceder a MySQL con TCP/IP, pero el rendimiento no es ni mucho menos el mismo (además de que, como hemos visto, blackshell no está para muchos trotes ;)).

Entonces se plantean 2 alternativas para hacerle llegar ese socket a Apache, y ambas consisten en introducir el fichero (sí, es un fichero) dentro del chroot.

Ya vimos cómo arrancar servicios locales en OpenBSD, además con MySQL como ejemplo. Pues solo hay que modificar la parte a incluir en /etc/rc.local de la siguiente manera:

if [ X"${mysql}" != X"NO" -a -x /usr/local/bin/mysqld_safe ]; then

  # arrancamos el servicio
  echo -n " mysqld"; /usr/local/bin/mysqld_safe $mysql --user=_mysql \
> /dev/null &

  # para el chroot de apache

  # esperamos a que se cree el socket de MySQL
  for i in 1 2 3 4 5 6 7 8 9; do
    if [ -S /var/run/mysql/mysql.sock ]; then
      sleep 2
      break
    else
      sleep 1
    fi
  done

  # nos aseguramos que existen los directorios
  # dentro del chroot
  mkdir -p /var/www/var/run/mysql 2> /dev/null

  # En versiones de mysql 4.x es necesario
  chown _mysql:_mysql /var/www/var/run/mysql

  # hacemos un enlace fuerte con el socket
  ln -f /var/run/mysql/mysql.sock /var/www/var/run/mysql/mysql.sock

fi

Este script modificado lo que hace es esperar a que se cree el socket de MySQL (como máximo espera 9 segundos, que en blackshell puede no ser suficiente :D), para luego hacer un enlace fuerte en el correspondiente directorio dentro del chroot de Apache.

Esta es la configuración aconsejable. No obstante, en caso de que MySQL se reinicie (ya sea por acción del administrador o por un fallo del propio gestor de bases de datos), habrá que volver a crear el enlace fuerte.

Ya que OpenBSD 3.3 tuvo un fallo en libpthread que hacía fallar a MySQL y yo, torpe de mi, no daba con el problema, implementé otra solución que no requiere que se cree un enlace fuerte: hacer que MySQL cree el socket dentro del chroot de Apache.

Tan sencillo como activar MySQL en nuestro /etc/rc.conf.local con:

mysql="--socket=/var/www/var/run/mysql/mysql.sock"

De forma que MySQL cree el socket en su sitio (ojo que tenemos que crear el directorio /var/www/var/run/mysql/).

Esto no tiene mayor historia, solo que cuando usemos cualquier herramienta de MySQL habrá que indicarle dónde está el socket, por ejemplo:

$ mysql -u root -p -S /var/www/var/run/mysql/mysql.sock

Y ya tenemos a MySQL accesible por Apache. Si además quisieramos que otro proceso en chroot accediera al servidor de bases de datos, pues el primer método es obligatorio :(, pero bueno... MySQL no da problemas si todo está en condiciones ;).

Actualización: he adecuado el script a la versión 3.8 del sistema.

Anotación por Juan J. Martínez, clasificada en: mysql, apache, chroot.

Los comentarios están cerrados: los comentarios se cierran automáticamente una vez pasados 30 días. Si quieres comentar algo acerca de la anotación, puedes hacerlo por e-mail.

Algunas anotaciones relacionadas: