Ansible Mini Project Tutorial: Automating Host Updates and User Management
Goals
In this tutorial, I hope you will learn how to create an Ansible project to automate host updates, securely manage users using Ansible Vault, and log task results. I'll also cover best practices for organizing your Ansible project and securely managing credentials.
Pre-requisites
- Basic Knowledge of Ansible: Familiarity with SSH, Ansible playbooks, and YAML.
- Ansible Installed: Ensure Ansible is installed on your control machine. This can be your laptop. On WSL, for example, if you are a Windows user.
- SSH Keys for Authentication: It's best practice to use SSH keys when managing hosts with Ansible.
Generating and Using SSH Keys for Authentication
Before starting with Ansible, ensure SSH access is set up between your control machine and the hosts you're managing. It is recommended to use SSH keys instead of passwords for secure, passwordless authentication. You can generate and copy SSH keys using for example:
# Generate SSH keys (if you don't already have them)
ssh-keygen -t rsa -b 4096
# Copy the public key to the remote hosts (replace <user> and <host>)
ssh-copy-id <user>@<host>
Once keys are in place, Ansible will automatically use them for connecting to remote hosts.
Project Directory Structure
A well-organized project directory helps keep Ansible files modular, maintainable, and scalable. Here's a recommended directory structure for your Ansible project:
ansible_project/
│
├── inventory/
│ └── inventory.yml # Inventory file for hosts
├── group_vars/
│ └── all.yml # Common variables across all hosts
├── host_vars/
│ └── wazuh.yml # Host-specific variables for Wazuh host
├── vault.yml # Vaulted file to store sensitive data like passwords
└── update_hosts.yml # The playbook for updating hosts
Why This Structure?
- Inventory: Keeps track of the hosts and their groupings (e.g., based on OS).
- group_vars: Store variables that are common across groups of hosts.
- host_vars: Store variables that are unique to specific hosts.
- Vault: Securely stores sensitive information such as passwords.
- Playbook: Contains the tasks for updating hosts and managing users.
1. Inventory File
The inventory file defines the hosts and groups them based on their operating systems. This allows us to apply tasks specifically for each group.
Inventory (inventory.yml
) - [hostnames and IPs are not real]
all:
hosts:
aws-1:
ansible_host: 192.168.206.113
checkmk:
ansible_host: 192.168.49.28
homepage:
ansible_host: 192.168.135.51
main-wp:
ansible_host: 192.168.8.62
pi24:
ansible_host: 192.168.201.60
ansible_user: pi # assuming 'pi' is the sudo user for Raspbian
pihole2:
ansible_host: 192.168.102.7
pioffice:
ansible_host: 192.168.84.66
pve01:
ansible_host: 192.168.129.88
wazuh:
ansible_host: 192.168.62.85
ansible_user: almalinux_user # Replace with your actual user
ansible_become: true
ansible_become_method: su
children:
ubuntu:
hosts:
aws-1:
checkmk:
homepage:
main-wp:
pihole2:
pioffice:
raspbian:
hosts:
pi24:
debian:
hosts:
pve01:
almalinux:
hosts:
wazuh:
2. Playbook for Host Updates
This playbook updates all hosts based on their operating system. It handles privilege escalation (using sudo
for Ubuntu/Debian and su
for AlmaLinux) and uses apt
for Ubuntu/Debian and yum
for AlmaLinux.
Playbook (update_hosts.yml
)
---
- name: Update Ubuntu, Debian, and Raspbian hosts
hosts: ubuntu:debian:raspbian
become: true
vars_files:
- vault.yml # Loading Vaulted file
vars:
ansible_become_pass: "{{ vault_sudo_password }}" # Global sudo password
tasks:
- name: Update the package manager cache
ansible.builtin.apt:
update_cache: yes
cache_valid_time: 3600
- name: Upgrade all packages
ansible.builtin.apt:
upgrade: dist
- name: Ensure user '[your user here]' exists
ansible.builtin.user:
name: [user]
state: present
create_home: yes
shell: /bin/bash
- name: Update AlmaLinux host (wazuh)
hosts: wazuh
become: true
become_method: su
vars_files:
- vault.yml # Loading Vaulted file
vars:
ansible_become_pass: "{{ vault_wazuh_password }}" # Wazuh su password
tasks:
- name: Update the package manager cache
ansible.builtin.yum:
update_cache: yes
- name: Upgrade all packages
ansible.builtin.yum:
name: '*'
state: latest
- name: Ensure user '[your user here]' exists
ansible.builtin.user:
name: [your user here]
state: present
create_home: yes
shell: /bin/bash
3. Securing Credentials with Ansible Vault
For secure management of sudo passwords, I advise using Ansible Vault. Create a vault.yml
file to store the passwords securely.
Vaulted File (vault.yml
)
Encrypt the file using:
ansible-vault encrypt vault.yml
4. Running the Playbook
To run the playbook, use the following command:
ansible-playbook -i inventory/inventory.yml update_hosts.yml --ask-vault-pass --ask-become-pass
This will prompt you for the vault password (to decrypt vault.yml
) and for the sudo
password if necessary. However, once the passwords are on the created vault, you can omit the --ask-become-pass switch if you wish.
5. Logging the Results
You can log the output of the playbook execution to a file using the tee
command:
ansible-playbook -i inventory/inventory.yml update_hosts.yml --ask-vault-pass --ask-become-pass | tee playbook_output.txt
This will capture both the terminal output and save it to playbook_output.txt
.
Troubleshooting and Best Practices
SSH Timeouts: If SSH connections are timing out, you can set a timeout in the inventory file:
aws-1 ansible_ssh_timeout=60
Limit to a Single Host: If you suspect a specific host is causing issues, limit the playbook to that host:
ansible-playbook -i inventory/inventory.yml update_hosts.yml --ask-vault-pass --ask-become-pass --limit aws-1
Verbose Mode: If the playbook hangs or you need more detailed output, run the playbook in verbose mode with the -vvv
flag:
ansible-playbook -i inventory/inventory.yml update_hosts.yml --ask-vault-pass --ask-become-pass -vvv
This small and straightforward Ansible tutorial covers automating host updates, managing users, and securely handling credentials using Ansible Vault. For example, for your home lab.
Following the suggested project structure will help ensure your projects remain modular, maintainable, and scalable.