My Profile Photo

AndrewCz


Using liberty-minded opensource tools, and using them well


Cleaning up Ansible Playbooks and Roles


I need to start publishing my ansible playbooks and their associated roles to the world so that I can get a broader test base for them as well as to be able to show prospective employers and/or partners my previous work. This means that I need to get rid of any PII and other secrets. Also, I should be able to clean up the scripts as well - make them look presentable.


Clone the code. Here's the repo.

Vault and .vpass

For setting up the vault, Ansible’s documentation puts it quite simply. It is stated that the best way is just to add another layer of indirection at the variable file level. This can be achieved by having the sensitive variables reference encrypted ones. For instance a variable my_secret could reference vault_my_variable. That second variable would be contained within the vault file that resides next to the original.

Vault Password

It’s the password of passwords. However I set it up, I have to be able to en/decrypt that file using a password. When I run ansible-playbook I have a flag that I can pass. That flag is --ask-vault-pass. Then I would have to put in the password for every run.

Another way to pass the password to a run would be to use a vault password file. That would be with the flag --vault-password-file which would point to the password file. Either that, or I can also set the env var ANSIBLE_VAULT_PASSWORD_FILE. That way Ansible will automatically search for the password in that file.

That file can also be a python script. The plaintext version should be a string stored as a single line in the file. But the script can do anything, including prompt for input. For now, I think that a plaintext password file will do just fine, but I will definitely put that in keepassx.

Vault locations

So there are three locations. Like I mentioned somewhere else, I want my roles to be able to stand on their own, so I wanted a vault to be included inside of the role itself, but also have one in the playbook level as well.

Role level

There’s a milestone on github to have every .yml file that underneath the role’s defaults folder be automatically included in the variables. Unfortunately, using include_vars supersedes the group_vars entries, so that wouldn’t work. I guess I’ll wait until 2.3 comes out and hopefully they’ll have something worked out. I’d personally much prefer it to be the vars/ directory as that would make more sense just namespace-wise, but as long as they can give me an option I won’t complain.

Playbook level

This is a bit easier because of the way Ansible parses the file structure for the inventory. So in each group_vars directory, there is now a folder called all that holds both main.yml and vault.yml that both get parsed at execution.

Both of these setups are completely agnostic as to what role is being called from which playbook. It took me awhile to come up with this system, but I think it’s the most robust that could be available to me. I’ll tell you what - my skeleton for my plays and my roles is getting beefier by the day.

Synchronize vs Copy

Sync

Not delete files - rsync no delete Does overwrite changed files

Copy

  • No de-duplication
  • Slower

    Variables

I mean, you don’t want to have them make too many decisions. But you do want to give them some.

Roles

Roles should have two sections:

  • CHANGE ME
  • SANE DEFAULTS

When playbooks copy the variables from here, they should only include the CHANGE ME by default. They can of course choose to include other variables as needed.

Playbooks

All vars are placed in the group_vars/ directory.

All

The directory all should have a file named main.yml that has one section per role that’s in the site.yml play under “Roles in Common”. There’s also going to be another file under there that’s vault.yml. This is encrypted, obviously with all the sensitive info.

Per-play

Each play should have it’s own file. It too should have one section per role that’s in it’s play.

Defaults

Sensible Defaults

Sensible defaults should stay in their roles, and not be mentioned in the playbook. In the role itself? Sure, fine. But not in the playbook.

Personal Defaults

This is the naming scheme of things, etc. Hard to tell from sensible defaults, but consider this. A blog wouldn’t want to have a subheader of “smacz’s blog” when someone else was forking it, now would they. That’s a personal default. This should definitely be included in the playbook.

Authenticator Defaults

Easy - these go in the playbook’s vault.

Special defaults

These use the when_defined dictate that ansible has.

Rename

In my repo, one can see that I have a directory that is named Raw that contains a skeleton of both a role as well as a playbook. The names of these have been changed to “blank” with varying degrees of capitalization. If there is a file or if inside of a file there is the word ‘blank’ that’s in an actual role, that’s just because I haven’t changed it from the skeleton setup. I’ll want to find out all of that.

README.md

Hosts naming

Singular and Simple

site.yml and the plays/ directory

During the time I was developing the playbook that was directing my mailserver rollout, I came across a few architectural glitches, as well as a few shortcuts. I have found that the easiest way to think of a playbook is that it does nothing except contribute to the layers of indirection.

For one, there should never be any internal plays, as they are all almost always re-usable, and should therefore be put in a role, as it would be more modular that way.

Secondly, site.yml can itself contain plays. For instance:

- name: Tasks segregated at the role level
  hosts: all
  remote_user: root

  roles:
  - common
  - iptables
  - postfix-server
  - mysql

This was for my mailserver. Before I included any other playbooks, I set up the roles that were in common for all of the hosts, and it worked! For instance, they might all have different iptables configurations, but that is dealt with at the variable level, and since they all need to address it during their setup, I might as well have them all run at once.

That’s another advantage to this, initially, all of the hosts run at once. If I only did include’s that pointed to my plays, and they were for individual or separate groups of hosts, they each run iptables on their first go-round. That means that I’d be stuck waiting for iptables task that would take three (in this case with three machines) times as long to complete. This way, I can send it to them in parallel and only spend (iptables * time) amount of time instead of 3 * (iptables * time). If that makes sense. IDK. Trust me on this one. It’s waaaay better.

Next, the plays/ directory can be populated with plays that define roles that are only for certain hosts within that playbook. If you reallY think about it, if there’s only one type of server, that means that all tasks are tasks in common. Therefore there really needs be no plays/ directory or at least no plays. At that point, the site.yml can contain all of the roles.

requirements.yml

Never really used it. Will probably have to once I start using ansible-galaxy. Got rid of it in all of my playbooks, but it’s still in my skeleton.

roles

Once again, since I’m not using ansible galaxy, I might as well not use roles, external or internal. Internal roles are located in their own special directory, and external roles are gotten from ansible-galaxy, and I don’t use it!

Parenthesis showing which task handler is running and [X/X] notation as well

Cross-pollination

In squid I just copy-pasted the httpd SSL config task and didn’t even change the variable names.

Nextcloud

It needs an upgrade to the latest version of PHP and the latest version of nextcloud.


References: