4 min read

Ansible Mini Project Tutorial: Automating Host Updates and User Management

Ansible Mini Project Tutorial: Automating Host Updates and User Management
Generated with DALL-E

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)

vault_sudo_password: 'your_sudo_password'
vault_wazuh_password: 'your_wazuh_password'

the second line exists once the become is achieved via su and not sudo

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.