mirror of
https://github.com/tiennm99/litellm.git
synced 2026-08-02 08:21:53 +00:00
feat: Add configurable mount name and path prefix for HashiCorp Vault (#16253)
- Add HCP_VAULT_MOUNT_NAME env var to override default 'secret' mount
- Add HCP_VAULT_PATH_PREFIX env var to add prefix to secret paths
- Update get_url() method to construct URLs with configurable mount and prefix
- Add test coverage for custom mount names and path prefixes
- Maintain backward compatibility with existing configurations
This allows users to configure Vault paths like:
- Custom mount: {VAULT_ADDR}/v1/{MOUNT_NAME}/data/{SECRET}
- With prefix: {VAULT_ADDR}/v1/secret/data/{PREFIX}/{SECRET}
- Both: {VAULT_ADDR}/v1/{MOUNT_NAME}/data/{PREFIX}/{SECRET}
Resolves issue where mount name was hardcoded and path prefixes weren't supported.
This commit is contained in:
@@ -24,8 +24,13 @@ class HashicorpSecretManager(BaseSecretManager):
|
||||
# Vault-specific config
|
||||
self.vault_addr = os.getenv("HCP_VAULT_ADDR", "http://127.0.0.1:8200")
|
||||
self.vault_token = os.getenv("HCP_VAULT_TOKEN", "")
|
||||
# If your KV engine is mounted somewhere other than "secret", adjust here:
|
||||
# Vault namespace (for X-Vault-Namespace header)
|
||||
self.vault_namespace = os.getenv("HCP_VAULT_NAMESPACE", None)
|
||||
# KV engine mount name (default: "secret")
|
||||
# If your KV engine is mounted somewhere other than "secret", set HCP_VAULT_MOUNT_NAME
|
||||
self.vault_mount_name = os.getenv("HCP_VAULT_MOUNT_NAME", "secret")
|
||||
# Optional path prefix for secrets (e.g., "myapp" -> secret/data/myapp/{secret_name})
|
||||
self.vault_path_prefix = os.getenv("HCP_VAULT_PATH_PREFIX", None)
|
||||
|
||||
# Optional config for TLS cert auth
|
||||
self.tls_cert_path = os.getenv("HCP_VAULT_CLIENT_CERT", "")
|
||||
@@ -118,10 +123,24 @@ class HashicorpSecretManager(BaseSecretManager):
|
||||
return {"name": self.vault_cert_role}
|
||||
|
||||
def get_url(self, secret_name: str) -> str:
|
||||
"""
|
||||
Constructs the Vault URL for KV v2 secrets.
|
||||
|
||||
Format: {VAULT_ADDR}/v1/{NAMESPACE}/{MOUNT_NAME}/data/{PATH_PREFIX}/{SECRET_NAME}
|
||||
|
||||
Examples:
|
||||
- Default: http://127.0.0.1:8200/v1/secret/data/mykey
|
||||
- With namespace: http://127.0.0.1:8200/v1/mynamespace/secret/data/mykey
|
||||
- With custom mount: http://127.0.0.1:8200/v1/kv/data/mykey
|
||||
- With path prefix: http://127.0.0.1:8200/v1/secret/data/myapp/mykey
|
||||
"""
|
||||
_url = f"{self.vault_addr}/v1/"
|
||||
if self.vault_namespace:
|
||||
_url += f"{self.vault_namespace}/"
|
||||
_url += f"secret/data/{secret_name}"
|
||||
_url += f"{self.vault_mount_name}/data/"
|
||||
if self.vault_path_prefix:
|
||||
_url += f"{self.vault_path_prefix}/"
|
||||
_url += secret_name
|
||||
return _url
|
||||
|
||||
def _get_request_headers(self) -> dict:
|
||||
|
||||
@@ -17,6 +17,10 @@ from litellm._uuid import uuid
|
||||
|
||||
verbose_logger.setLevel(logging.DEBUG)
|
||||
|
||||
# Minimal setup for module-level instantiation
|
||||
import litellm.proxy.proxy_server
|
||||
litellm.proxy.proxy_server.premium_user = True
|
||||
|
||||
from litellm.secret_managers.hashicorp_secret_manager import HashicorpSecretManager
|
||||
|
||||
hashicorp_secret_manager = HashicorpSecretManager()
|
||||
@@ -211,3 +215,41 @@ def test_hashicorp_secret_manager_tls_cert_auth(monkeypatch):
|
||||
|
||||
# Verify the token was cached
|
||||
assert test_manager.cache.get_cache("hcp_vault_token") == "test-client-token-12345"
|
||||
|
||||
|
||||
def test_hashicorp_custom_mount_and_prefix():
|
||||
"""Test URL construction with custom mount name and path prefix using get_url method."""
|
||||
# Save original values
|
||||
original_mount = hashicorp_secret_manager.vault_mount_name
|
||||
original_prefix = hashicorp_secret_manager.vault_path_prefix
|
||||
original_namespace = hashicorp_secret_manager.vault_namespace
|
||||
|
||||
try:
|
||||
# Test that existing manager uses default "secret" mount and namespace "admin"
|
||||
url = hashicorp_secret_manager.get_url("my-secret")
|
||||
assert "/secret/data/" in url
|
||||
assert "my-secret" in url
|
||||
|
||||
# Test custom mount name
|
||||
hashicorp_secret_manager.vault_mount_name = "kv"
|
||||
hashicorp_secret_manager.vault_path_prefix = None
|
||||
hashicorp_secret_manager.vault_namespace = None
|
||||
url = hashicorp_secret_manager.get_url("my-secret")
|
||||
assert url == f"{hashicorp_secret_manager.vault_addr}/v1/kv/data/my-secret"
|
||||
|
||||
# Test path prefix
|
||||
hashicorp_secret_manager.vault_mount_name = "secret"
|
||||
hashicorp_secret_manager.vault_path_prefix = "myapp"
|
||||
url = hashicorp_secret_manager.get_url("my-secret")
|
||||
assert url == f"{hashicorp_secret_manager.vault_addr}/v1/secret/data/myapp/my-secret"
|
||||
|
||||
# Test both custom mount and prefix
|
||||
hashicorp_secret_manager.vault_mount_name = "kv"
|
||||
hashicorp_secret_manager.vault_path_prefix = "production"
|
||||
url = hashicorp_secret_manager.get_url("my-secret")
|
||||
assert url == f"{hashicorp_secret_manager.vault_addr}/v1/kv/data/production/my-secret"
|
||||
finally:
|
||||
# Restore original values
|
||||
hashicorp_secret_manager.vault_mount_name = original_mount
|
||||
hashicorp_secret_manager.vault_path_prefix = original_prefix
|
||||
hashicorp_secret_manager.vault_namespace = original_namespace
|
||||
|
||||
Reference in New Issue
Block a user