Despliegue de Ansible y Semaphore en Docker para automatizar tareas Windows y Linux. Creamos una máquina virtual Linux Ubuntu sobre Proxmox, instalamos Docker y Docker Compose. Instalamos Ansible y desplegamos contenedor con Semaphore. Preparamos los servidores Linux y programamos y ejecutamos una primera tarea para revisar el correcto funcionamiento de Ansible.

Paso 1: Crear la máquina virtual en Proxmox

En primer lugar, crearemos la máquina virtual con Linux Ubuntu Server 26 específica para este propósito, para ello, subiremos (si aún no lo tenemos) el ISO de Ubutu Server al local del nodo Proxmox y crearemos la máquina virtual, con los siguientes datos:

  • General: asignaremos un ID y un nombre, por ansible.
  • OS: seleccionamos la ISO de Ubuntu 26.04 subida a local.
  • System: dejamos las opciones por defecto, podemos activar Qemu Agent si queremos instalarlo posteriormente.
  • Disks: asignaremos entre 30 GB y 50 GB. Si el almacenamiento en Proxmox es SSD, marcaremos la casilla Discard para optimizar el espacio.
  • CPU: asignaremos 2 cores (es más que suficiente para empezar).
  • Memory: asignaremos 2 GB o 4 GB de RAM.
  • Network: configuraremos la red para que la VM tenga salida a Internet (para instalar los paquetes) y visibilidad hacia las redes de los servidores Linux y Windows a los que necesitemos acceder para automatizar tareas.

Iniciaremos la máquina virtual Ubuntu Server y seguiremos los pasos de instalación normales de Ubuntu Server 26:

Paso 2: Instalar Docker y Docker Compose

Una vez terminada la instalación de Linux Ubuntu Server, accederemos al nuevo servidor por SSH. Para instalar Docker y Docker Compose, ejecutaremos los siguientes comandos.

1. Actualizaremos el sistema e instalaremos los certificados básicos:

2. Agregaremos la clave GPG oficial de Docker:

3. Añadiremos el repositorio oficial de Docker para Ubuntu 26:

4. Instalaremos el motor de Docker y Docker Compose:

5. Habilitaremos docker para que se inicie en el arranque del equipo:

Paso 3: Desplegar Ansible Semaphore

Ahora crearemos el contenedor donde desplegaremos la interfaz web del sistema Ansible Semaphore. Utilizaremos una base de datos PostgreSQL para almacenar los registros de las ejecuciones, usuarios e inventarios.

Crearemos una carpeta para organizar el despliegue:

Crearemos el archivo de configuración:

Pegaremos el siguiente contenido dentro de docker-compose.yml (modificaremos las contraseñas de ejemplo por unas seguras):

Guarda el archivo pulsando Ctrl+O y cierra la edición pulsando Ctrl+X.

Iniciaremos la infraestructura docker con los contenedores indicados en el fichero docker-compose.yml en segundo plano con:

Los contenedores, imágenes y volúmenes se crearán automáticamente y, por defecto, se levantará el puerto 3000:

Ya podremos abrir un navegador en cualquier equipo de la misma red del servidor Ansible y navegar a la URL:

http://IP_Servidor_Ansibe:3000

Nos mostrará la ventana de login de Semaphore:

En cuanto accedamos por primera vez a Semaphore, nos mostrará la ventana para crear un proyecto nuevo, en Nombre del Proyecto introduciremos «Automatización» y pulsaremos en «Crear»:

Paso 3: Desplegar Ansible Semaphore

Paso 4: Claves de acceso a servidores Linux

El siguiente paso natural es crear las claves de acceso a los servidores que queramos administrar. Para el caso de los servidores Linux, usaremos SSH. Para establecer las claves SSH de acceso desde el servidor Ansible Semaphore a los servidores Linux, seguiremos estos pasos.

Paso 4.1: Generar el par de claves en servidor Ansible

Accederemos por SSH al servidor Ansible Semaphore y ejecutaremos este comando:

Preguntará dónde guardarla (pulsaremos Enter para dejar la ruta por defecto) y pedirá una «passphrase» (contraseña). Para automatizar con Ansible de forma sencilla, dejaremos en blanco presionando Enter dos veces.

