Description
SUMMARY
When I set token_path=~/.config/ansible
and create a .vault-token
file there, the vault_read
plugin can't find the token file. If I change token_path
to a hard-coded path like /home/my_user/.config/ansible
, the plugin can read it.
The reasoning for pointing to a folder under the users home dir is to minimize the risk of accidentally committing a users vault token. The default location for token_file
is ./.vault-token
, which will usually be added to your .gitignore
. But it is easy to mis-type the filename when you create it. If mis-typed, it is not covered by .gitignore
and can easily be added and committed by mistake.
I'm aware that .vault-token
will be picked up by default in my home dir, but to reduce clutter and follow the XDG Base Directory Specification I'd like to have it in ~/.config/ansible
instead.
ISSUE TYPE
- Bug Report
COMPONENT NAME
community.hashi_vault.vault_read
ANSIBLE VERSION
ansible [core 2.15.6]
config file = /home/michael_ingeman/code/ansible-main/ansible.cfg
configured module search path = ['/home/michael_ingeman/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/michael_ingeman/code/ansible-main/.venv/lib/python3.9/site-packages/ansible
ansible collection location = /home/michael_ingeman/code/ansible-main
executable location = /home/michael_ingeman/code/ansible-main/.venv/bin/ansible
python version = 3.9.5 (default, Nov 23 2021, 15:27:38) [GCC 9.3.0] (/home/michael_ingeman/code/ansible-main/.venv/bin/python)
jinja version = 3.1.2
libyaml = True
COLLECTION VERSION
Collection Version
--------------------- -------
community.hashi_vault 6.0.0
CONFIGURATION
COLLECTIONS_PATHS(/home/myuser/code/ansible_bug/ansible.cfg) = ['/home/myuser/code/ansible_bug/collections']
COLLECTIONS_SCAN_SYS_PATH(/home/myuser/code/ansible_bug/ansible.cfg) = False
CONFIG_FILE() = /home/myuser/code/ansible_bug/ansible.cfg
DEFAULT_ROLES_PATH(/home/myuser/code/ansible_bug/ansible.cfg) = ['/home/myuser/code/ansible_bug/roles']
[defaults]
callback_result_format = yaml
roles_path=./roles/
collections_path=./collections
collections_scan_sys_path=False
[hashi_vault_collection]
token_path=/home/myuser/.config/ansible
url=https://vault.mycompany
ca_cert=/etc/ssl/certs/ca-certificates.crt
OS / ENVIRONMENT
Linux michael-ws-linux 5.4.0-167-generic #184-Ubuntu SMP Tue Oct 31 09:21:49 UTC 2023 x86_64 x86_64 x86_64 GNU/Linux
STEPS TO REPRODUCE
Create a .vault-token
file in ~/.config/ansible
:
mkdir -p ~/.config/ansible
echo <my_token_value> > ~/.config/ansible/.vault-token
Configure ansible.cfg
:
[hashi_vault_collection]
token_path=~/.config/ansible
url=https://vault.mycompany
Then try to fetch a secret:
ansible 'localhost,' -m debug -a "msg={{ lookup('community.hashi_vault.vault_read', 'secret/my_vault_secret') }}"
Change the token_path
to a hardcoded value:
[hashi_vault_collection]
token_path=/home/myuser/.config/ansible
url=https://vault.mycompany
EXPECTED RESULTS
If the secret exists, the lookup should succeed.
localhost | SUCCESS =>
msg:
auth: null
data:
secret_value_1: My first secret value
secret_value_2: My second secret value
lease_duration: 8294400
lease_id: ''
renewable: false
request_id: 89d93467-1d29-029e-36c8-b37fg5ecb2a3
warnings: null
wrap_info: null
If the secret doesn't exist, the lookup will will of course fail, but with a message like this instead:
localhost | FAILED! =>
msg: 'An unhandled exception occurred while running the lookup plugin ''community.hashi_vault.vault_read''.
Error was a <class ''ansible.errors.AnsibleError''>, original message: Forbidden:
Permission Denied to path ''secret/my_vault_secret''.. Forbidden: Permission
Denied to path ''secret/my_vault_secret''.'
This is the current functionality when using a path that doesn't require expansion.
ACTUAL RESULTS
The lookup fails with the message No Vault Token specified or discovered.
ansible [core 2.15.6]
config file = /home/myuser/code/ansible-main/ansible.cfg
configured module search path = ['/home/myuser/.ansible/plugins/modules', '/usr/share/ansible/plugins/modules']
ansible python module location = /home/myuser/code/ansible-main/.venv/lib/python3.9/site-packages/ansible
ansible collection location = /home/myuser/code/ansible-main
executable location = /home/myuser/code/ansible-main/.venv/bin/ansible
python version = 3.9.5 (default, Nov 23 2021, 15:27:38) [GCC 9.3.0] (/home/myuser/code/ansible-main/.venv/bin/python)
jinja version = 3.1.2
libyaml = True
Using /home/myuser/code/ansible-main/ansible.cfg as config file
Reading vault password file: /home/myuser/.config/ansible/toolchestpoc.vaultpw
setting up inventory plugins
Loading collection ansible.builtin from
host_list declined parsing /home/myuser/code/ansible-main/hosts as it did not pass its verify_file() method
script declined parsing /home/myuser/code/ansible-main/hosts as it did not pass its verify_file() method
auto declined parsing /home/myuser/code/ansible-main/hosts as it did not pass its verify_file() method
Parsed /home/myuser/code/ansible-main/hosts inventory source with ini plugin
Loading callback plugin minimal of type stdout, v2.0 from /home/myuser/code/ansible-main/.venv/lib/python3.9/site-packages/ansible/plugins/callback/minimal.py
Attempting to use 'default' callback.
Skipping callback 'default', as we already have a stdout callback.
Attempting to use 'junit' callback.
Attempting to use 'minimal' callback.
Skipping callback 'minimal', as we already have a stdout callback.
Attempting to use 'oneline' callback.
Skipping callback 'oneline', as we already have a stdout callback.
Attempting to use 'tree' callback.
Loading collection community.hashi_vault from /home/myuser/code/ansible-main/ansible_collections/community/hashi_vault
exception during Jinja2 execution: Traceback (most recent call last):
File "/home/myuser/code/ansible-main/ansible_collections/community/hashi_vault/plugins/lookup/vault_read.py", line 121, in run
self.authenticator.validate()
File "/home/myuser/code/ansible-main/ansible_collections/community/hashi_vault/plugins/module_utils/_authenticator.py", line 98, in validate
method.validate(*args, **kwargs)
File "/home/myuser/code/ansible-main/ansible_collections/community/hashi_vault/plugins/module_utils/_auth_method_token.py", line 81, in validate
raise HashiVaultValueError("No Vault Token specified or discovered.")
ansible_collections.community.hashi_vault.plugins.module_utils._hashi_vault_common.HashiVaultValueError: No Vault Token specified or discovered.
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "/home/myuser/code/ansible-main/.venv/lib/python3.9/site-packages/ansible/template/__init__.py", line 868, in _lookup
ran = instance.run(loop_terms, variables=self._available_variables, **kwargs)
File "/home/myuser/code/ansible-main/ansible_collections/community/hashi_vault/plugins/lookup/vault_read.py", line 124, in run
raise AnsibleError(e)
ansible.errors.AnsibleError: No Vault Token specified or discovered.
localhost | FAILED! =>
msg: 'An unhandled exception occurred while running the lookup plugin ''community.hashi_vault.vault_read''.
Error was a <class ''ansible.errors.AnsibleError''>, original message: No Vault
Token specified or discovered.. No Vault Token specified or discovered.'
The problem seems to be that the plugin doesn't do tilde expansion when validating token_path
. The token_path
and token_file
values are simply path-joined and handed to read()
, which doesn't natively handle tilde expansion. That should be handled beforehand by calling os.path.expanduser()
and os.path.expandvars()
. That is how it is handled by the built-in plugins. Maybe we can use unfrackpath()
from ansible.utils.path
here as well?