Now that we have ansible working, we can do some housekeeping of the server. I took most of the playbook(with some modifications) from @jigarwala from his repo at github. He has also written a blog on the topic on medium
The kind of tasks that come under this are:
- Update the apt package cache listing and installing some useful packages
- Setting the hostname of server
- Setting the locale & timezone
- Tightening the SSH Server(disabling root login, disabling password login, enabling strict mode, etc)
- Adding a user, giving him superuser access
Terraform already does add a user & grant ssh, but I am repeating that in ansible so that all servers, including those not terraformed, have the same user in the end.
The changes as usual is in this pull request, and the final code base is this.
Ansible Folder Structure
The Configuration of ansible can be broadly split into 3 sections
- Inventory – The list of servers that ansible provisions
- Roles – A self-contained list of instructions & assets that can configure a functionality or aspect of the server
- Playbooks – Mapping which roles to apply on which subset of the Inventory
All Ansible configuration is usually done with YAML syntax, except the inventory file which is usually done INI format.
The simplest example of an inventory file just contains the ip address of the server, like so
But inventories can be hierarchical, with aliases to servers and more tags to specifically configure each server. nsible has very clear documentation at Inventory Intro.
In our case, all that really matters here is that we are specifying 2 global variables.
[all:vars] username=edwin github_ssh_key_url=https://github.com/edwinclement08.keys
This is later used within ansible configuration to set the user in the server and the ssh authorized_keys. Make sure to replace those if you are using my repository.
Right now, the playbook is really quite simple and just refers to
common role that we defined. The file
ansible/playbooks/provision.yml is as follows
--- - name: provision cloud resources hosts: all roles: - role: common become: true tags: - role-common
All Ansible tasks have a name, which hold no significance to the machine. It is purely used for logging, and in the rare occasion, start executing at a given task
hosts map to the keys in Inventory. In this case,
all refers to all the entries in the inventory, as you might have guessed.
Roles is an array which refers to the roles present in
ansible/roles directory and the order in which to execute them.
become allows the task to use privilege escalation(using sudo, or other native implementation).
Tags are just names that can be used to execute subsets of tasks within the playbook and like
name, have no inherent meaning to ansible.
Roles contain the meat of the automation config. The folder structure has a pre-defined list of sub-folders out of at least one should be present. Ansible, again contains the full documentation on each of these folder here.
Out of the above, we will be using
|Tasks||Main list of tasks that the role executes|
|Templates||Any template files that are to be copied over to the server|
|Handlers||A special type of task that can be triggered to run after tasks(for example to reboot the system after upgrade)|
In all the folders,
main.yml will be the file that is picked up by ansible. Any other file in the folder must be included. In tasks folder, other files can be included with
Explaining the structure like this will not fully make it clear how this all comes together.
I highly recommend that you clone the repo and view the
ansible/roles/common folder. Its likely that by the time you read this, there are changes that make the code unrecognizable. In that case, use this
git checkout 82daffbbb9af07a2ade4e83e56cf31f8bb113a5e
Or, you can choose to view the pull request online.
In the next chapter, I will be installing tailscale, and configure it to connect all my instances together.
2 thoughts on “Ansible: Automating server initialization tasks”