Secure secret handler with cloud platform
Project description
noctivault
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 extragcp) - 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(orpip install 'noctivault[gcp]')
- Poetry:
poetry add noctivault- Local encrypted store:
poetry add "noctivault[local-enc]" - GCP remote:
poetry add google-cloud-secret-manager(orpoetry add "noctivault[gcp]")
Quickstart (Local, two‑file layout)
- 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
- 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
- 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.yamlandlocal.keyout of VCS
- Commit
- 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(orpoetry add "noctivault[gcp]") - Auth (ADC)
- Service account JSON:
export GOOGLE_APPLICATION_CREDENTIALS=/path/to/sa.json - Or:
gcloud auth application-default login
- Service account JSON:
- 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_pathNOCTIVAULT_LOCAL_KEY_FILE./local.keynext to.enc~/.config/noctivault/local.key
- Passphrase mode
settings.local_enc.passphraseorNOCTIVAULT_LOCAL_PASSPHRASE, or CLI--prompt
Schema Summary
- Mocks (
noctivault.local-store.yaml)- Top‑level
platform,gcp_project_idare required; entries inherit if omitted secret-mocks:name,value(str),version(int)
- Top‑level
- Refs (
noctivault.yaml)- Top‑level
platform,gcp_project_idrequired secret-refs: entries or grouped bykey/childrentype:str|int(defaultstr),version:latest|int
- Top‑level
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
.yamlandlocal.keyout of VCS (use.gitignore) - Key files should be mode 600; distribute via secure channels
- Keep plaintext
Troubleshooting
- CombinedConfigNotAllowedError: don’t mix mocks and refs in one file
- MissingLocalMockError / MissingRemoteSecretError: name/version/project mismatch
- TypeCastError: e.g.,
type=intfor 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 usesnoctivault.yamlonly
- Local:
- How to migrate from a single file?
- Move
secret-mocksintonoctivault.local-store.yaml, andsecret-refsintonoctivault.yaml
- Move
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
Release history Release notifications | RSS feed
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 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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
28d06321b439cad30729ed542db52854bb1308354d3f4ec647874d3a3be2aff5
|
|
| MD5 |
98980258e9b2139cdb34920e8e37be1e
|
|
| BLAKE2b-256 |
b7c30e8e681c95d24f2f493b9b88e126e699d11ed3d68ee407c14ef0ed399931
|
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
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7ac1378e6aed1f4571cc4a517cd3081463aa1626b5a9138e859921d1f143bc66
|
|
| MD5 |
726bb31aab0c1d0eedd84889d3618b0e
|
|
| BLAKE2b-256 |
c770b2ebef5dd6c8b24b52a7ce1b75a64a56a6fe6b6967df8d29d2401e006686
|