From 054996ee046c6f652bbdf00fc300b2fd20f0718a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ulrich=20Etil=C3=A9?= Date: Tue, 25 Feb 2025 11:49:26 +1100 Subject: [PATCH 1/2] feat: list secrets by categories --- plugins/module_utils/vaults.py | 61 ++++++++++++++++++++++++++++++++ plugins/modules/fetch_secrets.py | 26 +++++++++++--- 2 files changed, 83 insertions(+), 4 deletions(-) diff --git a/plugins/module_utils/vaults.py b/plugins/module_utils/vaults.py index f1b0d29..eb97626 100644 --- a/plugins/module_utils/vaults.py +++ b/plugins/module_utils/vaults.py @@ -34,6 +34,67 @@ def get_vault_entry(server_base_url, token, vault_id, entry_id): return response.json() except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") + +def get_vault_entry_from_name(server_base_url, token, vault_id, entry_name): + vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" + vault_headers = { + "Content-Type": "application/json", + "tokenId": token + } + + try: + response = requests.get(vault_url, headers=vault_headers, params={'name': entry_name}) + response.raise_for_status() + + return response.json() + except Exception as e: + raise Exception(f"An error occurred while getting a vault entry: {e}") + +def get_vault_entry_from_tag(server_base_url, token, vault_id, entry_tag): + vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" + vault_headers = { + "Content-Type": "application/json", + "tokenId": token + } + + try: + response = requests.get(vault_url, headers=vault_headers, params={'tag': entry_tag}) + response.raise_for_status() + + return response.json() + except Exception as e: + raise Exception(f"An error occurred while getting a vault entry: {e}") + +def get_vault_entry_from_path(server_base_url, token, vault_id, entry_path): + vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" + vault_headers = { + "Content-Type": "application/json", + "tokenId": token + } + + try: + response = requests.get(vault_url, headers=vault_headers, params={'path': entry_path}) + response.raise_for_status() + + return response.json() + except Exception as e: + raise Exception(f"An error occurred while getting a vault entry: {e}") + +def get_vault_entry_from_type(server_base_url, token, vault_id, entry_type): + vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" + vault_headers = { + "Content-Type": "application/json", + "tokenId": token + } + + try: + response = requests.get(vault_url, headers=vault_headers, params={'type': entry_type}) + response.raise_for_status() + + return response.json() + except Exception as e: + raise Exception(f"An error occurred while getting a vault entry: {e}") + def get_vault_entries(server_base_url, token, vault_id): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" diff --git a/plugins/modules/fetch_secrets.py b/plugins/modules/fetch_secrets.py index 2ba538a..b37cf7f 100644 --- a/plugins/modules/fetch_secrets.py +++ b/plugins/modules/fetch_secrets.py @@ -72,7 +72,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout -from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vaults, get_vault_entry, get_vault_entries +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vaults, get_vault_entry, get_vault_entry_from_name, get_vault_entry_from_tag, get_vault_entry_from_type, get_vault_entry_from_path, get_vault_entries import os import json import requests @@ -94,7 +94,10 @@ def run_module(): elements='dict', options=dict( secret_name=dict(type='str', required=False), - secret_id=dict(type='str', required=False) + secret_id=dict(type='str', required=False), + secret_path=dict(type='str', required=False), + secret_type=dict(type='str', required=False), + secret_tag=dict(type='str', required=False) ), required=False ) @@ -130,13 +133,28 @@ def run_module(): for secret in secrets: secret_name = secret.get('secret_name') secret_id = secret.get('secret_id') + secret_tag = secret.get('secret_tag') + secret_type = secret.get('secret_type') + secret_path = secret.get('secret_path') - if not secret_name and not secret_id: - module.fail_json(msg="Each secret must have either a secret_name or a secret_id", **result) + if not secret_name and not secret_id and not secret_tag and not secret_type and not secret_path: + module.fail_json(msg="Each secret must have either a secret_name or a secret_id or a secret_tag or a secret_type or a secret_path", **result) if secret_id: entry = get_vault_entry(server_base_url, token, vault_id, secret_id) fetched_secrets[secret_id] = entry['data'] + elif secret_name: + entry = get_vault_entry_from_name(server_base_url, token, vault_id, secret_name) + fetched_secrets[secret_name] = entry['data'] + elif secret_tag: + entry = get_vault_entry_from_tag(server_base_url, token, vault_id, secret_tag) + fetched_secrets[secret_tag] = entry['data'] + elif secret_path: + entry = get_vault_entry_from_path(server_base_url, token, vault_id, secret_path) + fetched_secrets[secret_path] = entry['data'] + elif secret_type: + entry = get_vault_entry_from_type(server_base_url, token, vault_id, secret_type) + fetched_secrets[secret_type] = entry['data'] else: entry = find_entry_by_name(entries, secret_name) if not entry: From 53bc03967c672e6844db98f68218cb7ca2646318 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Danny=20B=C3=A9dard?= Date: Wed, 26 Feb 2025 14:56:14 -0500 Subject: [PATCH 2/2] feat: implement get_sensible_value utility for fetching vault entries --- plugins/module_utils/utils.py | 29 +++++++++++++++++++++++++++++ plugins/module_utils/vaults.py | 2 +- plugins/modules/fetch_secrets.py | 30 +++++++++++------------------- 3 files changed, 41 insertions(+), 20 deletions(-) create mode 100644 plugins/module_utils/utils.py diff --git a/plugins/module_utils/utils.py b/plugins/module_utils/utils.py new file mode 100644 index 0000000..85f3cff --- /dev/null +++ b/plugins/module_utils/utils.py @@ -0,0 +1,29 @@ +from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vault_entry +import requests +import json + +def get_sensible_value(server_base_url, token, vault_id, entries): + fetched_secrets = {} + + if isinstance(entries, dict) and 'data' in entries: + entries = entries.get('data', []) + + if not isinstance(entries, list): + return {"error": f"Expected list of entries, got {type(entries).__name__}"} + + for secret in entries: + if not isinstance(secret, dict): + continue + + entry_name = secret.get('name') + if not entry_name or 'id' not in secret: + continue + + try: + entry = get_vault_entry(server_base_url, token, vault_id, secret['id']) + if isinstance(entry, dict) and 'data' in entry: + fetched_secrets[entry_name] = entry['data'] + except Exception as e: + fetched_secrets[entry_name] = {"error": str(e)} + + return fetched_secrets diff --git a/plugins/module_utils/vaults.py b/plugins/module_utils/vaults.py index eb97626..71c47d0 100644 --- a/plugins/module_utils/vaults.py +++ b/plugins/module_utils/vaults.py @@ -34,7 +34,7 @@ def get_vault_entry(server_base_url, token, vault_id, entry_id): return response.json() except Exception as e: raise Exception(f"An error occurred while getting a vault entry: {e}") - + def get_vault_entry_from_name(server_base_url, token, vault_id, entry_name): vault_url = f"{server_base_url}/api/v1/vault/{vault_id}/entry" vault_headers = { diff --git a/plugins/modules/fetch_secrets.py b/plugins/modules/fetch_secrets.py index b37cf7f..49f51b2 100644 --- a/plugins/modules/fetch_secrets.py +++ b/plugins/modules/fetch_secrets.py @@ -72,6 +72,7 @@ from ansible.module_utils.basic import AnsibleModule from ansible_collections.devolutions.dvls.plugins.module_utils.auth import login, logout +from ansible_collections.devolutions.dvls.plugins.module_utils.utils import get_sensible_value from ansible_collections.devolutions.dvls.plugins.module_utils.vaults import get_vaults, get_vault_entry, get_vault_entry_from_name, get_vault_entry_from_tag, get_vault_entry_from_type, get_vault_entry_from_path, get_vault_entries import os import json @@ -144,29 +145,20 @@ def run_module(): entry = get_vault_entry(server_base_url, token, vault_id, secret_id) fetched_secrets[secret_id] = entry['data'] elif secret_name: - entry = get_vault_entry_from_name(server_base_url, token, vault_id, secret_name) - fetched_secrets[secret_name] = entry['data'] + entries = get_vault_entry_from_name(server_base_url, token, vault_id, secret_name) + name_results = get_sensible_value(server_base_url, token, vault_id, entries) + fetched_secrets.update(name_results) elif secret_tag: - entry = get_vault_entry_from_tag(server_base_url, token, vault_id, secret_tag) - fetched_secrets[secret_tag] = entry['data'] + entries = get_vault_entry_from_tag(server_base_url, token, vault_id, secret_tag) + fetched_secrets = get_sensible_value(server_base_url, token, vault_id, entries) elif secret_path: - entry = get_vault_entry_from_path(server_base_url, token, vault_id, secret_path) - fetched_secrets[secret_path] = entry['data'] + entries = get_vault_entry_from_path(server_base_url, token, vault_id, secret_path) + fetched_secrets = get_sensible_value(server_base_url, token, vault_id, entries) elif secret_type: - entry = get_vault_entry_from_type(server_base_url, token, vault_id, secret_type) - fetched_secrets[secret_type] = entry['data'] - else: - entry = find_entry_by_name(entries, secret_name) - if not entry: - module.fail_json(msg=f"Secret '{secret_name}' not found", **result) - secret_id = entry['id'] - entry = get_vault_entry(server_base_url, token, vault_id, secret_id) - fetched_secrets[secret_name] = entry['data'] + entries = get_vault_entry_from_type(server_base_url, token, vault_id, secret_type) + fetched_secrets = get_sensible_value(server_base_url, token, vault_id, entries) else: - for secret in entries: - entry_name = secret['name'] - entry = get_vault_entry(server_base_url, token, vault_id, secret['id']) - fetched_secrets[entry_name] = entry['data'] + fetched_secrets = get_sensible_value(server_base_url, token, vault_id, entries) result = fetched_secrets