# Getting Started with Ansible for Patch Management

Date: 2025-11-03

Patch management is where good intentions collide with operational reality. Change windows, fragile shell loops, manual spreadsheet tracking—this is the state of most infrastructure teams before they standardise. Ansible changes the contract: one control node, agentless architecture, human-readable playbooks, and a single command to validate connectivity across every managed host before you touch a package.

<!--more-->

## Why Agentless Matters

Most automation tools require an agent running on every managed node—meaning agent version drift, additional port exposure, and another process to patch. Ansible uses SSH (or WinRM for Windows), which you already have open and already manage. There is nothing to install on targets, only on the control node.

---

## Control Node vs Managed Nodes

| Role | Description |
|---|---|
| **Control node** | Where Ansible runs. Requires Python 3.x. Linux or macOS native; Windows requires WSL2. |
| **Managed node** | Any host Ansible connects to. Requires Python 3.x and SSH access. No daemon. |

Ansible never daemonizes on managed nodes. Every run is a push from the control node outward.

---

## Installing Ansible

**Ubuntu / Debian:**

```shell
sudo apt update && sudo apt install -y ansible
```

**RHEL / CentOS / Fedora:**

```shell
sudo dnf install -y ansible
```

**macOS (Homebrew):**

```shell
brew install ansible
```

**Windows:** Ansible control is not natively supported on Windows. Use WSL2:

```shell
wsl --install
# Then follow the Ubuntu steps above inside the WSL2 shell
```

Verify the installation:

```shell
ansible --version
```

---

## SSH Key-Based Authentication

Ansible needs passwordless SSH access to managed nodes. Generate a dedicated key pair on the control node:

```shell
ssh-keygen -t ed25519 -C "ansible-control" -f ~/.ssh/ansible_id
```

Copy the public key to each managed node:

```shell
ssh-copy-id -i ~/.ssh/ansible_id.pub adminuser@TARGET_HOST
```

Test the connection manually before running any playbook:

```shell
ssh -i ~/.ssh/ansible_id adminuser@TARGET_HOST
```

---

## Inventory Basics

The inventory tells Ansible which hosts exist and how to reach them.

**INI format (`inventory.ini`):**

```ini
[webservers]
web01.example.com
web02.example.com

[dbservers]
db01.example.com

[all:vars]
ansible_user=ubuntu
ansible_ssh_private_key_file=~/.ssh/ansible_id
```

**YAML format (`inventory.yml`):**

```yaml
all:
  children:
    webservers:
      hosts:
        web01.example.com:
        web02.example.com:
    dbservers:
      hosts:
        db01.example.com:
  vars:
    ansible_user: ubuntu
    ansible_ssh_private_key_file: ~/.ssh/ansible_id
```

---

## Validate Connectivity Before You Patch

Never start a patching run without confirming every host responds. The `ping` module is not ICMP—it tests the full Ansible connection stack (SSH + Python):

```shell
ansible all -i inventory.ini -m ping
```

Expected output for a healthy host:

```
web01.example.com | SUCCESS => {
    "changed": false,
    "ping": "pong"
}
```

Any `UNREACHABLE` or `FAILED` here becomes a failed patch run. Fix connectivity first.

---

## First Playbook: Dry-Run Package Update

Create `update-check.yml`:

```yaml
---
- name: Dry-run package update on all hosts
  hosts: all
  become: true
  tasks:
    - name: Simulate package upgrade (apt)
      ansible.builtin.apt:
        upgrade: dist
        update_cache: true
      check_mode: true
      register: apt_result

    - name: Show what would change
      ansible.builtin.debug:
        var: apt_result
```

Run it with check mode and diff:

```shell
ansible-playbook -i inventory.ini update-check.yml --check --diff
```

`--check` simulates execution without making changes. `--diff` shows exactly which packages or files would be modified. Nothing touches the managed nodes until you remove `--check`.

---

**Next in the series:** [Must-Know Ansible Commands and Core Concepts](/ansible/devops/2025/11/06/ansible-commands-core-concepts.html) — ad-hoc commands, targeting patterns, privilege escalation, and running security-only updates from the command line.
