Skip to main content

OpenBao/Vault secrets source for pydantic-settings with AppRole authentication

Project description

openbao-pydantic-settings-adapter

PyPI version Python 3.11+ License: PolyForm Noncommercial

OpenBao/Vault secrets source for pydantic-settings with AppRole authentication, automatic token renewal, and graceful fallback to environment variables.

Features

  • AppRole Authentication - Secure machine-to-machine authentication
  • Automatic Token Renewal - TokenManager handles TTL-based token lifecycle
  • Namespace Support - Multi-tenant isolation (team/project level)
  • Two-Path Architecture - Separate secrets and supersecrets paths with deep merge
  • SecretStr Validation - Enforces SecretStr for supersecrets to prevent log exposure
  • Graceful Degradation - Falls back to .env when OpenBao is unavailable
  • Type Safety - Full type annotations with py.typed marker (PEP 561)

Installation

pip install openbao-pydantic-settings-adapter

Note: The import name is openbao_settings:

from openbao_settings import OpenBaoSettingsSource

Quick Start

from pydantic import SecretStr
from pydantic_settings import BaseSettings, PydanticBaseSettingsSource

from openbao_settings import OpenBaoSettingsSource


class Settings(BaseSettings):
    database_url: str
    api_key: SecretStr  # Fields from supersecrets MUST use SecretStr

    @classmethod
    def settings_customise_sources(
        cls,
        settings_cls: type[BaseSettings],
        init_settings: PydanticBaseSettingsSource,
        env_settings: PydanticBaseSettingsSource,
        dotenv_settings: PydanticBaseSettingsSource,
        file_secret_settings: PydanticBaseSettingsSource,
    ) -> tuple[PydanticBaseSettingsSource, ...]:
        return (
            init_settings,
            OpenBaoSettingsSource(settings_cls),  # OpenBao has priority
            env_settings,
            dotenv_settings,
        )


settings = Settings()

Configuration

Configure via environment variables:

