Skip to content

Local YAML Provider

The local provider stores secrets in a YAML file. Plaintext is the default for development; optional at-rest encryption is available via skret keys.

environments:
dev:
provider: local
file: ./.secrets.dev.yaml
version: "1"
secrets:
DATABASE_URL: "postgres://dev:dev@localhost/mydb"
API_KEY: "dev-key-123"
REDIS_URL: "redis://localhost:6379"

Encryption (optional, standard age format)

Section titled “Encryption (optional, standard age format)”

With encrypted: true on the environment, the file is stored as a standard age file (age-encryption.org/v1): the whole secrets payload is encrypted so it decrypts with the standalone age/rage CLIs, not only with skret. Reads auto-detect an encrypted file on disk even when the flag is off, and encryption is sticky — once a file is encrypted, saves keep it encrypted.

Terminal window
# One command: create key material, migrate the file, record the flag.
skret keys init --encrypt-existing
  • Recipient: an age X25519 keypair when the key material is an age private key (AGE-SECRET-KEY-1..., as generated by age-keygen or skret keys init); an age scrypt recipient derived from the material as a passphrase otherwise (the passphrase arm).
  • Key material resolution order: SKRET_AGE_KEY → SKRET_LOCAL_KEY → OS keyring (seeded by skret keys init) → interactive passphrase prompt (terminals only; non-interactive contexts fail with exit 4 and a remediation hint). See skret keys.
  • Files written by skret ≤ 1.34 (skret-encrypted-v1 envelopes) still decrypt transparently and keep their format until skret keys init --encrypt-existing migrates them in one command — every value and per-key expiry is preserved. skret keys show / skret doctor report the legacy format.

External decryption works with any age-compatible tool:

Terminal window
age-keygen -o key.txt # or: skret keys init (stores it in the OS keyring)
age -d -i key.txt .secrets.dev.yaml # prints the normal secrets YAML

Every mutation on the local provider (skret set, skret rotate, skret delete, and the mutations sync/import issue) appends one JSONL line to an append-only audit log: .skret-audit.log next to the secrets file, or the audit_log path configured for the environment.

{
"timestamp": "2026-09-19T09:00:00.123Z",
"op": "set",
"key_names": ["API_KEY"],
"env": "prod",
"actor": "deploy-bot"
}
  • Names only: the trail records key names, operation, environment, and actor (SKRET_ACTOR when set, else the OS user). Values are structurally excluded.
  • Created 0600; at 1 MiB it rotates to .skret-audit.log.1 (single backup).
  • skret audit renders and filters the trail (--since, --key, --limit, --format json) without decrypting the secrets file.

WARNING (plaintext mode): By default local secrets files are NOT encrypted. Never use the plaintext local provider for production secrets.

  • Always add .secrets.*.yaml to .gitignore
  • The skret init command does this automatically
  • File permissions are set to 0600 (owner read/write only), encrypted and plaintext alike
  • With encrypted: true, values are never at rest in plaintext; skret keys show warns when a plaintext file holds high-entropy values
Capability Supported
Read ✅
Write ✅
Versioning ❌
Tagging ❌
Encryption ✅ (optional, encrypted: true + skret keys init)
Max value size 1 MB