Ansible best practices

Ansible is a really flexible and easy tool for automation. This is great because you can start using it quickly to automate your tasks. But, this also means there can be many different ways to set it up. That’s why having some tips and best practices is key to keep things running smoothly in the long run and save yourself time and effort. Without further ado, here are some considerations we’ve picked up from working with Ansible, Tower, and AWX for the last decade.

Request information
Contact us

Source code management

  • Use a Source code management system, preferably GIT
  • NEVER commit directly to MASTER/PRIMARY. Just don’t. No really, I mean it. The master branch should always contain working, tested, and functionally correct (as far as you are aware) code
  • Any development should be done against a branch, tested, reviewed, and only when proven to work, merged into the master branch.
  • Use version tags for your roles. Tag your roles when changing anything in those roles. This is not necessarily for yourself, but for anybody using your roles. They can then pin the roles to a specific version, and be assured that their code keeps working.
  • One GIT-repo per role. This makes it easy for others to include your roles in their playbooks
  • One or more separate repos for your playbooks. If you use more repos for your playbooks, you might want to split off your environments directory into a separate repo, so you will not have to maintain multiple sets of the same variables.

Directory structure
Just use the standard directory structure for your roles. You can easily create a new role structure with
ansible-galaxy init. For your playbooks and inventories you can use something like the following:

In this tree you see four 00-superglobal.yml files. The ones in the all directories are symlinks to the one in the environments directory. This gives you a way to set variables over all environments, without having to repeat them. group_1 and group_2 can be either files (they should end with .yml then) or directories containing yaml files.

I like to prefix the variable and inventoryfiles with a number, because ansible processes the files in the group_vars and inventories in lexicographical order. That way I can control the order of reading variables, which can come in handy if you use yaml-isms like references and pointers.

Playbook structure

If you have a lot of tasks in a playbook, you might want to think about converting the tasks in that playbook to a role. Do not set variables in a playbook (if you can avoid it). I’ll have a rant about that a little further down in this document. If you want to include other playbooks for execution in the playbook you’re working on, you should think about converting that other playbook into a role. Structure your playbook logically. If you don’t use the pre-tasks, roles, post-tasks way of working at least still order your playbook in a similar way.
If you need to install multiple packages on a yum based system, use the yum module instead of package, and use the list feature of the name part. This is a whole lot faster as opposed to using package with a list of packages. If you have a really big list of packages to install, you could think about using packages_fact and then do list difference to get the final list of packages to install.
Use the lowest level of permissions. Do not use a blanket become: yes in the top of your playbook. Yes, it is easy and convenient, but you also open yourself up to unintended privileged files and settings.

Role inclusion: Use roles/requirements.yml to include roles into your playbook. This eliminates duplication of code. Pin the version of the role to the version you want. Creating a roles/requirements.yml .
If you want to use playbooks with differing versions of the same role, then create a separate playbook directory for each playbook, and below that a separate roles/requirements.yml .

Collections inclusion: Use collections/requirements.yml to include roles into your playbook. Not all collections and modules are by default available for AWX (for example maven_artifact from community_general). You have to add the collections used to the requirements.yml file. AWX will download the collections automatically before running the playbook

Ansible.cfg configuration file
Ansible supports several sources for configuring its behavior, including an ini file named ansible.cfg. The ansible.cfg file is placed in directory above the ones containing the playbooks, roles and environments.

Copy to Clipboard


Host key checking is by default switched off in AWX. The check can be enabled for Ansible Tower as it is host based instead of container based. You will need to populate the known-hosts file for the tower application user, before you can use a host in tower.

Explanation of the settings
inventory = environments/sandbox Since in the example directory structure you have all environments in 1 project, you want to have the default environment pointed to the one that does the least harm when broken. In this way you must specify a more critical environment when running playbooks via the commandline.
host_key_checking = False This disables ssh hostkey checking. In AWX this is the default setting, because the actual execution of the playbooks is done on a separate execution container, which can be destroyed at any moment. Since also the ssh user can be different for each playbook there is no easy way to push a known_hosts file into awx. Also note that the known_hosts methods are only a good security measure if those are known from the beginning of the existence of the host. When using ansible from the command line on a host that is persistent (does exist for a longer time) I would urge that host_key_checking be set to true(==left out), which is the default setting for Ansible.
remote_tmp = /tmp/.ansible/tmp This can be done as an extra security measure. On initial installation of the host, create a separate temp directory with only permissions for the intended ansible remote user. This will ensure that a local attacker (to the target system) will not be able to get to the temporary data/scripts that ansible pushes onto the target, as long as that attacker does not have elevated privileges.
remote_user = ansible This is the default remote user used. This setting is overruled in AWX by the machine credential set in the playbook template.

Variable definitions
and their locations

Ansible is really flexible when it comes to variables and their precedence. This can set you up for a world of hurt. You can define variables in 22 levels in your playbooks. That doesn’t mean you have to use all of them. Minimize the number of locations you use.

I normally only use the following:

  • role/defaults
  • 00-superglobal
  • group_vars/all
  • group_vars/group
  • host_vars/host when I absolutely have no other option.
  • ansible-playbook -e when I need to be extra sure I want to do something (cleaning up a sandbox install prior to redeploying)

I have run into instances where I had to look through 10 different files all the while keeping in mind the precedence level and the fact that dictionaries were merged and not overwritten, to find where the variable changed to the unexpected result.

Variable naming

Use underscores for your longer variable names. Please don’t use CaMeLCaSiNg. Your variable name can be long enough to not have to resort to CaMeLCaSiNg in order to save on typing. It gives better readability as well.
According to the YAML 1.1 spec, simple keys can be up to 1024 characters in length.
Use clear variable names. In simple loops you can get away with using a single letter for the iterator, but readability improves drastically when you use clear and descriptive variable names.
If you choose to use another method of variable naming, please do so in a uniform way and use the same convention everywhere.

Lists

I like to use an extra indent level to define lists. This gives a bit better readability. Look at the example below. It may not look like a big difference, but when you use this for complex dictionaries it will become obvious.

Copy to Clipboard

YAML ANCHORS

Yaml has a neat feature of duplicating yaml configuration to reuse in different parts. By using the & syntax you can base the option from a previous task into the current:

Copy to Clipboard


By using this shorthand you can prevent duplication for common options like usernames, password, urls, namespaces, etc.

With over a decade of experience leveraging Ansible, Tower, and AWX to streamline and secure IT operations, our team has honed the art of automation to perfection. Our deep dive into best practices for Ansible reflects not just our expertise but our commitment to ensuring that your automation journey is both efficient and effective. As technology continues to evolve, the importance of security within automation cannot be overstated. Our team is at the forefront, integrating the latest industry trends and security measures to protect your infrastructure.

We understand that navigating the complexities of automation and ensuring your systems are both robust and secure can be daunting. That’s why we have a team of certified specialists ready to assist your organization in overcoming these challenges. Whether you’re looking to optimize your current setup, adopt new automation strategies, or ensure your systems are secure against the latest threats, we’re here to help.

Don’t let the complexity of automation slow you down. Leverage our expertise and let us guide you through every step of your automation journey. Contact us today to learn how we can help your organization stay ahead in an ever-evolving technological landscape.

Contact us

Share This Story, Choose Your Platform!