Estos días estuve peleando (sin éxito) por tratar de evitar darle a Ansible root access irrestricto en mis targets Linux. He aquí mi experiencia y conclusión.

Mi plan original era que Ansible no se autentique ni corra como root en los targets. Esto apunta a no tener que habilitar el login como root a través de SSH (por seguridad). Pero además a lograr una configuración de mínimo privilegio utilizando sudo. Esto es, permitir a Ansible ejecutar como root sólo aquellos comandos necesarios para el funcionamiento de los módulos a utilizar, para evitar la clásica y terrible configuración de sudo:

pepe ALL=(ALL) NOPASSWD: ALL

La cual básicamente hace que "pepe" se convierta automáticamente en root (mala idea).

Para comenzar, se me ocurrió probar con el módulo apt, el cual se encarga de gestionar paquetes utilizando el gestor APT sobre hosts Debian/Ubuntu. La configuración previa de sudoers para el usuario con el que autentica Ansible en los targets ("sysadmin"), permite que éste ejecute apt-get update, entre otros comandos, como root (sudo). Luego, para pasar a root utilizo la opción -b (become), una especie de wrapper a los diferentes mecanismos de elevación de privilegios disponibles en cada sistema operativo soportado (sudo, su, doas, ksu, etc.).

Sin embargo, al momento de ejecutar el módulo, este falla indicando que se requiere password para sudo (lo cual significa que la configuración de sudoers sin contraseña no hizo efecto):

[root@hal9000 /opt/ansible]# ansible devel-debian8 -m apt -a "update_cache=yes" -b
www-devel.linuxito.com | FAILED! => {
    "changed": false, 
    "failed": true, 
    "module_stderr": "Shared connection to www-devel.linuxito.com closed.\r\n", 
    "module_stdout": "sudo: a password is required\r\n", 
    "msg": "MODULE FAILURE", 
    "rc": 1
}

La raíz del problema está en la implementación misma de Ansible. En su funcionamiento normal, luego de abrir una sesión SSH, abre una subshell como root, desde la cual luego se lanza el intérprete de Python (obviamente como usuario root), que se encarga de correr el script que implementa el módulo utilizado (en este caso "apt"). Es decir, luego de abrir la sesión SSH se pasa inmediatamente a root, y todo se hace como root. Esto se puede verificar ejecutando ps en el target:

root     26347  0.0  0.5  86812  5976 ?        Ss   09:45   0:00 sshd: sysadmin [priv]
sysadmin 26349  0.0  0.4  86812  4992 ?        S    09:45   0:00 sshd: sysadmin@pts/1
sysadmin 26362  0.0  0.0   4336   724 pts/1    Ss+  09:45   0:00 /bin/sh -c sudo -H -S -n -u root /bin/sh -c 'echo BECOM
root     26363  0.0  0.3  44656  3580 pts/1    S+   09:45   0:00 sudo -H -S -n -u root /bin/sh -c echo BECOME-SUCCESS-zo
root     26364  0.0  0.0   4336   768 pts/1    S+   09:45   0:00 /bin/sh -c echo BECOME-SUCCESS-zoevhwomjrmnkoysqlzidksk
root     26365  0.0  1.0  33228 10484 pts/1    S+   09:45   0:00 /usr/bin/python /home/sysadmin/.ansible/tmp/ansible-tmp
root     26366  1.0  4.8  94556 49456 pts/1    S+   09:45   0:00 /usr/bin/python /tmp/ansible_za0xsv/ansible_module_apt.

El primer comando es un simple echo para verificar que pudo pasar a root, luego se inicia el intérprete de Python con un script temporal que finalmente será borrado.

Probablemente sea imposible tomar esta captura con ps cuando la autenticación con sudo falla (hay que correr ps justo en el instante que falla la autenticación, algo imposible). Sin embargo, al fallar la autenticación, root recibe un mail con la advertencia de seguridad. Si hemos configurado el servidor para reenviar todo mail a root a nuestra casilla, recibiremos un correo como el siguiente:

Se observa claramente la secuencia de comandos en el target. Ahora bien, como el comando enviado a sudo abre directamente una subshell no queda otra opción que filtrar, como mucho, el comienzo del mismo.

Editar el archivo de configuración de sudoers correspondiente:

root@www-devel:~# nano /etc/sudoers.d/sysadmin

Siendo que la cadena del comando comienza siempre con "/bin/sh -c echo BECOME-SUCCESS" y luego sigue con un número aleatorio, como mínimo privilegio se deberá permitir lo siguiente:


User_Alias USR_ADMIN = sysadmin

# ansible commands
Cmnd_Alias CMD_ANSIBLE = /bin/sh -c echo BECOME-SUCCESS*

# ansible nopasswd
USR_ADMIN SERVIDOR = NOPASSWD:CMD_ANSIBLE

La consecuencia de esta configuración es que cualquiera (logueado como "sysadmin") puede abrir una shell como "root" ejecutando la siguiente secuencia:

sysadmin@www-devel:~$ sudo /bin/sh -c 'echo BECOME-SUCCESS; su - root'
BECOME-SUCCESS
root@www-devel:~#

Es una cagada, ya lo sé, pero al menos es un poco mejor que permitir:

sysadmin ALL=(ALL) NOPASSWD: ALL

Al menos sirve como triste consuelo.

Con esta configuración de sudo, ansible puede elevar privilegios correctamente y el módulo funciona:

[root@hal9000 /opt/ansible]# ansible desa-debian8 -m apt -a "update_cache=yes" -b
www-devel.linuxito.com | SUCCESS => {
    "cache_update_time": 1504182750, 
    "cache_updated": true, 
    "changed": true, 
    "failed": false
}

Lamentablemente Ansible no tiene bien documentada la configuración de permisos en los targets y asume que la autenticación es como root, o puede se ejecutar cualquier comando como root elevando privilegios, o bien uno debe resignarse a tipear la contraseña de root para cada host (algo ridículo cuando justamente estamos tratando de lograr automatización de tareas. Falta de buena documentación e implementaciones con diseño "fuck security" son cosas que me molestan mucho, pero lamentablemente uno debe resignar (por no contar con tiempo suficiente para reimplementar los módulos) para poder aprovechar esta muy buena herramienta.

Para lograr el mejor balance entre automatización (no solicitar contraseña) y seguridad (mínimo privilegio), lo mejor sería tener la posibilidad de permitir (para cada módulo de Ansible) ejecutar como superusuario sólo una lista de comandos estrictamente necesarios. Desconozco cómo será la configuración de seguridad del resto de las soluciones, pero al menos éste es un punto flojo de Ansible. Sin embargo es de esperarse con este tipo de soluciones donde la facilidad (máxima automatización posible) suele estar por encima de la seguridad.

Referencias


Tal vez pueda interesarte


Compartí este artículo