Skip to main content

Secure secret handler with cloud platform

Project description

noctivault

PyPI Python Versions License: MIT Wheel

Noctivault loads secrets from cloud Secret Managers into process memory without going through environment variables. Values are masked by default, and configuration is clearly separated from execution.

  • Safe by default: in‑memory resolution, masked string representations
  • Operational clarity: two files — references (refs) and mock values (mocks)
  • Flexible: local encrypted store and remote (GCP) fetch supported

Why Noctivault

  • Avoids env‑vars; secrets are handled via explicit API calls
  • Lighter than Vault/SOPS for Python apps; DX focused
  • Two‑file split clarifies “what to use” (refs) vs “where values come from” (mocks)
  • Commit .yaml.enc, distribute the key separately for safer, reproducible setups

Support & Requirements

  • Python: >= 3.10
  • Local encrypted store: extra local-enc (cryptography, argon2-cffi)
  • Remote (GCP): google-cloud-secret-manager (also available as extra gcp)
  • Remote platform support: Google only for now (AWS/Azure on roadmap)

Install

  • pip:
    • pip install noctivault
    • Local encrypted store: pip install 'noctivault[local-enc]'
    • GCP remote: pip install google-cloud-secret-manager (or pip install 'noctivault[gcp]')
  • Poetry:
    • poetry add noctivault
    • Local encrypted store: poetry add "noctivault[local-enc]"
    • GCP remote: poetry add google-cloud-secret-manager (or poetry add "noctivault[gcp]")

Quickstart (Local, two‑file layout)

  1. Mocks (plaintext or encrypted source): noctivault.local-store.yaml
platform: google
gcp_project_id: demo

secret-mocks:
  - name: db-password
    value: s3cr3t
    version: 2
  - name: db-port
    value: "5432"
    version: 1
  1. Refs (plaintext; do not encrypt): noctivault.yaml
platform: google
gcp_project_id: demo

secret-refs:
  - key: database
    children:
      - cast: password
        ref: db-password
        version: latest
        type: str
      - cast: port
        ref: db-port
        version: 1
        type: int
  1. Encrypt mocks (recommended)
  • Generate key: noctivault key gen (default ~/.config/noctivault/local.key, chmod 600)
  • Create encrypted file: noctivault local seal . --key-file ~/.config/noctivault/local.key --rm-plain
    • Commit .yaml.enc; keep plaintext .yaml and local.key out of VCS
  1. Load (Python)
from noctivault import NoctivaultSettings
import noctivault

nv = noctivault.noctivault(settings=NoctivaultSettings(source="local"))
secrets = nv.load(local_store_path="./")  # prefers .enc; falls back to .yaml

print(secrets.database.password)        # -> ***
print(secrets.database.password.get())  # -> "s3cr3t"
print(secrets.database.port.get())      # -> 5432

Restore plaintext from .enc when needed:

noctivault local unseal noctivault.local-store.yaml.enc --key-file ~/.config/noctivault/local.key > noctivault.local-store.yaml

Quickstart (Remote, GCP)

Prereqs

  • Dependency: poetry add google-cloud-secret-manager (or poetry add "noctivault[gcp]")
  • Auth (ADC)
    • Service account JSON: export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json
    • Or: gcloud auth application-default login
  • Permission: roles/secretmanager.secretAccessor, etc.

noctivault.yaml (refs only)

platform: google
gcp_project_id: my-gcp-project

secret-refs:
  - key: database
    children:
      - cast: password
        ref: db-password
        version: latest
        type: str

Load (Python)

from noctivault import NoctivaultSettings
import noctivault

nv = noctivault.noctivault(settings=NoctivaultSettings(source="remote"))
secrets = nv.load(local_store_path=".")  # reads ./noctivault.yaml
print(secrets.database.password)         # -> ***
print(secrets.database.password.get())   # -> UTF-8 string from GCP

Common errors and fixes

  • MissingDependencyError: add google-cloud-secret-manager
  • AuthorizationError: fix ADC/permissions
  • MissingRemoteSecretError: check project/ref/version in noctivault.yaml

