Roto las credenciales en el momento en que sospecho una brecha. No después de confirmarla. La rotación de credenciales de base de datos en un servidor ISPConfig suena a mantenimiento rutinario. Deja de ser rutinaria el día que encuentras una web shell en un sitio alojado. O un archivo de configuración que no puedes explicar, guardado en una copia de seguridad pública. En ese momento, cada contraseña vinculada a esa base de datos tiene que ser nueva. Verificada. Documentada. No simplemente asumida como correcta.

¿Cuándo deja de ser opcional la rotación de credenciales?
Hay unos pocos escenarios que se repiten lo suficiente como para mantener siempre listo un plan de rotación. Prefiero no improvisarlo bajo presión.
Un plugin o CMS de un sitio alojado se ve comprometido. Escribí sobre un caso real en este tipo de servidor en PHP2Shell: cómo protejí los servidores a la espera del parche. Era una vulnerabilidad de PHP que permitía a un atacante instalar una web shell antes de que existiera el parche. Una vez que una web shell se ejecuta bajo un usuario de hosting, a menudo puede leer el propio config.inc.php de ese sitio. En un servidor ISPConfig compartido, ese archivo está junto a las credenciales de la propia base de datos del panel de control. No solo la credencial que el atacante realmente buscaba.
Un archivo de configuración termina donde no debería. Un archivo de copia de seguridad olvidado en una carpeta pública. Un repositorio subido con un archivo suelto que no debía estar ahí. Un log más legible de lo que nadie pretendía. config.inc.php y mysql_clientdb.conf no tienen nada que hacer en ninguno de esos lugares. Los errores ocurren igualmente, incluidos los míos.
Un administrador de sistemas deja el equipo. Por amistosa que sea la salida, las credenciales de base de datos compartidas que esa persona tuvo son credenciales en las que ya no confío del todo. La confianza no se transfiere automáticamente cuando alguien se va.
Una intrusión sospechada, incluso sin confirmar. Este caso es el más difícil de explicar a quien nunca ha administrado un servidor bajo sospecha de ataque. No esperas a tener pruebas antes de actuar. Asumes el compromiso y rotas. Una rotación innecesaria cuesta una tarde. Una que se omite, tras una brecha real, puede costar todos los sitios que alberga el servidor.
Por qué la rotación de credenciales de base de datos manual es tan propensa a errores
La primera vez que roté a mano las credenciales de base de datos de ISPConfig, subestimé cuántos archivos estaban involucrados. Todos tienen que cambiar juntos, o algo se rompe silenciosamente unas horas después.
Está config.inc.php en el lado del servidor, y una segunda copia en el lado de la interfaz. Ambas necesitan los mismos valores nuevos. Está mysql_clientdb.conf, que ISPConfig lee para gestionar la propia base de datos de cada sitio alojado, no solo su propio mantenimiento interno. Dovecot, Pure-FTPd y Postfix mantienen cada uno su propia copia de algunas de las mismas credenciales. El correo y el FTP pueden dejar de autenticar en silencio si actualizas el usuario de la base de datos y te olvidas de solo uno de esos tres.
Después está la topología Master/Slave que usan algunas de mis configuraciones. Un nodo Slave se autentica contra la base de datos de su Master a través de la red, con una contraseña separada. Esa contraseña tiene que rotarse en el propio Master, no solo localmente. Si te equivocas en el orden, un Slave puede quedar bloqueado fuera del mismo Master del que se supone que debe replicar.
Nada de eso es difícil a nivel conceptual. Son muchos archivos. Varios servicios que reiniciar, en un orden sensato. Casi ninguna tolerancia a un error de tecleo, sobre todo mientras lo haces bajo presión, justo después de encontrar algo que no querías encontrar. Esa combinación es exactamente la razón por la que la rotación de credenciales de base de datos se sentía más arriesgada a mano de lo que la tarea debería ser. Por eso escribí reset_DB_password.sh, después de vivir el problema yo mismo más de una vez.
Qué hace realmente reset_DB_password.sh
reset_DB_password.sh detecta si el nodo es Standalone, Master o Slave. Luego ejecuta solo las fases que ese rol necesita.
La Fase A rota la contraseña local de root de MySQL. Es la contraseña que el propio ISPConfig usa para gestionar la base de datos de cada sitio alojado. El script actualiza mysql_clientdb.conf para que coincida con el nuevo valor.
La Fase B rota la contraseña del usuario de control ispconfig. Actualiza config.inc.php tanto en el lado del servidor como en el de la interfaz. Después actualiza las credenciales correspondientes dentro de Dovecot, Pure-FTPd y Postfix. Así, el correo y el FTP siguen autenticando sin un paso manual aparte por otros tres archivos de configuración.
La Fase C se ejecuta solo en un Slave. Se conecta de forma remota a la base de datos del Master. Rota ahí la contraseña del usuario Slave, y después actualiza dbmaster_password localmente, para que la replicación siga autenticando correctamente con el nuevo valor.
Después de la Fase B, el script ofrece reiniciar Dovecot, Pure-FTPd y Postfix por ti. Casi siempre digo que sí. Una rotación de credenciales que deja un servicio de correo funcionando con la contraseña antigua no está terminada, solo está callada sobre estar rota. Reiniciar en la misma ejecución, justo después de cambiar los archivos de configuración, mantiene todo dentro de una única ventana de mantenimiento corta. Evita así tres ventanas descubiertas por separado más tarde.
Copias de seguridad antes de cambiar nada
Antes de tocar un solo archivo, el script hace una copia completa con rsync de /usr/local/ispconfig/ en una carpeta con marca de tiempo. También intenta un mysqldump no bloqueante de las bases de datos mysql y dbispconfig. No bloqueante a propósito: prefiero terminar una rotación de credenciales antes que quedarme esperando un dump atascado por alguna razón ajena. Cada archivo de configuración que edita recibe primero su propia copia .bak, antes de que se reemplace ninguna cadena dentro de él.
Nada de eso sustituye una estrategia de copias de seguridad independiente. Sigo haciendo un snapshot separado, o una copia de seguridad completa, antes de ejecutar esto en cualquier servidor que realmente importe. El propio descargo de responsabilidad del script dice lo mismo, de forma más directa de lo que yo lo acabo de decir.
Primero en modo de prueba, siempre
Cada fase pide confirmación antes de cambiar nada. –dry-run simula una ejecución completa sin tocar un solo archivo. Uso dry-run primero en cada servidor, siempre. Incluso en los que ya he rotado credenciales antes, y creo conocer bien. –skip-local-root omite la Fase A, para cuando solo hay que rotar la contraseña del usuario de control. –role=master o –role=slave anula la detección automática, para el caso poco frecuente en que no lee correctamente por sí solo la topología de un servidor.
Las contraseñas que genera tienen 32 caracteres, solo letras y números. Suficientemente largas para resistir intentos de adivinarlas. Suficientemente simples para que los propios parsers de MySQL y PHP nunca tropiecen con un símbolo suelto en una cadena de conexión. He probado el script en ISPConfig 3.3.1p1. No lo he ejecutado contra ramas más antiguas o más nuevas. No asumiría un comportamiento idéntico ahí, sin comprobarlo yo mismo antes.
El rol de un nodo no siempre es obvio a simple vista, sobre todo en un servidor que heredaste en lugar de construir tú mismo. Por eso existe –role, y por eso vale la pena leer línea por línea la salida de dry-run la primera vez, no solo echarle un vistazo. Prefiero pasar dos minutos confirmando que un Slave es realmente un Slave que descubrirlo de la peor manera a mitad de la rotación.
Lo que te diría antes de que lo ejecutes
Aviso: el script se proporciona tal cual, con fines informativos. Su uso es bajo tu exclusiva responsabilidad: no asumo ninguna responsabilidad por pérdida de datos, interrupciones del servicio, o cualquier error provocado por un uso incorrecto, una modificación del código, o un contexto distinto al que yo mismo utilizo. Haz siempre una copia de seguridad independiente o un snapshot de la VM antes de ejecutarlo en producción, al margen de lo que ya capture por ti el propio paso de backup del script.
Es software libre. Puedes redistribuirlo y modificarlo, con atribución a mí como autor original. El código de reset_DB_password.sh, y el resto de la colección ispconfig-fast-tools, está en GitHub en github.com/matteocisilino/ispconfig-fast-tools.
La rotación de credenciales de base de datos es un hábito, no una tarea de limpieza
La rotación de credenciales de base de datos tras una brecha confirmada es simplemente respuesta a incidentes competente. La mayoría de administradores lo haría sin que se lo repitieran dos veces. El hábito más difícil es hacerlo tras una simplemente sospechada, antes de que nadie tenga pruebas. Esa es la única versión del plan que realmente limita el daño, mientras todavía es limitable. Un script que ejecuta las fases correctas según el rol del servidor, y que hace sus propias copias de seguridad primero. Además, me permite probarlo todo en modo dry-run antes de tocar nada real. Eso es lo que hace que el hábito sea práctico un martes por la noche, en lugar de teórico en una entrada de blog.
ISPConfig, MySQL, PHP, Dovecot, Pure-FTPd, Postfix y los demás nombres mencionados son marcas registradas de sus respectivos propietarios. Se usan únicamente para identificar los productos.
Deja una respuesta