Proxmox inventory plugin: get secrets from vault.yml

Hello,

I use the proxmox inventory plugin and would like to use the secrets from group_vars/all for the api secret. I use the follwing folder structure:

inventory/
├── group_vars
│   └── all
│       ├── vars.yml
│       └── vault.yml
├── host_vars
│   ├── ...
├── inventory.proxmox.yml
├── inventory.yml
└── z_inventory.constructed.yml

Now I would like to access the variable “token_secret” from group_vars/all/vault.yml inside the “inventory.proxmox.yml”, but unfortunately it’s not available.
Any hints how to do that? I would like to have a “single source of truth”…

Thanks a lot!
Thomas

Hi there!

Good question, I did some testing, I couldn’t make it work with either of the ones below:

password: "{{ my_var }}"

Results in:

[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with auto plugin:
'proxmox_readonly_password' is undefined

Using lookups didn’t fix it either

password: "{{ query('ansible.builtin.vars', 'proxmox_readonly_password') }}"

Results in:

[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with auto plugin: No variable found with
this name: proxmox_readonly_password

I tried with a lookup as well as a query using Vaultwarden/Bitwarden to see if it’s reachable when it’s outside the inventory, but also nothing :pensive_face:

[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with auto plugin: 'NoneType' object is
not subscriptable

I also tested it with the Foreman plugin, same results, makes me think that Ansible just can’t do it :sweat_smile: unless I’m missing something…

Inventory plugins cannot access anything in host_vars and group_vars, since these are only loaded after the inventory is loaded.

Generally inventory plugins don’t support templating, unless the plugin explicitly templates something. Some inventory plugins allow templating for things like usernames and passwords, but usually not for everything. The proxmox inventory plugin templates the following inputs: url, user, password, token_id, token_secret.

What you can do is use the ansible.builtin.unvault lookup to explicitly load the file, apply the ansible.builtin.from_yaml filter, and then access the right field. Something like this:

password: >-
  (lookup("ansible.builtin.unvault", "group_vars/all/vault.yml") | ansible.builtin.from_yaml).token_secret

(You might need to add the | string filter before | from_yaml.)

2 Likes

First of all, @felixfontein Legend for thinking of even more clever tricks to try! :wink:

I gave it a shot with what you suggested, but Ansible doesn’t seem to like it :frowning:

I made a file with my credentials in it and then vaulted the whole thing (I normally only use encrypt_string:

inventory/group_vars/all/proxmox_creds.yml:

user: 'blahblah'
password: 'secret_blahblah'

And I added the following in my inventory for the password:

user: 'search@pve'  # I'm only testing the password right now
password: >-
  (lookup("ansible.builtin.unvault", "group_vars/all/proxmox_creds.yml") | string | ansible.builtin.from_yaml).password

I also tried adding inventory to the path, no dice.

So, these files:

./inventory/group_vars/all/proxmox_creds.yml
./inventory/proxmox.yml

When asked to generate an inventory, produce:

ansible-inventory --graph
[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with auto plugin: 'NoneType' object is
not subscriptable
[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with yaml plugin: Plugin configuration
YAML file, not YAML inventory
[WARNING]:  * Failed to parse /home/ansible/projects/test/inventory/proxmox.yml with ini plugin: Invalid host pattern
'---' supplied, '---' is normally a sign this is a YAML file.
[WARNING]: Unable to parse /home/ansible/projects/test/inventory/proxmox.yml as an inventory source
@all:
<snip>

It’s almost correct.

  1. Missing template brackets
  2. File lookup not relative to inventory directory, need to prepend inventory/

So following does the trick for me:

token_secret: >-
  {{ (lookup("ansible.builtin.unvault", "inventory/group_vars/all/vault.yml") | ansible.builtin.from_yaml).token_secret }}
2 Likes

Ooops, the {{ / }} were pretty obvious :smiley:

1 Like

That did the trick! So, to summarize:

  1. Create a file with the variables you need, e.g.:
---
proxmox_readonly_username: 'search@pve'
proxmox_readonly_password: 'blabla'
  1. Encrypt the file with Ansible Vault
  2. Update the inventory to use the string suggested by @felixfontein with the fixes from @kristianheljas
---
plugin: 'community.general.proxmox'
url: 'https://pve.example.nl:8006'
user: "{{ (lookup('ansible.builtin.unvault', 'inventory/group_vars/all/proxmox.yml') | ansible.builtin.from_yaml).proxmox_readonly_username }}"
password: "{{ (lookup('ansible.builtin.unvault', 'inventory/group_vars/all/proxmox.yml') | ansible.builtin.from_yaml).proxmox_readonly_password }}"
validate_certs: true
want_facts: true
want_proxmox_nodes_ansible_host: false
  1. Bingo

And this also works with other lookups! Below is the one for Bitwarden:

---
plugin: 'community.general.proxmox'
url: 'https://pve.example.nl:8006'
user: "{{ lookup('community.general.bitwarden', 'Proxmox - search@pve', field='username')[0] }}"
password: "{{ lookup('community.general.bitwarden', 'Proxmox - search@pve', field='password')[0] }}"
validate_certs: true                                                                  
want_facts: true                                                                                      
want_proxmox_nodes_ansible_host: false

Not a question I asked, but grateful nonetheless! I just made my homelab codebase a touch better today :wink:

3 Likes

Works perfect :slight_smile: Thank you all!