m5p3nc3r

Repeatable builds

I wanted to ensure that anything I did throughout this project was repeatable. I didn't want to simply install a base OS, install and configure the packages I need and then forget about it. I needed something scriptable that I could use to automatically re-creaete any part of the system in case of failure, or if I needed to add an additional host.

After searching for a solution, the obvious choice seemed to be Ansible. It was a platform that I had researched during lockdown after watching a YouTube series Ansible 101 by Jeff Geerling. This seemed like an ideal opportunity to put my learning into practice.

Ansible?

So, what is Ansible? Ansible is an open-source automation tool, used for infrastructure management tasks such as configuration management, application deployment, intraservice orchestration, and provisioning. It is a simple automation language that describes an IT application infrastructure in Ansible Playbooks. These playbooks can then be run to build and configure the infrastructure. Because Ansible is a scriptable language, it ensures that the builds are repeatable without manual intervention.

The playbook

The playbook I used to build the host serving this site is available on my GitHub repository ansible-playbooks. It makes use of third party roles to install some of the required features (docker, nginx, certbot). The playbook itself is fairly self-explanatory, and if you want to learn more about how to configure and use Ansible yourself, I would recommend that you watch the Ansible 101 series by Jeff Geerling highlightd above.

Dealing with secrets

There are a couple of points in the Ansible script where I need to deal with secrets. These are for access keys to assets like private github container registries, and a shared secret for accessing the WatchTower update endpoint. As I need the script to be repeatable, I want to store the secrets along with the Ansible script so they can be accessed when running the script

- name: Log into ghcf.io registry
      community.general.docker_login:
        registry: ghcr.io
        username: "{{ secrets.GITHUB_ACTOR }}"
        password: "{{ secrets.GITHUB_TOKEN }}"

The details are stored in a local file secrets.enc in the form:

secrets:
  GITHUB_ACTOR: "<your github username>"
  GITHUB_TOGEN: "<your github PAT token>"

The contents of this file are then encrypted using ansible-vault:

ansible-vault encrypt secrets.enc

The contents of the secrets.enc file are now encryped (see below), and in a pre-quantum world, are safe to store alongside the Ansible scripts in the public GitHub repository.

$ANSIBLE_VAULT;1.1;AES256
32616464303463613337383265366162653864343765633437366264653731393564323364346561
6262303637326666613636313536613935326532303061320a663166333064633961643663616562
...

To make use of the secrets when executing the playbook, simply run the following command:

ansible-playbook -i inventory -e @secrets.enc --ask-vault-pass frontend.yaml

This will load and decrypt the secrets.enc file and make the secrets available to the playbook without ever leaving the file un-encryped on the host machine.

Conclusion

Using Ansible to manage the building of the website infrastructure has enabled me to achieve the key objective of repeatability. I can now build the whole of the hosting infrastructure with a single command, enabling me to deploy the required system configuration to any host with minimal effort.