Variable Description Required
BAO_ADDR OpenBao server URL (e.g., http://localhost:8200) Yes
BAO_SECRET_PATH Base path to secrets (e.g., myapp) Yes
BAO_APPROLE_ROLE_ID AppRole Role ID Yes
BAO_APPROLE_SECRET_ID AppRole Secret ID Yes
BAO_NAMESPACE OpenBao namespace for multi-tenant isolation No
BAO_MOUNT_POINT KV engine mount point (default: kv) No
BAO_TIMEOUT Connection timeout in seconds (default: 30) No
BAO_TOKEN_RENEWAL_THRESHOLD When to renew token (default: 0.75 = at 75% of TTL) No

For Docker/Kubernetes, you can use file-based credentials:

  • BAO_APPROLE_ROLE_ID_FILE
  • BAO_APPROLE_SECRET_ID_FILE
  • BAO_NAMESPACE_FILE

Secrets Architecture

The library reads from two paths and merges them:

kv/{BAO_SECRET_PATH}/secrets      - Regular secrets (developers can view/edit)
kv/{BAO_SECRET_PATH}/supersecrets - Sensitive secrets (admin only)

Important: Fields loaded from supersecrets MUST use SecretStr type annotation. The library validates this at runtime and raises SecurityMisconfigurationError if violated.

# Wrong - will raise SecurityMisconfigurationError
class Settings(BaseSettings):
    api_key: str  # Loaded from supersecrets but not SecretStr!

# Correct
class Settings(BaseSettings):
    api_key: SecretStr  # Properly protected

Token Lifecycle

TokenManager automatically handles token renewal:

  1. Caches tokens per (namespace, role_id) combination
  2. Renews at 75% of TTL (configurable via BAO_TOKEN_RENEWAL_THRESHOLD)
  3. Thread-safe for multi-threaded applications
  4. Graceful degradation if OpenBao becomes unavailable
from openbao_settings import TokenManager

# Manual token invalidation (e.g., for credential rotation)
TokenManager().invalidate()

# Check token health
TokenManager().is_healthy(namespace="myapp", role_id="...")

Diagnostics

Track where settings were loaded from:

from openbao_settings import get_last_source_info, SourceInfo

info: SourceInfo = get_last_source_info()
print(info.status)              # True if loaded from OpenBao
print(info.source)              # "openbao" or "env"
print(info.details)             # Human-readable description
print(info.openbao_keys_loaded) # Number of keys from OpenBao
print(info.timestamp)           # When the check was performed

API Reference

Classes

  • OpenBaoSettingsSource - Main settings source for pydantic-settings
  • OpenBaoClient - Low-level HTTP client for OpenBao API
  • TokenManager - Singleton for token lifecycle management

Exceptions

  • OpenBaoError - Base exception for all OpenBao errors
  • InvalidPathError - Path not found (HTTP 404)
  • InvalidRequestError - Invalid request/credentials (HTTP 400)
  • ForbiddenError - Access denied (HTTP 403)
  • InvalidResponseError - Unexpected API response structure
  • SecurityMisconfigurationError - SecretStr validation failed

Response Models

  • AppRoleLoginResponse - AppRole authentication response
  • KvV2ReadResponse - KV v2 read response
  • SourceInfo - Settings source diagnostic info

Development

Syncing with Remote

# Fetch commits and tags
git pull origin main --tags

# If local branch is behind remote
git reset --hard origin/main

Verify sync status

git log --oneline origin/main -5
git diff origin/main

CI/CD

The pipeline consists of two stages:

  1. auto_tag — on push to main, reads __version__ from __init__.py and automatically creates a tag (if it doesn't exist)

  2. mirror_to_github — on tag creation, mirrors the repository to GitHub (removing .gitlab-ci.yml)

Release flow

  1. Update __version__ in src/openbao_settings/__init__.py
  2. Push to main
  3. CI creates tag → mirrors to GitHub → publishes to PyPI

Versioning

This project follows Semantic Versioning (MAJOR.MINOR.PATCH):

  • PATCH — bug fixes, documentation, metadata
  • MINOR — new features (backwards compatible)
  • MAJOR — breaking changes

License

This project is licensed under the PolyForm Noncommercial License 1.0.0.

You may use this software for noncommercial purposes only.

See LICENSE for the full license text, or visit polyformproject.org.

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

openbao_pydantic_settings_adapter-1.0.4.tar.gz (18.6 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

File details

Details for the file openbao_pydantic_settings_adapter-1.0.4.tar.gz.

File metadata

File hashes

Hashes for openbao_pydantic_settings_adapter-1.0.4.tar.gz
Algorithm Hash digest
SHA256 a726bc470ea0e4dff5389cbbc464f219e03b63f7533a4c58a1ab847765de446d
MD5 c88c6a3b0c2275d1ca0cce61f6593058
BLAKE2b-256 9e5f55b119938d1da928bc628ad4e03484dee50a65d9c9797ced8db1c0b8fbf5

See more details on using hashes here.

Provenance

The following attestation bundles were made for openbao_pydantic_settings_adapter-1.0.4.tar.gz:

Publisher: publish.yml on itstandart/openbao-pydantic-settings-adapter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file openbao_pydantic_settings_adapter-1.0.4-py3-none-any.whl.

File metadata

File hashes

Hashes for openbao_pydantic_settings_adapter-1.0.4-py3-none-any.whl
Algorithm Hash digest
SHA256 1e29889aca1f280144e765de2545bcdfeb4222bfebe5577de3f844dce04f50d8
MD5 193674ff6da7042bd2a978ac7a4178f0
BLAKE2b-256 8441fee6036f07f5e7e0f8a116aefe3c42e1c3d6c2dadc189038cf642bc7b5c5

See more details on using hashes here.

Provenance

The following attestation bundles were made for openbao_pydantic_settings_adapter-1.0.4-py3-none-any.whl:

Publisher: publish.yml on itstandart/openbao-pydantic-settings-adapter

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page