Paso 4.2: Poner la clave privada en Semaphore

Ahora vamos a obtener la clave privada por pantalla para copiarla, con:

Por supuesto, en este proceso, es IMPRESCINDIBLE mantener la clave privada en una carpeta de acceso seguro en el servidor Linux Ansible y no exponerla en ningún momento. Si se copia en un equipo Windows, tras finalizar el proceso, conviene reiniciar el equipo para que se «libere» de memoria.

Copiamos el bloque de la clave privada, incluyendo (muy importante) las líneas —–BEGIN OPENSSH PRIVATE KEY—– y —–END OPENSSH PRIVATE KEY—–. Volvemos a la consola web de Semaphore, a nuestro proyecto creado, pulsamos en «Almacén de Claves» y en «Nueva clave»:

Introducimos un nombre para la clave, para identificarla para su posterior uso, por ejemplo «admin_linux», seleccionamos «LOCAL» y pegamos en Clave Privada la clave copiada anteriormente. En caso de haber indicado una passphrase, la introduciremos aquí. De momento, el nombre de usuario podemos indicar el que crearemos posteriormente específico en cada servidor «anb_sru»:

Paso 4.3: Repartir la clave pública en los servidores Linux que queramos administrar

Ahora indicaremos a los servidores Linux que confíen en esa llave. Para ello, deberemos tener inventariados todos los equipos Linux y conocer su usuario administrador y su dirección IP.

Para la «repartir» la clave pública tenemos varias opciones: enviarla por SSH desde el servidor de Ansible a cada servidor, en este caso, tendríamos que utilizar el usuario administrador de cada equipo y esta NO es una buena práctica, dado que para ejecutar tareas automatizadas que requieran de elevación de privilegios, a este usuario administrador de cada servidor habría que indicarle que puede ejecutar sudo… sin solicitar contraseña. Por lo tanto, esta opción NO LA RECOMENDAMOS. La otra opción, la recomendada, es crear un usuario específico para uso de Ansible en cada servidor, sin contraseña, sin posibilidad de que pueda realizar login, solo para uso de Ansible, para conectar por SSH a los equipos y poder ejecutar comandos con elevación de privilegios. Explicamos ambas opciones más adelante.

Preparar equipos servidores para conexión SSH desde servidor Ansible

Para poder realizar la gestión desde el servidor Ansible, es imprescindible que los servidores tengan el servicio SSH activo y, si tienen el cortafuegos local activado, nos debemos asegurar de que tienen acceso por SSH desde la IP del servidor de Ansible. Para cortafuegos local ufw podremos permitir acceso SSH (puerto 22) a la IP del Ansible con el comando:

Ansible usa Python, por lo que también es conveniente que esté instalado en cada servidor y, además, conocer su ubicación, para indicársela posteriormente en el inventario de Semaphore.

Opción 1: transferir clave por SSH con usuario administrador de los servidores (NO RECOMENDADA)

Cuando tengamos la lista de servidores y estemos seguros de que tienen SSH, volveremos a la consola SSH del servidor Ansible, e iremos ejecutando el siguiente comando (hay que repetirlo por cada servidor a gestionar). Sólo necesitaremos ejecutarlo una vez, para transferir una copia de la clave pública del servidor Ansible al resto de equipos Linux:

Cambiaremos la IP y el usuario por la IP de cada servidor y el nombre del usuario administrador (con permisos de acceso SSH).

Nos solicitará confirmación, escribiremos «yes» y nos solicitará la contraseña del usuario indicado en el comando del servidor indicado en la IP.

Opción 1: transferir clave por SSH con usuario administrador de los servidores (NO RECOMENDADA)

Si los datos son correctos, transferirá la clave pública al servidor Linux indicado y, a partir de este momento, el servidor de Ansible Semaphore tendrá acceso administrativo a dicho servidor. Repetiremos el proceso para todos los servidores a administrar.

