Chris Bugg

Developer, Tech-Engineer, Woodworker

(and other stuff)

3 - Ansible

(2021-04-12)

With the announcement today of Cloudflare Pages being finally available for everyone it might already be time to take another look at this sites backend, but we'll save that for another week!

This week it's all about Ansible and how I've come to use and rely on it for so many things that used to be manual and/or fragile tools and processes.

Quick overview: Ansible is an automation tool for IT and other stuff. It takes all those fragile bash scripts and complex configurations that are only stored on end-systems and brings them back to a central home that's easy to version-control, QA, and share. In my case I use it for my personal computers so there's very little version-control, QA, or sharing, but I do enjoy a lot of the other benefits (like cleaning up my bad habbits)!

How it works: Ansible is open source but is generally used as a 'binary' (pip package) that you run on the machine you use to connect-to/control whatever other machines you're managing. There's no agents so it relies on direct-access and lots of homogeneity in the machines to work best. Generally this works well with flat internal networks or cloud-based servers that all leave SSH open to the world and run the same sort of OS and services ("Cattle, not pets"). The 'binary' essentially handles running all those one-off (then multi-reused) bash-scripts (re-'written' in YAML mostly) and abstracts away a lot of the pain of running five commands against 20 servers, simultaneously.

Now that we're done with my (probably) poor interpretation of Ansible, lets see some examples where it's useful for me. I used to run about 20 servers of various purposes at-home (mostly on an old tower-turned-ESXi-host). This meant it was a nightmare to do simple things that need to happen frequently, like just running apt update on all the servers every week. This obviously led to a worse-overall situation, since many servers just sat there running out-dated or vulnerable software with inconsistent security setups. After too many years, I finally decided to explore some of the IaC solutions, and settled on Ansible. It was simple, open source, and had a large user-base (read: easier to find solutions to edge-cases).

Over the past several years I haven't really embraced Ansible full-on, but what it's done for me is make it not matter how many machines I'm managing along the way because it just...scales! Now-days the ESXi server is gone and I'm manageing a hand-full of Raspberry Pis and some cloud-based VPSs. While the number and type of servers have changed, the management is the same. Every week-or-so I open up a terminal, cd over into my ansible folder, and run ansible-playbook -i hosts.yml maintenance/update_all.yml. After a few minutes, the command completes and I have a warm-fuzzy feeling that everything's good, sans all the time it would take me to do that manually.

Let's break that down!

Sometimes it's not the regular things that Ansible helps a-lot with, but the once-in-a-while things! One of the biggest problems with new machines is doing all the 10-thousand little things to lock them down and make sure they're ready-to-go in terms of security. In the previous incantation of this blog I had a post that detailed every step I would/should take to secure a brand-new (post-install) machine. This was a very handy-reference, but in the end I still had to do all that configuring by-hand, and so it didn't always get done. Now I use Ansible, and every new machine is locked-down with a few keystrokes:

  1. Add the new machine to hosts.yml
  2. ansible-playbook -i hosts.yml fresh_box/setup_fresh_box.yml
  3. All machines (including the brand-new one) are secured!

One of the concepts Ansible tries hard to push is modularization. Each thing in it's place. This I find flows well into the new-machine problem. For each new-machine there isn't a list of static commands that need to happen, but rather a list of things that should change, and this is how it's represented in my Ansible files:

<setup_fresh_box.yml>
---
- import_playbook: setup_passwordless_sudo.yml
- import_playbook: disable_password_auth.yml
- import_playbook: setup_unattended_upgrades.yml
- import_playbook: setup_fail2ban.yml

Looking at setup_fresh_box.yml, it doesn't actually contain any tasks or anything! It's really just a reference to a bunch of other playbooks that each do their own thing, but together, setup a fresh box (server). Each of these seperate playbooks are totally independant and can be run at-will against any (or all) of the hosts.

Here's disable_password_auth.yml as an example of one of these playbooks:

<disable_password_auth.yml>
---
- name: Log in as sudo user to disable root
hosts: all
become: yes

tasks:
- name: Disable root login over SSH
lineinfile: dest=/etc/ssh/sshd_config regexp="^PermitRootLogin" line="PermitRootLogin no" state=present
notify:
- restart sshd

- name: Disable password login
lineinfile: dest=/etc/ssh/sshd_config regexp="^PasswordAuthentication" line="PasswordAuthentication no"
state=present
notify:
- restart sshd

handlers:
- name: restart sshd
service:
name: sshd
state: restarted

Looking at it now, it's probably mis-labeled a bit as it's doing more than just disabling password auth, but at least we're grouping the sshd changes into the same place. A new feature in this playbook is the concept of handlers. As we see at the bottom though, it's just a native Ansible feature to 'handle' services. In this case it handles the sshd service, and restarts it when we ask (after each of our changes). A more efficient approach might be to just do the restart once after both changes are made, but there's a lot more we could do with this!

So, Ansible is great! I'm very happy that I got into it when I did, and firmly beleive it's made my system management easier and faster. If you're dealing with managing more than a couple systems it's well worth the time to invest in researching these IaC options. Ansible isn't the only option and there are pros and cons to each. Find the one that will fit your work best!

Happy Hacking!
- Chris