En el artículo Cómo autenticar con clave pública en SSH expliqué detalladamente todos los pasos necesarios para autenticar con clave pública un usuario a través de SSH.
Para que el usuario con el que ejecutamos ansible
(en este caso root) sea capaz de autenticar con clave pública (sin contraseña) en los servidores, será necesario agregar la clave pública del mismo en cada archivo authorized_keys
perteneciente al usuario con el cual queremos autenticar en cada sistema remoto. Es una tarea tediosa, pero debe realizarse una única vez.
Es posible copiar nuestra clave pública por SSH, concatenando al archivo authorized_keys
del usuario en cuestión (por supuesto autenticando con contraseña). Si el usuario con el que queremos autenticar remotamente no posee contraseña, es posible habilitar el acceso por SSH como root de manera temporal (cambiando a PermitRootLogin yes
en el archivo sshd_config
y recargando el demonio sshd
).
Por seguridad no es recomendable autenticar sin contraseña en servidores remotos como root (directamente se debe impedir el ingreso por SSH como root, para mayor seguridad, configuración por defecto en la mayoría de las distribuciones GNU/Linux). Es decir, para autenticar a través de Ansible sobre los sistemas a administrar de manera centralizada, utilizar un usuario no privilegiado ("ansible", "sysadmin", o cualquier otro). Crear un usuario nuevo para el caso si no se dispone de uno.
Supongamos que deseo autenticar como el usuario "sysadmin" en el servidor "www-devel.linuxito.com" sin utilizar contraseña. Una vez copiado el contenido la clave pública del usuario con el que corre ansible
(~/.ssh/id_dsa.pub
) dentro del archivo /home/sysadmin/.ssh/authorized_keys
del servidor "www-devel.linuxito.com", sólo basta con agregar el nuevo sistema al inventario.
A tal fin voy a definir un nuevo grupo llamado "devel-debian8". Mi idea inicial es separar mis servidores en grupos por entorno y versión de sistema operativo. De esta forma voy a organizar mis servidores en "prod-debian7", "devel-debian7", "prod-debian8", "devel-debian8", y así sucesivamente.
[root@hal9000 /opt/ansible]# nano ~/ansible_hosts
127.0.0.1 [devel-debian8] www-devel.linuxito.com:2222 ansible_user=sysadmin
Luego ya es posible lanzar un comando hacia el nuevo grupo, en este caso un simple "ping":
[root@hal9000 /opt/ansible]# ansible devel-debian8 -m ping The authenticity of host '[www-devel.linuxito.com]:2222 ([192.168.42.38]:2222)' can't be established. ECDSA key fingerprint is SHA256:saraza.com. No matching host key fingerprint found in DNS. Are you sure you want to continue connecting (yes/no)? yes www-devel.linuxito.com | SUCCESS => { "changed": false, "failed": false, "ping": "pong" }
Como toda vez que se inicia una conexión SSH por primera vez, se solicita almacenar el fingerprint del sistema remoto. Luego ya no aparece dicho warning. Notar cómo no solicita la contraseña para el usuario "sysadmin" en el sistema "www-devel.linuxito.com":
[root@hal9000 /opt/ansible]# ansible devel-debian8 -m ping www-devel.linuxito.com | SUCCESS => { "changed": false, "failed": false, "ping": "pong" }
Ya es posible lanzar cualquier comando con el módulo "shell":
[root@hal9000 /opt/ansible]# ansible devel-debian8 -m shell -a "uname -r" www-devel.linuxito.com | SUCCESS | rc=0 >> 3.16.0-4-amd64
Cabe destacar que al utilizar un usuario no privilegiado, será necesario que cuente con una configuración de sudo
adecuada para ejecutar los comandos deseados sin tener problemas de autorización:
[root@hal9000 /opt/ansible]# ansible devel-debian8 -m shell -a "sudo apt-get update" [WARNING]: Consider using 'become', 'become_method', and 'become_user' rather than running sudo www-devel.linuxito.com | SUCCESS | rc=0 >> Ign http://ftp.br.debian.org jessie InRelease Obj http://ftp.br.debian.org jessie Release.gpg Obj http://ftp.br.debian.org jessie Release Obj http://ftp.br.debian.org jessie/main amd64 Packages Obj http://ftp.br.debian.org jessie/contrib amd64 Packages Obj http://ftp.br.debian.org jessie/contrib Translation-en Obj http://ftp.br.debian.org jessie/main Translation-es Obj http://ftp.br.debian.org jessie/main Translation-en Obj http://security.debian.org jessie/updates InRelease Obj http://security.debian.org jessie/updates/main amd64 Packages Obj http://security.debian.org jessie/updates/contrib amd64 Packages Obj http://security.debian.org jessie/updates/contrib Translation-en Obj http://security.debian.org jessie/updates/main Translation-en Leyendo lista de paquetes...
Durante la ejecución de este comando, es posible notar el funcionamiento de Ansible en el target, ejecutando ps
:
sysadmin 13034 0.0 0.4 86812 5012 ? S 14:31 0:00 sshd: sysadmin@pts/1 sysadmin 13087 0.0 0.0 4336 812 pts/1 Ss+ 14:35 0:00 /bin/sh -c /usr/bin/python /home/sysadmin/.ansible/tmp/ sysadmin 13088 0.5 1.0 33168 10312 pts/1 S+ 14:35 0:00 /usr/bin/python /home/sysadmin/.ansible/tmp/ansible-tmp sysadmin 13089 1.2 1.2 37400 12572 pts/1 S+ 14:35 0:00 /usr/bin/python /tmp/ansible_v6Is8E/ansible_module_comm root 13090 0.0 0.3 44656 3588 pts/1 S+ 14:35 0:00 sudo apt-get update root 13091 23.7 2.3 55640 24420 pts/1 R+ 14:35 0:00 apt-get update
Se observa (a grandes rasgos) que se inicia la conexión SSH como "sysadmin", la cual a su vez abre una shell sh
desde donde se ejecuta el intérprete de Python (/usr/bin/python
), el cual levanta un script temporal que termina ejecutando el comando solicitado.
En el próximo artículo sobre Ansible trataré el tema de los playbooks, el cual probablemente abarque más de un episodio. Por el momento esto es todo.
Referencias