Getting Started
See Home for installation and a first taste of Raaz with the local provider (no cloud account
needed). This page picks up from there - setting up real cloud credentials and the rest of the day-to-day
commands.
Set up a cloud provider
Cloud provider credentials live in a per-provider file at ~/.raaz/providers/<provider>/provider.env - this
file is deliberately kept outside the repo/package so credentials never end up bundled into a distributable
wheel. The easiest way to create it is interactively:
raaz provider configure aws # or azure / oci / gcp
It prompts for each field the provider needs (masking secrets like AWS_SECRET_ACCESS_KEY), writes the file
for you, and offers to run raaz doctor right after so you know immediately if something's wrong. You can
still edit the file by hand instead - the field names for each provider are below.
AWS
# ~/.raaz/providers/aws/provider.env
AWS_ACCESS_KEY_ID=...
AWS_SECRET_ACCESS_KEY=...
AWS_DEFAULT_REGION=us-east-1
Raaz uses boto3's default credential chain, so anything boto3 normally picks up (env vars, shared
credentials file, IAM role) also works.
Azure
# ~/.raaz/providers/azure/provider.env
AZURE_TENANT_ID=...
AZURE_CLIENT_ID=...
AZURE_CLIENT_SECRET=...
AZURE_VAULT_URL=https://<your-vault>.vault.azure.net/
OCI
# ~/.raaz/providers/oci/provider.env
OCI_TENANCY=...
OCI_USER=...
OCI_FINGERPRINT=...
OCI_KEY_FILE=...
OCI_REGION=...
OCI_COMPARTMENT_ID=...
OCI_VAULT_ID=...
OCI_VAULT_KEY_ID=...
GCP
# ~/.raaz/providers/gcp/provider.env
GOOGLE_APPLICATION_CREDENTIALS=/path/to/service-account.json
GOOGLE_CLOUD_PROJECT=my-project-id
Both fields are optional - GCP authenticates via Application Default Credentials by default (run
gcloud auth application-default login once and you're done), and resolves its project from the ADC default
project if GOOGLE_CLOUD_PROJECT isn't set. Use provider.env only if you want to pin a specific
service-account key or project instead of relying on whatever ADC picks up.
Vault
# ~/.raaz/providers/vault/provider.env
VAULT_ADDR=https://your-vault-host:8200
VAULT_TOKEN=...
Token auth only, against Vault's KV v2 secrets engine - AppRole/OIDC/other auth methods aren't supported.
VAULT_NAMESPACE (Vault Enterprise multi-tenancy) and VAULT_MOUNT (which KV v2 mount to use, default
secret) are both optional - for plain open-source Vault (including the dev server below) you'll never set
VAULT_NAMESPACE at all. raaz doctor --provider vault still reports it as "Missing" either way - doctor's
hint check doesn't distinguish "required" from "optional and fine to leave empty," so that specific line is a
known false positive, safe to ignore. No real Vault server handy? vault server -dev starts a fully working
one locally in one command (ephemeral, in-memory - never point it at real secrets) and prints a root token you
can use as VAULT_TOKEN straight away.
1Password
# ~/.raaz/providers/1password/provider.env
OP_SERVICE_ACCOUNT_TOKEN=...
OP_VAULT_ID=...
Requires a 1Password Service Account (Business/Teams/Family plans - an Individual account alone can't create
one) with access to whichever vault you want to use. Each pushed file becomes one Secure Note item, titled
<app>/<env>/<filename>, holding the whole file's content in a single field.
Two easy mistakes to make setting this up:
- The Service Account needs write access to the vault, not just read. New Service Accounts are often
created read-only by default (a sensible least-privilege default) - if
pushfails with "not sufficient permissions," go back and grant it write/edit access to the specific vault. OP_VAULT_IDis the vault's ID, not its display name - and the 1Password web app's URL has two different IDs in it, easy to grab the wrong one. A vault URL looks like.../app#/<ACCOUNT_ID>/Vault?itemListId=<ACCOUNT_ID>:<VAULT_ID>- the first ID in the path is your account ID (the most visually obvious one to copy, and wrong for this); the actual vault ID is the part after the colon initemListId. If you have theopCLI,op vault listshows vault IDs directly and avoids this entirely.
Bitwarden
# ~/.raaz/providers/bitwarden/provider.env
BW_ACCESS_TOKEN=...
BW_ORGANIZATION_ID=...
BW_PROJECT_ID=...
Requires a Bitwarden Secrets Manager machine account access token, plus the organization and project it belongs
to - create the project in the Secrets Manager web UI first (BW_PROJECT_ID scopes every secret raaz pushes to
that one project, the same role OP_VAULT_ID plays for 1Password). Each pushed file becomes one secret, keyed
<app>/<env>/<filename>, holding the whole file's content as the secret value.
One thing worth knowing: Bitwarden's own list API is organization-wide, not project-scoped - raaz filters to
your configured project itself, so listing/pulling never picks up a same-named secret that happens to live in a
different project.
Check your setup before pushing anything
Once you've filled in a provider's provider.env, run raaz status to confirm it's actually usable - it
checks for likely-missing fields and does a real connectivity check (the same thing raaz doctor checks on
its own, if you only want that one piece), then also shows whether your local files are in sync with what's
stored remotely. This is the command to reach for day to day; raaz doctor/raaz diff remain available
individually for scripting or when you only want one piece of what status shows.
raaz status --provider aws
You find out about a typo'd vault URL or missing credential from a clear message this way, instead of a raw
SDK stack trace the first time you push.
Establish a context and push/pull
raaz init myapp dev aws # or gcp / azure / oci / vault / 1password / bitwarden / local
raaz push # pushes every .env file in the project root to AWS
raaz pull # fetches them back, overwriting whatever's currently there
By default your .env files stay right at the project root - the convention most tools already use. On a
true first init, raaz init asks whether you'd rather store them under a subfolder of .raaz/ instead
(default: no); see raaz init for what opting in looks like.
app/env/provider are always --options that fall back to whatever context was last saved - init is
the one exception, since it's establishing that context for the first time. To operate on a different
app/env/provider without changing the saved context, pass the flags explicitly:
raaz push --app myapp --env prod --provider aws
Sharing what a project needs, without sharing secrets
A teammate cloning the repo needs to know which keys a .env file should have - without ever seeing your real
values. raaz dotfiles example writes a <file>.example alongside a real file with every value blanked:
raaz dotfiles example
API_KEY=
DATABASE_URL=
Comments and blank lines in the real file carry over unchanged, so any annotations stay put. Commit the
.example file to git (unlike the real .env, which usually isn't) - it's meant to be shared.
Once a .example file exists, raaz push keeps it in sync automatically, every push, for as long as it's
there - nothing to remember or re-run by hand. Skip that for a single push with raaz push --no-examples;
delete the .example file to stop tracking it permanently.
Running a process without touching disk
If you'd rather not have secrets sitting in a .env file at all - on a laptop or in CI - raaz run fetches
them fresh and injects them straight into a subprocess's environment instead:
raaz run -- java -jar app.jar
raaz run --env prod -- node server.js --port 8080
Put -- before the command so its own flags aren't mistaken for raaz's. The child process's stdout/stderr
connect straight to your terminal, and its exit code becomes raaz run's exit code, so it composes normally
in scripts (raaz run -- pytest && echo ok). Add --verbose/-v to print a table of every key, its value,
and which secret it came from before running - useful for confirming what's actually being injected; it's
off by default so a plain raaz run never prints secret values.
Whether your app actually picks up the injected variables depends on how it reads config -
System.getenv(...) in Java (or anything a framework like Spring Boot binds from the environment) works with
no changes; System.getProperty(...) (JVM -D flags) is a different namespace and won't see them; an app
that reads a .env file directly off disk needs pull instead.
Switching environments
raaz use staging # shortcut for `raaz ctx use --env staging`
raaz ctx use --app otherapp --provider gcp # change any subset of app/env/provider
raaz ctx show
raaz ctx clear
If your local .env files have changes that were never pushed under the context you're switching away
from, raaz use/ctx use won't just leave them stranded - it offers to push them right now before switching
(the default, recommended choice), falling back to asking whether to continue anyway if you decline or the
push fails. Either way, any local file that ends up in sync with the old context gets cleared automatically
afterward (backed up first, so raaz rollback can still bring it back) - so a stale .env from the context
you just left can't silently linger and get read by your app, or accidentally re-pushed to the new context.
Pass --push to answer the push question automatically instead of being asked - useful for scripts; --force
skips this whole check instead, touching nothing local at all.
pull always writes flat: every secret is restored to the configured .env dir using just its filename, and
it overwrites the file if one's already there - there's no concept of nested subdirectories in push/pull
today. push similarly only looks at .env-style files sitting directly in that dir, not in subdirectories.
Pass --dir <name> to either command to use a different subfolder under .raaz/ for a single run.
Before pull overwrites anything, it backs up whatever was already there into .raaz/backups/<timestamp>/ -
if a pull wasn't what you wanted, raaz rollback --list shows the available snapshots and raaz rollback
restores the most recent one (raaz rollback --to <timestamp> for a specific one).
Want to compare two environments directly, without switching context or pulling anything down? raaz diff
--against <env> compares the current env's remote content against another env's, same app/provider - useful
for catching drift like a key that's set in prod but missing from staging:
raaz diff --against staging
Found drift you want to actually fix, or need to seed a brand-new environment from an existing one? raaz sync
copies secrets into a different app/env/provider in one shot - migrating off local onto a real backend,
moving between two cloud providers, or cloning staging into a new preprod. It previews what would change
before writing anything, and never deletes anything at the destination:
raaz sync --to-provider aws --to-env preprod # seed preprod from the current context
raaz sync --to-provider aws --dry-run # preview only - see docs/cli.md#sync for the full flag set
Audit log
Every push, pull, dotfiles remove, rollback, and .raaz/<dir>/ file move gets one line appended
to ~/.raaz/audit.log - timestamp, action, app/env/provider, and whether it succeeded. Never a secret
name, key, or value. Read-only commands (list, run, diff, status, doctor) never touch this file.
raaz audit # every entry, newest first
raaz audit --app myapp --env prod # scoped to one app/env
This is local and complements each cloud provider's own real audit trail (AWS CloudTrail, Vault's audit devices, and so on) - it doesn't replace them, and it's not tamper-resistant the way those are. What it adds is the one thing no single provider's log has: a record spanning every provider you use, tagged with raaz's own app/env/provider context.
On by default, with zero setup. Pass --no-log before the subcommand to disable it for one run - useful in CI,
where a shared/ephemeral filesystem makes a local log pointless anyway:
raaz --no-log push
This prints a warning every time, since disabling it is meant to be a deliberate choice, not a silent default.
Cleaning up
raaz dotfiles remove # delete local .env files for the current context, pick which ones
raaz dotfiles remove --force # delete all of them, no prompts (needed for CI - the picker needs a real terminal)
This only ever deletes the project's own local .env-style files - never anything stored remotely, whether
that's a real cloud secret or local's own on-disk copy under ~/.raaz. Raaz has no command that deletes a
secret from where it's actually stored: remove a cloud secret through the vendor's own tooling; for local,
delete ~/.raaz/providers/local/<app>/<env>/ by hand.
Sharing a secret with someone else
Everything above assumes the other person already has access to the same app/env/provider context you do.
raaz share .env --key API_KEY is for when they don't: it prints a one-time-read link that works in any
browser, with no raaz install and no cloud credentials needed to open it. Just the plain filename works even if
you opted into a .raaz/<dir>/ subfolder earlier - you never need to type that path yourself.
share isn't limited to .env files, either - any file shares, whole, with no --key/menu: a .pem
certificate, a plain token in a .txt file, a kubeconfig, whatever. raaz share id_rsa or raaz share
ca.pem work exactly the same way raaz share .env does. See CLI Reference for how it works
and the one-time raaz share configure setup it needs.