A Python library for unified secrets management across HashiCorp Vault, system keyring, and .env files.
Project description
credential-bridge
A unified Python library for secrets management across HashiCorp Vault, the OS system keyring, and .env files.
Table of Contents
- Features
- Installation
- Quick Start
- CLI Usage
- Backends
- Custom Backends
- Error Handling
- Environment Variables
- Development
- Contributing
- License
Features
- Three backends: HashiCorp Vault (KV-v2), OS system keyring, and
.envfiles SecretsManagerfacade: switch backends without changing application code- Plugin architecture: register third-party backends with one call
- Typed exceptions: granular hierarchy rooted at
CredentialBridgeError - Typer + Rich CLI:
cb,vault-cli,keyring-cli,env-cli, andrun-wizardentry points - Cross-platform: works on Linux, macOS, and Windows
Installation
pip install credential-bridge
# With dev dependencies
pip install "credential-bridge[dev]"
Quick Start
Using SecretsManager
from credential_bridge import SecretsManager
# HashiCorp Vault (set VAULT_ADDR env var first)
sm = SecretsManager("vault", vault_token="s.xxx")
sm.add_secret("myapp/database", {"user": "admin", "pass": "s3cr3t"})
secret = sm.get_secret("myapp/database")
# System keyring
sm = SecretsManager("keyring", service_name="myapp")
sm.add_secret("api_key", {"api_key": "sk-abc123"})
# .env file
sm = SecretsManager("env", path=".env")
sm.add_secret("DATABASE", {"DB_HOST": "localhost", "DB_PORT": "5432"})
Using backends directly
from credential_bridge import VaultBackend, KeyringBackend, EnvFileBackend
# Vault with AppRole auth
vault = VaultBackend(
vault_url="https://vault.example.com",
vault_role_id="<role-id>",
vault_secret_id="<secret-id>",
)
vault.add_secret("myapp/db", {"password": "hunter2"})
# Keyring
kr = KeyringBackend(service_name="myapp")
kr.add_secret("token", {"value": "sk-abc123"})
# .env file
env = EnvFileBackend(path=".env")
env.add_secret("DATABASE", {"DB_HOST": "localhost", "DB_PORT": "5432"})
CLI Usage
# Show all commands
cb --help
# Vault
cb vault add myapp/db --secret user=admin --secret pass=s3cr3t
cb vault get myapp/db
cb vault list
cb vault delete myapp/db
# Keyring
cb keyring add api_key --secret api_key=sk-abc123 --service-name myapp
cb keyring get api_key --service-name myapp
cb keyring delete api_key --service-name myapp
# .env file
cb env add DATABASE --secret DB_HOST=localhost --secret DB_PORT=5432
cb env get DB_HOST
cb env list
cb env delete DB_HOST
# Interactive wizard
cb wizard
Backends
| Backend | Best use case |
|---|---|
| Vault | Production workloads requiring audit logs, dynamic secrets, fine-grained policies, and centralized governance |
| Keyring | Developer machines and CI environments where OS-level credential storage is available |
| .env file | Local development, Docker Compose setups, and twelve-factor apps that read config from the environment |
Custom Backends
Implement BaseSecretBackend and register it with SecretsManager:
from credential_bridge import BaseSecretBackend, SecretsManager
from credential_bridge.manager import register_backend
from typing import Any, Dict, List
class RedisBackend(BaseSecretBackend):
backend_name = "redis" # required — omitting raises TypeError
def add_secret(self, name: str, secret: Dict[str, Any]) -> None: ...
def get_secret(self, name: str) -> Dict[str, Any]: ...
def update_secret(self, name: str, secret: Dict[str, Any]) -> None: ...
def delete_secret(self, name: str) -> None: ...
def list_secrets(self, path: str = "") -> List[str]: ...
register_backend("redis", RedisBackend)
sm = SecretsManager("redis", host="localhost", port=6379)
Error Handling
All exceptions inherit from CredentialBridgeError:
CredentialBridgeError
├── BackendError
│ ├── VaultError
│ │ ├── VaultAuthError — bad token / AppRole credentials
│ │ ├── VaultConnectionError — unreachable server
│ │ └── VaultSecretNotFoundError — secret path does not exist
│ ├── KeyringError
│ └── EnvFileError
│ ├── EnvFileNotFoundError — key not found
│ └── EnvFileKeyExistsError — add_secret called on existing key
├── BackendNotRegisteredError
└── ConfigurationError
from credential_bridge import (
SecretsManager,
VaultAuthError,
VaultConnectionError,
VaultSecretNotFoundError,
CredentialBridgeError,
)
sm = SecretsManager("vault", vault_token="s.xxx")
try:
secret = sm.get_secret("myapp/database")
except VaultSecretNotFoundError:
print("Secret path does not exist")
except VaultAuthError:
print("Authentication failed — check your token or AppRole credentials")
except VaultConnectionError:
print("Could not reach Vault — check VAULT_ADDR")
except CredentialBridgeError as exc:
print(f"Unexpected error: {exc}")
Environment Variables
| Variable | Description |
|---|---|
VAULT_ADDR |
Vault server URL (e.g. https://vault.example.com) |
VAULT_TOKEN |
Token for Token auth method |
VAULT_ROLE_ID |
Role ID for AppRole auth method |
VAULT_SECRET_ID |
Secret ID for AppRole auth method |
Resolution order for VaultBackend: constructor argument → environment variable → ~/.vault_config.json.
Development
# Install in editable mode with dev dependencies
pip install -e ".[dev]"
# Run unit tests
pytest tests/unit/
# Run integration tests (requires external services)
pytest tests/integration/ -m integration
# Lint
ruff check src/
# Type check
mypy src/
# Serve docs locally
mkdocs serve
Contributing
All contributions are welcome! Fork the repo, make your changes, and open a pull request. You can also open an issue with the label enhancement.
License
MIT — see LICENSE.txt for details.
Project details
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file credential_bridge-0.2.0.tar.gz.
File metadata
- Download URL: credential_bridge-0.2.0.tar.gz
- Upload date:
- Size: 1.0 MB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
9516546172fcc3efed545288943027048dbc5ef5133672d3bfc00accdf3cb65e
|
|
| MD5 |
23cff9eb700c15c1e53b40026ebe0db2
|
|
| BLAKE2b-256 |
e4539783848af599fd9903b1d7aaedd01f36b525542edb98d0f4cb582c9dd4df
|
File details
Details for the file credential_bridge-0.2.0-py3-none-any.whl.
File metadata
- Download URL: credential_bridge-0.2.0-py3-none-any.whl
- Upload date:
- Size: 29.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.11.15
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
15cfef1511228a22793b43d925f334834776ec9ca9ca381ba519357f0b1345e0
|
|
| MD5 |
eb734db9ff259a9c6b37847f03922f9a
|
|
| BLAKE2b-256 |
ffe8e5e66fa32e73b234b37c8b9dd53403569fed15563fda0b021e438f6f6781
|