ANSIBLE¶
El acceso a los equipos se puede hacer por usr-pass pero se DEBE hacer por pares de llaves público-privadas.
Para ello lo ideal es generar las llaves en el gestor (ordenador del profesor) y ubicar la llave pública del mismo en TODAS las máquinas a controlar, añadirla a ~/.ssh/authorized_keys tanto en Windows como GNU/Linux con cat llave_a_añadir.pub >> ~/.ssh/authorized_keys.
Comandos CLI¶
Ansible puede funcionar lanzando comandos directos o por play books separadas.
Pruebas "ping"¶
ansible -i inventory.yml vps -m ping -u usuario con par de llaves o con -K para que pida contraseña.
Corriendo playbooks¶
ansible-playbook -i inventory playbook-vps.yml
O con -vvvv para ser mas verboso y con -u usuario podemos seleccionar un usuario diferente al del ssh.
Run¶
ansible-playbook --inventory hosts \
-user root \
--ask-pass \
--forks 5 \
--limit SUBSET \
playbook.yml
Recuerda que en ANSIBLE los permisos de root se adquieren con el modo --become y pide la clave con --ask-become-pass.
SUBSET es un patrón que limita el número de equipos del grupo dado, p.e. "des1", "sys1" o un equipo dado "des1_101".
Por defecto se realizarán 5 conexiones en paralelo, por lo que como óptimo puede ser adecuado para no saturar la red. Si tienes 24 alumnos puede ser adecuado subirlo a 6 o bajarlo a 4.
Instalar ansible¶
en Ubuntu y derivadas¶
sudo apt-get install ansible
Inventario¶
Ejemplo por grupos (ideal para aulas):
all:
vars:
ansible_user: usuario_remoto
ansible_ssh_private_key_file: /home/usuario_local/ansible/ansible-private-key
ansible_connection: ssh
children:
# Desarrollo DAW1 y DAM1
des1:
hosts:
des1_101:
des1_102:
ansible_host: 192.168.30.102
des1_103:
ansible_host: 192.168.30.103
des1_104:
ansible_host: 192.168.30.104
des1_105:
ansible_host: 192.168.30.105
des1_106:
ansible_host: 192.168.30.106
des1_107:
ansible_host: 192.168.30.107
des1_108:
ansible_host: 192.168.30.108
des1_109:
ansible_host: 192.168.30.109
des1_110:
ansible_host: 192.168.30.110
des1_111:
ansible_host: 192.168.30.111
des1_112:
ansible_host: 192.168.30.112
des1_113:
ansible_host: 192.168.30.113
des1_114:
ansible_host: 192.168.30.114
des1_115:
ansible_host: 192.168.30.115
des1_116:
ansible_host: 192.168.30.116
des1_117:
ansible_host: 192.168.30.117
des1_118:
ansible_host: 192.168.30.118
des1_119:
ansible_host: 192.168.30.119
des1_120:
ansible_host: 192.168.30.120
des1_121:
ansible_host: 192.168.30.121
des1_122:
ansible_host: 192.168.30.122
des1_123:
ansible_host: 192.168.30.123
des1_124:
ansible_host: 192.168.30.124
des1_125:
ansible_host: 192.168.30.125
des1_126:
ansible_host: 192.168.30.126
des1_127:
ansible_host: 192.168.30.127
des1_128:
ansible_host: 192.168.30.128
des1_129:
ansible_host: 192.168.30.129
des1_130:
ansible_host: 192.168.30.130
# Sistemas SMR1 y ASIR1
sys1:
hosts:
sys1_201:
#...
Ejemplos más complejos:
all:
children:
localhost:
hosts:
127.0.0.1
vps:
hosts:
ateca-profe:
# ansible_host: 192.168.XX.YY
ansible_host: dominio.duckdns.org
ansible_port: 12345
#ansible_ssh_user=root
#ansible_ssh_pass=xxxxxx
#ateca-profe-ip:
# ansible_host: AA.BB.CC.DD
# ansible_port: 12345
server_group2:
children:
app1:
hosts:
host2:
host3:
app2:
hosts:
host4:
host5:
#vars:
# ssh_port: 1234
#ungrouped:
Ejemplos:¶
Depuración básica¶
- hosts: all
tasks:
- name: Print message
debug:
msg: Hello Ansible World
Añadir, evitar y actualizar paquetes¶
- Comprueba conectividad (si existe seguimos)
- Instala los paquetes de la lista
- Elimina los paquetes de la lista de ausentes
- Actualiza el resto de paquetes
playbook-vps.yml:
- hosts: vps
tasks:
- name: Ping
ansible.builtin.ping:
- name: Install a list of packages
ansible.builtin.apt:
pkg:
- sudo
- curl
- fail2ban
#name: nginx=1.18.0
state: latest
update_cache: yes
- name: Remove curl
ansible.builtin.apt:
pkg:
- vagrant
state: absent
- name: Upgrade the OS (apt-get dist-upgrade)
ansible.builtin.apt:
upgrade: dist
Actualizar y apagar equipos¶
---
- name: Playbook de Actualización y Reinicio Controlado
hosts: web_servers # Asegúrate de que este grupo esté definido en your_inventory.ini
become: yes # Ejecutar con privilegios elevados (sudo)
gather_facts: yes # Recopila información del sistema operativo
tasks:
# 1. Actualización de paquetes
- name: 🔄 1. Actualizar lista de paquetes
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600 # Solo actualizar si ha pasado una hora
register: apt_update_status
ignore_errors: yes # Permite seguir incluso si la actualización falla
- name: 📦 2. Aplicar las actualizaciones de todos los paquetes
ansible.builtin.apt:
upgrade: yes
autoremove: yes
register: apt_upgrade_status
# --- LÓGICA DE APAGADO (SHUTDOWN) ---
# Si tu objetivo NO es actualizar, sino solo apagar, usa este playbook simple:
- name: Apagado Controlado
hosts: target_equipment
become: yes
tasks:
- name: Ejecutar apagado seguro
ansible.builtin.reboot:
state: absent # Indica que el objetivo es el apagado
reboot_timeout: 10
Bloquear acceso al exterior¶
---
- name: Configure iptables to block all except local and 192.168.30.0/24
hosts: all
become: true
tasks:
# 1. Allow loopback traffic (essential for local system operations)
- name: Allow loopback interface
ansible.builtin.iptables:
chain: INPUT
in_interface: lo
jump: ACCEPT
# 2. Allow traffic from the specific subnet 192.168.30.0/24
- name: Allow traffic from 192.168.30.0/24
ansible.builtin.iptables:
chain: INPUT
source: 192.168.30.0/24
jump: ACCEPT
# 3. Set default policy to DROP for all other incoming traffic
- name: Drop all other incoming traffic
ansible.builtin.iptables:
chain: INPUT
policy: DROP
# 4. (Optional) Allow established/related connections to maintain active sessions
- name: Allow established connections
ansible.builtin.iptables:
chain: INPUT
ctstate:
- ESTABLISHED
- RELATED
jump: ACCEPT
Eliminar reglas IPTABLE¶
Para eliminar una regla, se usa el parámetro state: absent. Es crucial especificar los mismos parámetros de coincidencia (cadena, protocolo, puerto, comentario) que en la regla original para que Ansible pueda identificarla correctamente.
- name: Eliminar regla de puerto HTTP
ansible.builtin.iptables:
chain: INPUT
protocol: tcp
destination_port: 80
jump: ACCEPT
state: absent
comment: "Regla para Apache"
Consideraciones importantes:
- Persistencia: El módulo ansible.builtin.iptables aplica las reglas en tiempo real. Para que persistan tras un reinicio, depende de la distribución: en Debian/Ubuntu suele requerir iptables-persistent, mientras que en RHEL/CentOS se guarda en /etc/sysconfig/iptables.
- Seguridad: Al establecer políticas restrictivas (ej. policy: DROP), asegúrese de permitir primero el tráfico SSH (port 22) para no perder la conexión remota.
- Módulos alternativos: En sistemas con firewalld, es preferible usar el módulo firewalld de Ansible en lugar de iptables directamente.
Servicio complejo "Flask"¶
playbook-docker-compose-localhost.yml:
# Examples use the django example at https://docs.docker.com/compose/django. Follow it to create the
# flask directory
- name: Run using a project directory
#hosts: localhost
hosts: ateca-profe
gather_facts: false
tasks:
- name: Tear down existing services
community.docker.docker_compose_v2:
project_src: flask
state: absent
- name: Create and start services
community.docker.docker_compose_v2:
project_src: flask
register: output
- name: Show results
ansible.builtin.debug:
var: output
- name: Run `docker compose up` again
community.docker.docker_compose_v2:
project_src: flask
register: output
- name: Show results
ansible.builtin.debug:
var: output
- ansible.builtin.assert:
that: not output.changed
- name: Stop all services
community.docker.docker_compose_v2:
project_src: flask
state: stopped
register: output
- name: Show results
ansible.builtin.debug:
var: output
- name: Verify that web and db services are not running
ansible.builtin.assert:
that:
- web_container.State != 'running'
- db_container.State != 'running'
vars:
web_container: >-
{{ output.containers | selectattr("Service", "equalto", "web") | first }}
db_container: >-
{{ output.containers | selectattr("Service", "equalto", "db") | first }}
- name: Restart services
community.docker.docker_compose_v2:
project_src: flask
state: restarted
register: output
- name: Show results
ansible.builtin.debug:
var: output
- name: Verify that web and db services are running
ansible.builtin.assert:
that:
- web_container.State == 'running'
- db_container.State == 'running'
vars:
web_container: >-
{{ output.containers | selectattr("Service", "equalto", "web") | first }}
db_container: >-
{{ output.containers | selectattr("Service", "equalto", "db") | first }}
Activar un servicio¶
En ocasiones podemos querer levantar un servicio concreto a nuestros alumnos, p.e. mysql por lo que con ésto podemos independizar dicho servicio según profesor.
playbook-docker-compose-prueba.yml:
- name: Run using a project directory
#hosts: localhost
hosts: ateca-profe
gather_facts: false
tasks:
- name: copy Docker Compose files
copy:
src: files/item
dest: /home/luis/yourproject
loop:
- compose.yml
- compose.prod.yml
# use files parameter to use multiple docker-compose.yml files
# mind the _v2 suffix
- name: deploy Docker Compose stack
community.docker.docker_compose_v2:
project_src: /home/luis/yourproject/item
files:
- compose.yml
- compose.prod.yml
Crear SUDO:¶
Equipos Debian NO suelen venir con sudo por lo que, los que venimos de Ubuntu y derivadas nos resulta incómodo trabajar con su...
playbook-vps-create-user-sudo.yml:
# Le falta crear .profile y .bashrc
- hosts: vps
tasks:
- name: Make sure we have a 'wheel' group
ansible.builtin.group:
name: wheel
state: present
- name: Allow 'wheel' group to have passwordless sudo
lineinfile:
dest: /etc/sudoers
state: present
regexp: "^%wheel"
line: "%wheel ALL=(ALL) NOPASSWD: ALL"
validate: "visudo -cf %s"
- name: Add sudoers users to wheel group
user: name=luis
groups=wheel
append=yes
state=present
createhome=yes
- name: Set up authorized keys for the deployer user
authorized_key: user=luis key="{{item}}"
with_file:
- /home/luis/.ssh/id_ed25519.pub
Docker¶
playbook-vps-docker.yml:
---
# Cambiar hosts y sistema Ubuntu/Debian/...
- name: Install Docker on Ubuntu
hosts: vps
#remote_user: garis # Change remote user to your sudo user!
become: true
vars:
arch_mapping: # Map ansible architecture {{ ansible_architecture }} names to Docker's architecture names
x86_64: amd64
aarch64: arm64
tasks:
- name: Update and upgrade all packages to the latest version
ansible.builtin.apt:
update_cache: true
upgrade: dist
cache_valid_time: 3600
- name: Install required packages
ansible.builtin.apt:
pkg:
- apt-transport-https
- ca-certificates
- curl
- gnupg
- software-properties-common
- name: Create directory for Docker's GPG key
ansible.builtin.file:
path: /etc/apt/keyrings
state: directory
mode: '0755'
- name: Add Docker's official GPG key
ansible.builtin.apt_key:
url: https://download.docker.com/linux/ubuntu/gpg
keyring: /etc/apt/keyrings/docker.gpg
state: present
- name: Print architecture variables
ansible.builtin.debug:
msg: "Architecture: {{ ansible_architecture }}, Codename: {{ ansible_lsb.codename }}"
- name: Add Docker repository
ansible.builtin.apt_repository:
repo: >-
deb [arch={{ arch_mapping[ansible_architecture] | default(ansible_architecture) }}
signed-by=/etc/apt/keyrings/docker.gpg]
https://download.docker.com/linux/debian {{ ansible_lsb.codename }} stable
filename: docker
state: present
- name: Install Docker and related packages
ansible.builtin.apt:
name: "{{ item }}"
state: present
update_cache: true
loop:
- docker-ce
- docker-ce-cli
- containerd.io
- docker-buildx-plugin
- docker-compose-plugin
- name: Add Docker group
ansible.builtin.group:
name: docker
state: present
- name: Add user to Docker group
ansible.builtin.user:
name: "{{ ansible_user }}"
groups: docker
append: true
- name: Enable and start Docker services
ansible.builtin.systemd:
name: "{{ item }}"
enabled: true
state: started
loop:
- docker.service
- containerd.service
Windows¶
Connect to Windows (Managed Node)To manage your Windows 11 machine from Ansible, you will need to configure PowerShell Remoting on the Windows side.
-
Open an Administrator PowerShell prompt on your Windows 11 machine.
-
Run the initialization script to allow remote connections (en powershell)
powershell Enable-PSRemoting -Force -
Set the WinRM service to automatically start (en powershell)
powershell Set-Service -Name "WinRM" -StartupType Automatic Start-Service
⚠️ ADVERTENCIA: los playbooks contra equipos Windows pueden ser diferentes a los de GNU/Linux.
Bloquear conexiones externas¶
---
- name: Configure Windows Firewall to block all except local
hosts: windows_servers
tasks:
# 1. Allow Loopback Traffic (Localhost)
- name: Allow inbound loopback traffic
community.windows.win_firewall_rule:
name: "Allow Inbound Loopback"
localport: any
direction: in
protocol: any
remoteip: "127.0.0.1,::1"
action: allow
state: present
enabled: yes
- name: Allow outbound loopback traffic
community.windows.win_firewall_rule:
name: "Allow Outbound Loopback"
remoteport: any
direction: out
protocol: any
localip: "127.0.0.1,::1"
action: allow
state: present
enabled: yes
# 2. Allow Specific Local Management Ports (e.g., WinRM)
# Ensure these are allowed before the global block rules
- name: Allow WinRM Inbound from Management Subnet
community.windows.win_firewall_rule:
name: "Allow WinRM Inbound"
localport: 5985
direction: in
protocol: tcp
remoteip: "192.168.1.0/24" # Replace with your management subnet
action: allow
state: present
enabled: yes
# 3. Acceso a Moodle (178.255.108.43)
# Ensure these are allowed before the global block rules
- name: Allow moodle.educarex.es
community.windows.win_firewall_rule:
name: "Allow Moodle"
direction: out
protocol: tcp
remoteip: "178.255.108.43/32" # Replace with your management subnet
action: allow
state: present
enabled: yes
# 4. Block All Other Inbound Traffic
- name: Block all other inbound traffic
community.windows.win_firewall_rule:
name: "Block All Inbound"
localport: any
direction: in
protocol: any
remoteip: "any"
action: block
state: present
enabled: yes
# 5. Block All Other Outbound Traffic
- name: Block all other outbound traffic
community.windows.win_firewall_rule:
name: "Block All Outbound"
remoteport: any
direction: out
protocol: any
localip: "any"
action: block
state: present
enabled: yes
Fuentes:¶
- cheetsheet
- ansible-playbook
- ansible-playbook-options
- ansible-playbook-tags
- ansible-playbook-limit
- ansible-playbook-verbosity
- ansible-playbook-examples
- ansible-playbook-inventory
- ansible-playbook-connection
- ansible-playbook-become
- ansible-playbook-become-user
- ansible-playbook-become-method
- ansible-playbook-become-password