CLI

  • Key: noctivault key gen [--out PATH]
  • Seal: noctivault local seal <dir|file> (--key-file PATH | --passphrase PW | --prompt) [--out PATH] [--rm-plain] [--force]
  • Unseal: noctivault local unseal <enc_file> (--key-file PATH | --passphrase PW | --prompt)
  • Verify: noctivault local verify <enc_file> (--key-file PATH | --passphrase PW | --prompt)

When a directory is given, .yaml.enc is preferred; otherwise falls back to .yaml. You can pass file paths directly as well.

Settings & Precedence

  • NoctivaultSettings(source="local"|"remote")
  • Local encrypted store key material (in this order):
    • settings.local_enc.key_file_path
    • NOCTIVAULT_LOCAL_KEY_FILE
    • ./local.key next to .enc
    • ~/.config/noctivault/local.key
  • Passphrase mode
    • settings.local_enc.passphrase or NOCTIVAULT_LOCAL_PASSPHRASE, or CLI --prompt

Schema Summary

  • Mocks (noctivault.local-store.yaml)
    • Top‑level platform, gcp_project_id are required; entries inherit if omitted
    • secret-mocks: name, value (str), version (int)
  • Refs (noctivault.yaml)
    • Top‑level platform, gcp_project_id required
    • secret-refs: entries or grouped by key/children
    • type: str|int (default str), version: latest|int

See docs/api.md for full details.

Security

  • Masked by default (repr/str -> ***); call .get() to reveal
  • Encryption format (NVLE1)
    • AES‑256‑GCM; Argon2id (for passphrase); KDF params stored in header
    • Tamper detection via GCM tag; invalid tag -> decryption failure
  • Operational guidance
    • Keep plaintext .yaml and local.key out of VCS (use .gitignore)
    • Key files should be mode 600; distribute via secure channels

Troubleshooting

  • CombinedConfigNotAllowedError: don’t mix mocks and refs in one file
  • MissingLocalMockError / MissingRemoteSecretError: name/version/project mismatch
  • TypeCastError: e.g., type=int for non‑numeric values
  • InvalidEncHeaderError / DecryptError: bad header / wrong key
  • RemoteUnavailableError: transient GCP issues; retry later

FAQ

  • Why two files?
    • Separate intent (refs) from value sources (mocks); simpler reviews and switching between local/remote
  • Which file is preferred?
    • Local: .yaml.enc > .yaml; Remote uses noctivault.yaml only
  • How to migrate from a single file?
    • Move secret-mocks into noctivault.local-store.yaml, and secret-refs into noctivault.yaml

Roadmap

  • Remote drivers for AWS/Azure
  • Cache/TTL/force‑refresh
  • Pluggable providers; HMAC option for display_hash

Contributing

  • PRs welcome. Please keep Ruff/Mypy clean and maintain high test coverage
  • For security reports, please use responsible disclosure

License

MIT — see LICENSE.

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

noctivault-0.1.0.tar.gz (18.3 kB view details)

Uploaded Source

Built Distribution

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

noctivault-0.1.0-py3-none-any.whl (20.3 kB view details)

Uploaded Python 3

File details

Details for the file noctivault-0.1.0.tar.gz.

File metadata

  • Download URL: noctivault-0.1.0.tar.gz
  • Upload date:
  • Size: 18.3 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for noctivault-0.1.0.tar.gz
Algorithm Hash digest
SHA256 28d06321b439cad30729ed542db52854bb1308354d3f4ec647874d3a3be2aff5
MD5 98980258e9b2139cdb34920e8e37be1e
BLAKE2b-256 b7c30e8e681c95d24f2f493b9b88e126e699d11ed3d68ee407c14ef0ed399931

See more details on using hashes here.

File details

Details for the file noctivault-0.1.0-py3-none-any.whl.

File metadata

  • Download URL: noctivault-0.1.0-py3-none-any.whl
  • Upload date:
  • Size: 20.3 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.11.10

File hashes

Hashes for noctivault-0.1.0-py3-none-any.whl
Algorithm Hash digest
SHA256 7ac1378e6aed1f4571cc4a517cd3081463aa1626b5a9138e859921d1f143bc66
MD5 726bb31aab0c1d0eedd84889d3618b0e
BLAKE2b-256 c770b2ebef5dd6c8b24b52a7ce1b75a64a56a6fe6b6967df8d29d2401e006686

See more details on using hashes here.

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