El día de hoy tuve que auditar permisos en un servidor de bases de datos MySQL, y me encontré con la dificultad que el mismo no provee una herramienta o comando para volcar todos los permisos (grants) de todos los usuarios. Por ello me vi en la necesidad de desarrollar un pequeño script Bash para llevar a cabo esta simple tarea. Pequeño script al que luego le agregué alguna funcionalidad básica para realizar filtrado y formateo de la salida.



El comando MySQL SHOW GRANTS, vuelca las sentencias SQL necesarias para duplicar los privilegios otorgados a una cuenta de usuario MySQL. Su comportamiento es similar al del comando SHOW CREATE TABLE, que vuelca la sentencia necesarias para crear una tabla.

Sin embargo, la limitación que tiene el comando SHOW GRANTS, es que se debe especificar una cuenta de usuario, y no es posible volcar los grants para todos los usuarios definidos en el motor de bases de datos. Entonces, es necesario primero listar todos los usuarios, para luego obtener los grants de cada uno.

El script, el cual he decidido llamar "mysqlgrants", está publicado en mi repositorio de scripts en GitHub.

Al ser ejecutado sin parámetros (o con -h) muestra una breve ayuda:

root@linuxito:~# ./mysqlgrants.bash
Dump MySQL grants for all users.

Usage: ./mysqlgrants.bash -u USER [-p] [OPTIONS]

  -u USER          User for login.

Options:

  -h, --help       Show this help.
  -p               Ask for pasword.
  --all-privileges List users with all privileges on some database.
  --global         List users with some privilege on all databases.
  --root           List users with all privileges on all databases
                   (same as --all-privileges --global).

Para funcionar requiere una cuenta de usuario MySQL con privilegios de SELECT sobre la base de datos 'mysql' (generalmente 'root'):

root@linuxito:~# ./mysqlgrants.bash -u root -p
Enter password: 
GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY PASSWORD xxxx
GRANT USAGE ON *.* TO 'fulanito'@'%' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON `mydb`.* TO 'fulanito'@'%'
GRANT ALL PRIVILEGES ON *.* TO 'root'@'::1' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'linuxito' IDENTIFIED BY PASSWORD xxxx
GRANT PROXY ON ''@'' TO 'root'@'linuxito' WITH GRANT OPTION
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD xxxx
GRANT PROXY ON ''@'' TO 'root'@'localhost' WITH GRANT OPTION

Por seguridad (en caso de correr el script como 'root', o un usuario que tenga privilegios SUPER), el script reemplaza los hashes de las contraseñas, en la salida, por la cadena "xxxx".

La opción --all-privileges lista aquellos usuarios que tengan ALL PRIVILEGES sobre alguna base de datos (junto con la base en cuestión):

root@linuxito:~# ./mysqlgrants.bash -u root -p --all-privileges
Enter password: 
USER                            ALL PRIVILEGES ON
'debian-sys-maint'@'localhost'  *.*
'fulanito'@'%'                  `mydb`.*
'root'@'::1'                    *.*
'root'@'127.0.0.1'              *.*
'root'@'linuxito'               *.*
'root'@'localhost'              *.*

La opción --global muestra aquellos usuarios con privilegios globales, es decir algún tipo de privilegio sobre todas las bases de datos (*.*):

root@linuxito:~# ./mysqlgrants.bash -u root -p --global
Enter password: 
GRANT ALL PRIVILEGES ON *.* TO 'debian-sys-maint'@'localhost' IDENTIFIED BY PASSWORD xxxx
GRANT USAGE ON *.* TO 'fulanito'@'%' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'::1' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'127.0.0.1' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'linuxito' IDENTIFIED BY PASSWORD xxxx
GRANT ALL PRIVILEGES ON *.* TO 'root'@'localhost' IDENTIFIED BY PASSWORD xxxx

La opción --root es equivalente a utilizar --all-privileges --global:

root@linuxito:~# ./mysqlgrants.bash -u root -p --root
Enter password: 
'debian-sys-maint'@'localhost'  *.*
'root'@'::1'                    *.*
'root'@'127.0.0.1'              *.*
'root'@'linuxito'               *.*
'root'@'localhost'              *.*

Este comando es útil para detectar rápidamente usuarios que tengan todos los privilegios sobre todas las tablas. Si en esta salida aparece algún usuario distinto a 'root', se deben encender todas las alarmas. Se trata de una intrusión, o de una configuración de permisos desastrosa, situación que puede ocurrir tranquilamente cuando se deja la administración de un servidor de bases de datos MySQL en manos de un inepto.

Esto fue lo que encontré en uno de los servidores de un cliente:

root@debian:~# ./mysqlgrants.bash -u root -p --all-privileges --global
Enter password: 
'debian-sys-maint'@'localhost'     *.*
'root'@'::1'                       *.*
'root'@'127.0.0.1'                 *.*
'root'@'debian'                    *.*
'root'@'localhost'                 *.*
'sultanito'@'%'                    *.*
'menganitodb'@'%'                  *.*
'test'@'%'                         *.*
'prueba'@'%'                       *.*
'prod_user'@'%'                    *.*
'borrar2016'@'%'                   *.*

Kill it with fire!!!

Conclusiones

No confundir ineptitud con ignorancia. Un ignorante (como quien escribe) se remite a manuales, guías, tutoriales, o cualquier otra fuente bibliográfica confiable que le sea de ayuda cuando se enfrenta a una tarea que desconoce. Se instruye para resolver la tarea de la mejor forma (correcta, eficiente y segura). Luego deja de ser completamente ignorante en esa cuestión o tarea en particular. Un inepto, por el contrario, simplemente aplica la funesta técnica de prueba y error, mezclada con un poco de copy&paste de comandos de dudosa procedencia. Los resultados en este último caso son terribles.

Por otro lado, ahora que traigo a colación el tema de copy&paste de comandos, jamás de los jamases peguen en sus consolas comandos copiados de este blog. Los comandos que aquí se incluyen se presentan de manera meramente ilustrativa, con el fin de instruir al lector. Incluso sus salidas están alteradas completamente para no divulgar detalles de los sistemas sujetos a ejemplo.

Para finalizar, las consecuencias de abaratar costos en recursos humanos dedicados a la administración de sistemas, backup y seguridad pueden tener consecuencias catastróficas. Un bug en un desarrollo de software en general se puede corregir (con esto no quiero decir que se debe abaratar costos en el desarrollo), pero la negligencia e ineptitud en cuestiones de infraestructura puede provocar pérdida de datos e incidentes de seguridad, los cuales pueden provocar considerables pérdidas de tiempo y dinero (y suelen tener consecuencias irreversibles e irreparables).

Referencias

MySQL 5.7 Reference Manual / ... / SHOW GRANTS Syntax


Tal vez pueda interesarte


Compartí este artículo