Pero, para esta opción NO RECOMENDADA, si necesitamos ejecutar tareas automatizadas en los servidores que requiera de elevación de privilegios, no funcionarán, porque el usuario administrador de los equipos, habitualmente, cuando usamos sudo … nos solicitará contraseña. En este caso, para que funcionase, habría que añadir, en el fichero sudoers, una línea, para ello (repetimos que NO es lo recomendable), en cada servidor, con el usuario administrador, ejecutaremos:

Y añadiremos, al final, esta línea:

Opción 1: transferir clave por SSH con usuario administrador de los servidores (NO RECOMENDADA)

Con esta configuración, y por eso NO es recomendable, el usuario administrador del equipo podrá ejecutar elevación de privilegios sin que se le solicite contraseña (solo se le pedirá contraseña al iniciar sesión).

Opción 2: crear usuario seguro sin contraseña/login en cada servidor específico para Ansible (RECOMENDADO)

Es muy recomendable crear un usuario específico en los servidores para uso de Ansible. Este usuario será el que se emplee para las automatizaciones que requieran de elevación de privilegios (sudo…).

Para evitar que los comandos sudo… fallen, crearemos un usuario administrador en cada servidor, sin contraseña, pues usará la clave SSH pública de Ansible. Accederemos a cada servidor y crearemos un usuario, por ejemplo «anb_sru», sin contraseña (no tendrá acceso con login normal):

Creamos un archivo dedicado dentro de la carpeta sudoers.d. Esto es mucho más seguro que editar el archivo principal /etc/sudoers. Le indicamos que el usuario creado anteriormente puede ejecutar cualquier comando como administrador sin que se le pida contraseña:

Accedemos con el usuario creado para asignarle su estructura de carpetas de seguridad. Así nos aseguramos de que él sea el propietario legítimo de los archivos:

Ahora necesitamos conocer la clave pública del servidor Ansible, así que volvemos a la consola shell del servidor Ansible y ejecutamos el siguiente comando, que nos devolverá la clave pública (la copiamos):

Volvemos al servidor, y creamos el archivo de claves y pegamos dentro la clave pública que hemos generado en nuestro servidor Semaphore/Ansible:

Pegaremos la clave generada aneriormente en el servidor Ansible y guardamos.

Damos los permisos obligatorios de Linux para este archivo (si no tiene los permisos 600, el servidor SSH rechazará la conexión por considerarlo inseguro):

Primera tarea de automatización en Ansible para verificar funcionamiento y conexión con servidores

Aunque la práctica recomendada es usar Git (en local o remoto) para gestionar los playbooks de tareas, para tener control de versiones y modificaciones, Ansible también permite playbooks locales. Para realizar una primera automatización de prueba, vamos a usar los playbooks locales.

Accederemos al servidor de Ansible por SSH y crearemos una carpeta para almacenar los playbooks (usaremos la carpeta creada en el proceso de despliegue del sistema «~/semaphore»):

Crearemos nuestro primer playbook «inventario.yml»:

Pegaremos el siguiente YAML que obtiene el tiempo que está el servidor encendido, el espacio en la unidad raíz y el nombre del equipo:

IMPORTANTE: dado que Semaphore está corriendo en docker, deberemos establecer esta carpeta del equipo Ubuntu Server local como volumen en el contenedor Docker. Para ello, editaremos el archivo docker-compose.yml que creamos anteriormente para el despliegue:

en «semaphore», antes de «depends_on», añadimos (manteniendo la indentación):

Es importante limitar los permisos para la carpeta playbooks, dado que podríamos guardar scripts con contraseñas en plano. Además, esta carpeta debe ser accesible por Docker, para que sea accesible, a su vez, por el contenedor con Ansible/Semaphore:

Qué significan los permisos aplicados anteriormente:

  • Propietario ($USER / admin): tiene permisos 7 (en carpetas) y 6 (en archivos). Esto significa que puede leer, escribir, modificar y borrar cualquier playbook desde el shell de comandos.
  • Grupo (1001 / Docker Semaphore): tiene permisos 5 (en carpetas) y 4 (en archivos). Esto le da permiso de Solo Lectura. El contenedor puede leer los scripts de Python y tus Playbooks de Ansible para ejecutarlos, pero no puede modificarlos ni borrarlos.
  • Otros (0): el último cero es el escudo. Cualquier otro usuario que acceda a al servidor Ubuntu (otros administradores, servicios web, o un intruso) se encontrará con «Permiso Denegado» si intenta hacer un simple cat a un script para visualizarlo.

