I started out using INI format for both inventory and secrets. Eventually I needed to use loops and switched the inventory file to YAML format. Now I need to use loops to set the secrets as well, so I want to switch my secrets file from INI to YAML. But ansible-playbook can't seem to read encrypted YAML files.
Here's a toy example of what works, creating a single file for each host. Playbook single_file_test.yaml:
---
- hosts: encrypted_hosts_test
tasks:
- name: create file
ansible.builtin.lineinfile:
path: "/home/vagrant/{{ file_name }}"
line: "{{ single_secret }}"
create: yes
Inventory file hosts.yaml:
all:
children:
encrypted_hosts_test:
hosts:
machine1:
file_name: "machine1_file"
machine2:
file_name: "machine2_file"
Encrypted secrets file hosts.vault:
[encrypted_hosts_test]
machine1 single_secret="123"
machine2 single_secret="234"
Command:
ansible-playbook --ask-vault-pass -i hosts.yaml -i hosts.vault single_file_test.yaml
Then here's the more complicated playbook I want, multi_file_test.yaml:
---
- hosts: encrypted_hosts_test
tasks:
- name: create multiple file tags
ansible.builtin.lineinfile:
path: "/home/vagrant/{{ item.key }}"
line: "{{ item.value.tag }}"
create: yes
loop: "{{ file_tags | dict2items }}"
- name: create multiple file secrets
ansible.builtin.lineinfile:
path: "/home/vagrant/{{ item.key }}"
line: "{{ item.value.secret }}"
create: yes
loop: "{{ file_secrets | dict2items }}"
Inventory file hosts.yaml:
all:
children:
encrypted_hosts_test:
hosts:
machine1:
file_tags:
fileA:
tag: "machine1_fileA_tag"
fileB:
tag: "machine1_fileB_tag"
machine2:
file_tags:
fileC:
tag: "machine1_fileC_tag"
fileD:
tag: "machine1_fileD_tag"
Since my secrets are not a fixed set of key/value pairs any more, I need a YAML secrets file. If I use cleartext, cleartext_secret.yaml:
all:
children:
encrypted_hosts_test:
hosts:
machine1:
file_secrets:
fileA:
secret: "234"
fileB:
secret: "345"
machine2:
file_secrets:
fileA:
secret: "567"
fileB:
secret: "789"
Command:
ansible-playbook -i hosts.yaml -i cleartext_secret.yaml multi_file_test.yaml
But if that same secret file is encrypted as hosts.yaml.vault, and I use this command:
ansible-playbook --ask-vault-pass -i hosts.yaml -i hosts.yaml.vault multi_file_test.yaml
I get this error:
[WARNING]: * Failed to parse /home/mat/Repository/ansible/pi/test/hosts.yaml.vault with ini plugin: Invalid host pattern 'all:' supplied, ending in ':' is not allowed, this
character is reserved to provide a port.
[WARNING]: Unable to parse /home/mat/Repository/ansible/pi/test/hosts.yaml.vault as an inventory source
I guess it's possible that this just doesn't work. But I find it weird that ansible can auto-detect INI or YAML when the files are unencrypted, but can only handle INI format if the files are encrypted. How can I tell ansible-playbook that this file is in YAML format?
This is on Ubuntu Jammy. Ansible version information:
ansible [core 2.15.8]
config file = /etc/ansible/ansible.cfg
configured module search path = ['/home/mat/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /usr/lib/python3/dist-packages/ansible
ansible collection location = /home/mat/.ansible/collections:/usr/share/ansible/collections
executable location = /usr/bin/ansible
python version = 3.10.12 (main, Nov 20 2023, 15:14:05) [GCC 11.4.0] (/usr/bin/python3)
jinja version = 3.0.3
libyaml = True
TL;DR
Ansible documentation does not explicitly state that the inventory files could be encrypted. It works with INI-formatted inventories, though, but I did not encounter any official example of that. Even if you try to force usage of YAML inventory plugin, Ansible will just issue a warning that it cannot parse that file as an inventory source.
More practical answer
You're trying to use an inventory file as a source for encrypted variables, but the general practice is to store the variables in
group_varsandhost_varsdirectories. It applies to secrets, too.Moreover, encrypting the whole inventory file will decrease the maintainability of your solution:
You could either follow the tip from the link above, or simplify the things a bit and store the files with secrets without referencing the encrypted variables in the plain ones - but you (and whoever else maintains the project) will need to know their names or be informed enough on how to find them.
If you want to store all your secrets within one file, you can store it separately or add it to
group_vars/alldirectory, create there a structure that will allow to iterate over the hosts, and adjust your playbook to use that structure. Note that in this case the secrets will be available for all hosts.If you still want to store the secrets within the inventory file, you can encrypt them independently using
ansible-vault encrypt_string YOUR_SECRET, which gives something like that (vault password is123here):This could be inserted as a value of a YAML key: