#!/usr/bin/env python3 """ Generic API wrapper using Vault for dynamic token retrieval. Supports Vault paths where tokens are stored as keys under a category. Usage: python3 vault_api.py [header_type] [payload_file] """ import sys import json import urllib.request import ssl # Disable SSL verification for self-signed certs ssl._create_default_https_context = ssl._create_unverified_context VAULT_URL = "https://beavault.beawit.net:8200" def vault_auth(): """Authenticate to Vault and return client token.""" auth_data = json.dumps({ "role_id": "75d2dcfb-9c65-7f60-59b4-eee8c7f8dc0e", "secret_id": "6202b465-2f25-547c-ec07-f47cfc4dda3e" }).encode() req = urllib.request.Request( f"{VAULT_URL}/v1/auth/approle/login", data=auth_data, headers={"Content-Type": "application/json"}, method="POST" ) with urllib.request.urlopen(req) as resp: data = json.loads(resp.read()) return data["auth"]["client_token"] def get_service_token(vault_token, vault_path, token_key): """Retrieve specific token from Vault category.""" req = urllib.request.Request( f"{VAULT_URL}/v1/kv/data/{vault_path}", headers={"X-Vault-Token": vault_token} ) with urllib.request.urlopen(req) as resp: data = json.loads(resp.read()) secret_data = data["data"]["data"] if token_key in secret_data: return secret_data[token_key] else: available = list(secret_data.keys()) raise KeyError(f"Token key '{token_key}' not found. Available: {available}") def api_call(method, base_url, api_path, vault_path, token_key, header_type="Bearer", payload_file=None): """Make authenticated API call.""" vault_token = vault_auth() service_token = get_service_token(vault_token, vault_path, token_key) url = f"{base_url}{api_path}" headers = {"Content-Type": "application/json"} if header_type.lower() == "xc-token": headers["xc-token"] = service_token elif header_type.lower() in ["api-key", "x-api-key"]: headers["api-key"] = service_token elif header_type.lower() == "x-vault-token": headers["X-Vault-Token"] = service_token else: headers["Authorization"] = f"Bearer {service_token}" if method == "GET": req = urllib.request.Request(url, headers=headers) with urllib.request.urlopen(req) as resp: return json.loads(resp.read()) elif method in ["POST", "PATCH"]: data = None if payload_file: import os if os.path.exists(payload_file): with open(payload_file) as f: data = json.dumps(json.load(f)).encode() req = urllib.request.Request(url, data=data, headers=headers, method=method) with urllib.request.urlopen(req) as resp: return json.loads(resp.read()) else: raise ValueError(f"Unsupported method: {method}") def main(): if len(sys.argv) < 6: print("Usage: python3 vault_api.py [header_type] [payload_file]") print("Examples:") print(' python3 vault_api.py GET "https://grist.beawit.net" "/api/..." "api/integration" "grist"') print(' python3 vault_api.py GET "http://192.168.25.5:8080" "/api/..." "api/infrastructure" "nocodb-token" "xc-token"') print(' python3 vault_api.py GET "http://192.168.19.17:6333" "/collections" "api/infrastructure" "qdrant-api-key" "api-key"') sys.exit(1) method = sys.argv[1].upper() base_url = sys.argv[2] api_path = sys.argv[3] vault_path = sys.argv[4] token_key = sys.argv[5] header_type = sys.argv[6] if len(sys.argv) > 6 else "Bearer" payload_file = sys.argv[7] if len(sys.argv) > 7 else None result = api_call(method, base_url, api_path, vault_path, token_key, header_type, payload_file) print(json.dumps(result, indent=2)) if __name__ == "__main__": main()