Secrets
4 min read
Teploy has two secret providers. Start with the local one — it needs nothing extra to run. Move to OpenBao when you need scoped per-app credentials, database passwords that rotate themselves, or an audit trail of who accessed what.
Local (default)
teploy secret set API_KEY=secret123
teploy secret get API_KEY
teploy secret list # keys only, values masked
teploy secret rotate API_KEYValues are encrypted at rest with age (X25519), decrypted by the CLI on demand, and merged into the same env file your app reads — the difference from a plain teploy env set value is at-rest encryption and audit-friendly access, not a different delivery mechanism. No server-side process to run.
Reference a local secret from teploy.yml:
env:
API_KEY: secret:API_KEYOpenBao
OpenBao is the open-source Vault-compatible secrets manager Teploy integrates as a first-class accessory. Everything lives under teploy secret --provider openbao (or the OpenBao-only subcommands below, which don't need the flag).
Setup
teploy secret setup --provider openbaoIdempotent: deploys OpenBao on the private teploy network, initializes it, and auto-unseals with a generated seal key stored in the local age secret store — never plaintext on disk. teploy secret status reports seal/init state. --restart is always reboot-safe: the container comes back initialized and unsealed with zero intervention.
Off-box key isolation, for teams that don't want the unseal key anywhere near the app server:
teploy secret setup --provider openbao --seal awskms \
--kms-key-id <id> --kms-region us-east-1
teploy secret setup --provider openbao --seal transit \
--transit-address https://unsealer.internal:8200 --transit-token <token>Seal credentials ride a 0600 host env file, never the world-readable OpenBao config.
High availability — a multi-node Raft quorum instead of a single file-storage node:
teploy secret setup --provider openbao --replicas 3Each node auto-unseals with the shared seal and joins the leader via retry_join. The primary keeps the base container name (so every downstream command targets it unchanged); followers get -N suffixes. Killing a node still under quorum keeps serving reads and writes; the killed node auto-unseals and rejoins on restart.
Put, get, list
teploy secret put --provider openbao db password=s3cr3t host=pg.internal
teploy secret get --provider openbao db
teploy secret list --provider openbaoput accepts multiple key=value fields in one secret (db#password, db#host, ...). These commands use the OpenBao root token — an admin path, distinct from what your app is scoped to access (see AppRole below).
Deploy-time injection
env:
DB_PASSWORD: "secret:db#password" # -> secret/<app>/db, key "password"
API_KEY: "secret:apikey" # #field defaults to "value" for a flat secretEvery app gets its own least-privilege AppRole and policy on teploy secret setup: read-only on secret/<app>/*, nothing else, no write access even to its own secrets. secret:name#field references are resolved once per deploy and merged into the same secret-safe env file local secrets use — never argv, never plaintext on disk.
Dynamic database credentials
Short-lived, auto-revoked credentials instead of a static password:
teploy secret db setup --provider openbao # against a Postgres accessory
teploy secret db creds --provider openbao # fetch on demandFor zero app-side plumbing, run an Agent sidecar that auths as the app's own AppRole, templates the credentials to a shared volume, and auto-renews the lease before it expires:
secret:
provider: openbao
agent: trueThe app reads DB_USER/DB_PASS from /vault/secrets/db.env, mounted read-only. The credentials connect to Postgres as a per-lease, revocable user — not the root account.
Static-role rotation
For a fixed app account whose password should still rotate automatically, rather than minting a new user per request:
teploy secret db static-role --username appuser --rotation-period 24h --admin-pass <admin-pw>
teploy secret db static-creds --username appuserOpenBao takes over the existing appuser row and rotates its password on the given period — the account identity stays the same, only the credential changes.
Audit streaming
teploy secret audit ship --provider openbao # one-shot
teploy secret audit enable --provider openbao # continuous, via a systemd timer
teploy secret audit disable --provider openbaoEvery secret access — read, write, dynamic credential issue — streams into teploy-observe's tamper-evident, hash-chained audit trail (see audit: in the config reference). enable installs a timer that runs ship --local on an interval; it's idempotent, so re-running never double-ships an event.
Coming from teploy vault
Earlier releases used a standalone teploy vault command. It's been folded into teploy secret --provider openbao for consistency with the other provider-abstracted commands (network --provider, etc.) — same capabilities, vault:name#key references become secret:name#field, and the vault: config block becomes secret: { provider, accessory, agent }.