Para aplicar los cambios, desde la carpeta donde tenemos el fichero docker-compose.yml, volveremos a ejecutar el comando:

Volveremos a la consola web de gestión de Semaphore, pulsaremos en «Repositorios» y en «Nuevo repositorio»:

Introduciremos los siguientes datos:

  • Nombre: nombre identificativo para el repositorio, por ejemplo «Local»
  • URL o ruta: indicaremos la ruta exacta donde hemos guardado el fichero inventario.yml. Dado que Semaphore se ejecuta en un contenedor Docker y dado que hemos redireccionado la carpeta real /semaphore/playbooks a /playbooks en el contenedor, en este campo introduciremos: /playbooks
  • Clave de Acceso: seleccionaremos la clave creada anteriormente «admin_linux».

Crearemos un inventario con las máquinas Linux que queramos administrar, para ello, pulsaremos en «Inventario» y en «Nuevo inventario» – «Ansible Inventory»:

Introduciremos los siguientes datos:

  • Nombre: nombre descriptivo del inventario, por ejemplo «Servidores_Linux».
  • Credenciales de Usuario: elegiremos la clave creada anteriormente «admin_linux».
  • Tipo: elegiremos Static.
  • Y en el recuadro, en formato INI, introduciremos todos los servidores (nombre e IP), por ejemplo:

Y, muy importante, añadiremos también al recuadro anterior el usuario que hemos usado para la conexión SSH con cada servidor:

Y si el usuario es diferente para cada servidor, introduciremos los datos así:

Ansible permite, incluso, hacer un híbrido, es decir, si por ejemplo varios de los servidores usan el mismo usuario, por ejemplo «usuario_ssh», y algunos un usuario concreto, podremos indicar:

Y un detalle más, Ansible necesita Python en los servidores, si no le indicamos en qué ruta está, lo buscará automáticamente pero mostrará un warning. Para evitar el warning, indicaremos en qué ruta está Python en el recuadro anterior:

Y si en algún servidor está en otra ruta:

Para esta primera automatización no necesitamos variables complejas, pero crearemos una vacía para uso futuro. Pulsaremos en Grupos de Variables y en «Nuevo grupo»:

Introduciremos un nombre y dejaremos todo lo demás vacío:

Por último, para crear la tarea propiamente dicha, pulsaremos en «Plantillas de Tareas» y en «Nueva plantilla»:

Elegiremos «Ansible Playbook»:

Introduciremos los siguientes datos para crear la tarea:

  • Nombre: Inventario_Linux.
  • Ruta al archivo de playbook: inventario.yml.
  • Inventario: Servidores_Linux.
  • Repositorio: Local.
  • Grupos de Variables: Variables_Linux.

Dejaremos todo lo demás por defecto y pulsaremos en «Crear»:

Una vez creada la tarea, para ejecutarla, pulsaremos en el botón «Play»:

En la ventana que nos muestra, pulsaremos en «Ejecutar»:

Si al ejecutar la tarea muestra este error:

12:30:22 PM Failed to install inventory: cannot decrypt access key, perhaps encryption key was changed
12:30:22 PM Failed to run task: cannot decrypt access key, perhaps encryption key was changed

Se debe a que hemos establecido la clave antes de recrear el contenedor (tras aplicar el cambio de mapeo a carpeta /playbooks) y, como no hemos persistido la carpeta de configuración del contenedor, cada vez que lo reiniciemos cambiará la key, por lo que habría que volver a crear la clave. Para evitar esto, vamos a persistir la configuración, editando el fichero docker-compose.yml y añadiendo:

Justos debajo de la línea «- ./playbooks:/playbooks»:

Crearemos la carpeta «config» dentro de ~/semaphore:

Y le estableceremos los permisos:

Volveremos a recrear el contenedor para que se aplique el cambio:

Y deberemos volver a crear la clave:

Una vez corregidos los problemas, si ejecutamos la tarea, funcionará perfectamente: