22

One of my roles has two different variable types. One is public (things like package versions and other benign information). These can be committed to SCM without a worry. It also requires some private information (such as API keys and other secret information). I'm using ansible-vault to encrypt secret information. My solution was to have vars/main.yaml for pulic, and vars/vault.yml for the encrypted private information.

I came across a problem and am uncertain what's the best practice or actual solution here. It seems that ansible only loads the vars/main.yml file. Naturally I do not want to encrypt the public information so I looked for solution. So far the only solution I came up with (suggested on IRC) is to create group_vars/all/vault.yml and prefix all variables with the role name. This works because ansible seems to recursively load everything under group_vars. This does work but seems organizationally incorrect because the variables are for a specific role and not "globally universally true". I also tried to put include: vars/vault.yml into vars/main.yml but that did not work.

Is there a proper way to do this?

ahawkins
  • 1,164
  • 1
  • 10
  • 15

3 Answers3

15

As very first task in your role you could have an include_vars task.

- include_vars: vault.yml

I have never tried it but according to the docs vault encrypted files can be used with the include_vars module.

The vault feature can encrypt any structured data file used by Ansible. This can include “group_vars/” or “host_vars/” inventory variables, variables loaded by “include_vars” or “vars_files” [...]

udondan
  • 57,263
  • 20
  • 190
  • 175
  • Do you agree with el_whictels answer below about such things should not be included in the role itself? – ahawkins Mar 24 '16 at 19:39
  • Not necessarily, it depends what the purpose of you role is. If you just use it to structure you rules I guess it is OK. Most probably this API key won't change and other people (as in outside of your project or company) won't use the role. If it was a general role to be used b others, then of course it wouldn't make sense to hardcode an API key in the role. But then it also wouldn't make sense to have a vault file in the role because anybody running it would need to know the password anyway, therefore can decode it. – udondan Mar 25 '16 at 05:24
  • Still, one could argue a role should not hold any implementation configuration at all. I am mostly on that train too. But again, if your main purpose is it to give your Ansible rules a structure, that's a good argument too. – udondan Mar 25 '16 at 05:30
  • @udondan If a role does the user management, it is natural to put the user definitions in the role and not somewhere else. Furthermore Ansible makes it almost impossible to put generic variables somewhere else, because `group_vars` override each other. http://serverfault.com/q/816126/92706 – ceving Jan 25 '17 at 13:19
  • @ceving I absolutely disagree on that. A role is a "role" and should not hold any implementation details. User definitions should be passed in some way to the role. This can be done by role parameters or, yes, `group_vars` are just a perfect example for small projects. If your role is free from user definitions I don't see why variable precedence is related to this. You should define your users in a single location (group_vars, host_vars, loaded from some external source like LDAP through a vars plugin,...) and nothing gets overridden. – udondan Jan 25 '17 at 14:34
  • @udondan Try to understand Ansible. It does not meet any of those OO patterns you have learned. Read the link I have quoted, understand the problem and delete you comment. – ceving Jan 25 '17 at 17:44
  • 1
    @ceving apart from the fact that udondan is the all-time number 1 contributor to the Ansible tag on SO...please consider generally entertaining the possibility that others might have a keener understanding than you. It's true that you should avoid declaring the same variable for groups with overlapping memberships, but this just means that you need to be careful when designing your inventory (including group vars). – um-FelixFrank May 31 '17 at 12:27
10

In case anyone is still trying to do that, instead of having the following structure:

vars/main.yml
vars/vault.yml

which won't work like you saw, you can instead organise your role like this:

vars/main/vars.yml
vars/main/vault.yml

Every vars file in the 'main' dir will be loaded by your role and you can encrypt your 'vault.yml' file only.

Chadys
  • 156
  • 2
  • 5
  • Works perfect. Because the role always need to decrypt de vault to see whether it will need those variables or not, you'll have to always pass `--ask-vault` flag to the `ansible-playbook` execution. – RicHincapie Sep 27 '21 at 15:10
6

Using Vault is a good idea. But you should not do this in a role.

The reason is, your role just declares a variable and its default. A playbook will use this or set its one value. If a variable is private, you should declare the variable as required, but without a default. So if anybody is using your role he must declare the variable in order to make it run.

One solution to ask for a required variable is a simple condition:

- fail: msg="Variable foo is required"
  when: foo is not defined

So the handling of vault encrypted variables is on playbook level an. It's an implementation detail which should not be in a role.

flxPeters
  • 1,476
  • 12
  • 21