Automating Server Management with Ansible

Simplify agent-less server management with Ansible using YAML.


What is Ansible?

Ansible is an open-source IT automation tool that simplifies the management and configuration of servers. It uses YAML for its playbook language, making it easy to read and write, and operates without needing an agent on the client machines, relying instead on SSH.

Key Concepts & Terms

  • Playbook: A YAML file containing a series of tasks to be executed on a managed node.
  • Inventory: A file listing all the managed nodes.
  • Task: A single action to be performed, like installing a package or running a command.
  • Module: Predefined units of work in Ansible, such as 'apt' for package management.
  • Role: A way to group tasks and handlers together to be reusable.

Setting Up Ansible on Ubuntu

Update Your Ubuntu VM

Ensure your system is up-to-date:

sudo apt update
sudo apt upgrade -y
sudo apt-get install qemu-guest-agent

Install Ansible

Add the Ansible PPA and install Ansible:

sudo apt update
sudo apt install software-properties-common -y
sudo add-apt-repository --yes --update ppa:ansible/ansible
sudo apt install ansible -y

Configure SSH Access

Ansible communicates with other servers via SSH. Ensure you have SSH access set up.

Generate an SSH key on your Ansible server if you don’t have one already:

ssh-keygen
ssh-add ~/.ssh/ssh_key

Ensure the user "ansible" exists on your target machine.

sudo adduser ansible
sudo usermod -aG sudo ansible

Copy SSH Key to Target Server:

scp ~/.ssh/ssh_key.pub ansible@<target_server_ip>:/tmp/ssh_key.pub
ssh ansible@<target_server_ip>
mkdir -p ~/.ssh
cat /tmp/ssh_key.pub >> ~/.ssh/authorized_keys
rm /tmp/ssh_key.pub
chmod 600 ~/.ssh/authorized_keys
chmod 700 ~/.ssh

Create an Inventory File

Create an inventory file to list your managed nodes:

mkdir ~/ansible-project
cd ~/ansible-project
nano inventory

Add the following content, replacing target_server_ip with the IP address of your target server:

[servers]
target_server_ip ansible_user=ansible

Test Connection

Test the connection to your managed node using Ansible:

ansible -i inventory servers -m ping

The correct reply to the ping module is "pong."

Example Playbook 1 - Automate Key Distribution

To avoid repeating the SSH key distribution steps for each server, create an Ansible playbook that is essentially a collection of commands. This playbook will add the SSH key to any machine listed in the inventory file, as long as the ansible user exists on the target machine.

Update the inventory file:

nano inventory

List the IP addresses of all servers:

[servers]
10.10.10.1
10.10.10.2
10.10.10.3
...

[servers:vars]
ansible_user=ansible
ansible_ssh_private_key_file=/root/.ssh/ssh_key
ansible_become=true
ansible_become_method=sudo
ansible_become_password=password

Create a playbook for SSH key distribution:

nano copy_ssh_key.yml

Add the following content:

---
- name: Distribute SSH key to target servers
  hosts: servers
  become: yes

  tasks:
    - name: Ensure the .ssh directory exists
      file:
        path: /home/ansible/.ssh
        state: directory
        owner: ansible
        group: ansible
        mode: '0700'
      become_user: ansible

    - name: Copy the SSH private key to the target server
      copy:
        src: /root/.ssh/ssh_key.pub
        dest: /home/ansible/.ssh/authorized_keys
        owner: ansible
        group: ansible
        mode: '0600'
      become_user: ansible

Run the playbook:

ansible-playbook -i inventory copy_ssh_key.yml

Example Playbook 2 - Automating System Updates

Create a playbook to automate system updates:

nano update.yml

Add the following content:

---
- name: Check connectivity and perform updates
  hosts: servers
  gather_facts: no

  tasks:
    - name: Ping all servers
      ping:

    - name: Update apt cache
      apt:
        update_cache: yes

    - name: Upgrade all packages
      apt:
        upgrade: dist

    - name: Check if upgrades were successful
      shell: dpkg -l
      register: result

    - name: Display upgrade result
      debug:
        var: result.stdout

Run the playbook:

ansible-playbook -i inventory update.yml

Example Playbook 3 - Automating QEMU Guest Agent Installation

As my VMs run on Proxmox, it makes sense to create a playbook for the QEMU Quest Agent installation:

nano qemu.yml

Add the following content:

---
- name: Ensure qemu-guest-agent is installed on servers
  hosts: servers
  become: true

  tasks:
    - name: Check if qemu-guest-agent is installed
      shell: dpkg -l | grep qemu-guest-agent
      register: qga_check
      ignore_errors: true

    - name: Install qemu-guest-agent if not installed
      command: sudo apt-get install -y qemu-guest-agent
      when: qga_check.rc != 0

Run the playbook:

ansible-playbook -i inventory qemu.yml

Example Playbook 4 - Automating MeshCentral Deployment

This is specific to my setup; I use MeshCentral to centrally manage my servers and MeshCentral relies on an agent running on the client. This playbook will deploy the MeshCentral agent to the target machines:

nano meshcentral.yml

Add the following content:

---
- name: Deploy MeshCentral if not already installed
  hosts: servers
  become: true
  vars:
    meshcentral_script_url: "https://yourmeshcentral.com/meshagents?script=1"
    meshcentral_server_url: "https://yourmeshcentral.com"
    meshcentral_key: "KsZT9sQmupL8xMMGy3vdF8KHnp7kvTWSxBy5jjQO@HgN4sZtpWu7kpwbRx43syhv"

  tasks:
    - name: Check if MeshAgent service exists
      shell: "systemctl list-unit-files | grep -q meshagent.service"
      register: meshagent_service_exists
      ignore_errors: true

    - name: Download the MeshCentral install script (direct)
      get_url:
        url: "{{ meshcentral_script_url }}"
        dest: /tmp/meshinstall.sh
      when: meshagent_service_exists.rc != 0

    - name: Download the MeshCentral install script (no proxy)
      command: "wget '{{ meshcentral_script_url }}' --no-proxy -O /tmp/meshinstall.sh"
      when: meshagent_service_exists.rc != 0
      ignore_errors: true

    - name: Make the MeshCentral install script executable
      file:
        path: /tmp/meshinstall.sh
        mode: '0755'
      when: meshagent_service_exists.rc != 0

    - name: Run the MeshCentral install script
      command: "/tmp/meshinstall.sh '{{ meshcentral_server_url }}' '{{ meshcentral_key }}'"
      environment:
        https_proxy: ""
      when: meshagent_service_exists.rc != 0

    - name: Ensure MeshCentral service is running
      service:
        name: meshcentral
        state: started
      when: meshagent_service_exists.rc != 0

Orchestrating Multiple Playbooks

Create a master playbook to run all the other playbooks in sequence:

nano master_playbook.yml

Add the following content:

---
import_playbook: copy_ssh_key.yml
import_playbook: update.yml
import_playbook: qemu.yml
import_playbook: meshcentral.yml

Finally, run the master playbook:

ansible-playbook -i inventory master_playbook.yml

We now have an initial setup to explore Ansible automations and automated server management.

Ansible's flexibility and scalability mean that you can extend these automations further, adding more tasks and refining your playbooks to meet the specific needs of your infrastructure. As you become more familiar with Ansible, you'll discover even more ways to leverage its capabilities, making your IT operations more robust and less error-prone.