Guides

Vault -- Secret Management

Alpha Feature — Vault is ready for testing and daily use, but the API may change between releases. If you encounter issues, please report them via GitHub.

Requires a paid plan. Vault is available starting with the Developer plan. The Free plan does not include Vault access. You must be logged in (asd login) to use Vault commands.

What is ASD Vault?

ASD Vault provides encrypted secret management backed by Supabase Vault and pgsodium. Instead of scattering API keys, database passwords, and certificates across .env files, sticky notes, and chat messages, Vault gives you a single encrypted store that you can access from the CLI, inject into running processes, and share securely with your team.

Secrets are encrypted at rest using pgsodium AEAD (XChaCha20-Poly1305). The encryption root key is managed by Supabase KMS and never stored in the database. Access is enforced via Row Level Security per user and organisation.

Quick Start

# Sign in (required before using Vault)
asd login

# Store a secret
asd vault set DATABASE_URL "postgres://user:pass@host:5432/db"

# Retrieve a secret
asd vault get DATABASE_URL

# List all secrets (shows metadata only, never values)
asd vault list

That is all you need to get started. The sections below cover every Vault capability in detail.

Commands Reference

CommandDescription
asd vault listList secrets (name, category, scope — no values shown)
asd vault get <name>Print decrypted value to stdout
asd vault set <name> [value]Create or update a secret
asd vault delete <name>Soft-delete a secret
asd vault import <directory>Bulk import secrets from a directory
asd vault export <directory>Export all secrets to files
asd vault inject <template>Substitute asd:// references in a template file
asd vault run --env-file <tpl> -- <cmd>Run a command with secrets injected as environment variables
asd vault keys listShow scope keys for your account
asd vault keys rotate [--scope user\|org]Generate a new scope key and re-encrypt all secrets
asd vault keys export [--scope user\|org]Print the scope key hex to stdout for backup
asd vault keys import <hex> [--scope]Import a scope key and re-encrypt secrets
asd vault migrate --to <tier>Batch re-encrypt secrets between encryption tiers

Storing Secrets

From a Command Argument

The simplest way to store a secret:

asd vault set API_KEY "sk-abc123"

From Standard Input

For multiline values or piped content, use --stdin:

cat ~/.kube/config | asd vault set kubeconfig --stdin

From a File

Store the contents of a file directly:

asd vault set tls/cert --file ./cert.pem

With Metadata

Add a category and description to keep your secrets organised:

asd vault set db/PASSWORD "s3cret" 
  --category database 
  --description "Production DB password"

Categories are free-form strings. Use them to group related secrets (e.g., database, api, tls) so they are easier to find with asd vault list.

Retrieving Secrets

asd vault get prints the decrypted value to stdout with no extra formatting, making it safe to use in scripts and pipelines:

# Use in a script
DB_URL=$(asd vault get DATABASE_URL)

# Pipe to another command
asd vault get tls/cert > /tmp/cert.pem

asd vault list shows metadata only (name, category, scope) and never displays decrypted values. This is safe to run in shared terminals or screen-sharing sessions.

Injecting Secrets into Processes

Running Commands with Secrets

The asd vault run command injects secrets as environment variables into a child process. Create a template file that references your secrets:

# .env.tpl
DATABASE_URL=asd://db/PASSWORD
API_KEY=asd://API_KEY
REDIS_URL=asd://cache/REDIS_URL

Then run your application with those secrets injected:

asd vault run --env-file .env.tpl -- node server.js

Vault resolves every asd:// reference, injects the decrypted values as environment variables, and starts your command. The secrets exist only in the process environment — they are never written to disk.

Substituting References in Config Files

For configuration files that need secrets baked in (e.g., JSON, YAML):

asd vault inject config.tpl config.json

This reads config.tpl, replaces all asd://secret-name references with their decrypted values, and writes the result to config.json.

Import and Export

Importing Secrets

Bulk-import secrets from a directory where each file name becomes the secret name:

asd vault import ./secrets/

If the directory contains files like API_KEY, DB_PASSWORD, and TLS_CERT, each file’s contents become the corresponding secret value.

Exporting Secrets

Export all your secrets back to files for backup or migration:

asd vault export ./backup/

The export is round-trip faithful — importing an exported directory recreates the original secrets.

Scopes: Personal vs Organisation

Every secret has a scope that determines who can access it:

ScopeFlagWho Can Access
Personal--scope user (default)Only you
Organisation--scope orgYou and your organisation’s admins
# Personal secret (default)
asd vault set MY_TOKEN "abc123"

# Shared with your organisation
asd vault set SHARED_API_KEY "xyz789" --scope org

Organisation-scoped secrets are ideal for shared credentials that multiple team members need, such as staging environment tokens or third-party API keys.

Plan Limits

Vault availability and capacity depend on your subscription plan:

PlanSecrets IncludedVault Access
Free0Not available
Developer10Included
Pro50Included
Scale200Included
EnterpriseUnlimitedIncluded

Need more secrets? The Vault addon adds 50 additional secrets for EUR 5/month per unit. Manage addons from your billing page.

Vault is available starting with the Developer plan. If you need encrypted secret management for a larger team, the Pro plan and above provide higher limits along with organisation-scoped sharing.

Web Dashboard

You can also manage secrets through the web interface at /workspace/vault/. The dashboard lets you browse, create, and delete secrets with a visual interface.

For security, the web dashboard shows secret metadata (name, category, scope, creation date) but never displays decrypted values. To read a secret’s value, use asd vault get from the CLI.

Security Details

ASD Vault is designed with a zero-plaintext-on-disk philosophy:

  • Encryption at rest: Secrets are encrypted using pgsodium AEAD (XChaCha20-Poly1305) before being stored in the database.
  • Key management: The encryption root key is managed by Supabase KMS and never stored alongside the encrypted data.
  • Access control: Row Level Security (RLS) policies enforce that users can only access their own secrets, or organisation-scoped secrets they are authorised for.
  • Soft deletes: When you delete a secret, it is soft-deleted (marked with a deleted_at timestamp) rather than permanently removed, providing an audit trail.
  • No plaintext on disk: Decrypted values are only held in memory during retrieval and injection. They are never written to log files or temporary storage.

Encryption Tiers

Every secret in Vault has an encryption tier that determines how it is protected and who can decrypt it. You can mix tiers within the same account — each secret independently stores its tier.

TierNameHow It WorksWho Can Decrypt
0Server-side onlyEncrypted at rest by pgsodium (automatic)Database administrators
1Scope key (default)Your secret is encrypted with a 256-bit key before it leaves your machineAnyone with scope key access
2PassphraseYou provide your own passphrase — ASD cannot decrypt itOnly the passphrase holder

Tier 0 is for non-sensitive configuration values. Secrets are still encrypted at rest by the database, but a database administrator could read them.

Tier 1 is the default. Every asd vault set automatically encrypts with a scope key before the value reaches the server. This means even a database administrator must intentionally fetch your scope key first — creating an audit trail of intent.

# Tier 1 is automatic -- no extra flags needed
asd vault set API_KEY "sk-abc123"
asd vault get API_KEY  # Transparently decrypted

Tier 2 uses a passphrase you choose. ASD never sees the passphrase and cannot decrypt these secrets for you. If you forget your passphrase, the secret is irrecoverable.

# Encrypt with your passphrase
asd vault set RECOVERY_SEED "word1 word2 ..." --passphrase "my-strong-pass"

# Decrypt requires the same passphrase
asd vault get RECOVERY_SEED --passphrase "my-strong-pass"

# Without the passphrase, you get a warning and raw ciphertext
asd vault get RECOVERY_SEED

To store a secret without client-side encryption (Tier 0), use the --no-encrypt flag:

asd vault set CONFIG_VALUE "not-sensitive" --no-encrypt

Scope Key Management

Scope keys are the 256-bit keys that protect your Tier 1 secrets. They are auto-generated on your first asd vault set and stored as system secrets in Vault itself.

Listing Keys

asd vault keys list

Shows all scope keys for your account, including whether they are user-scoped or org-scoped.

Rotating Keys

Key rotation generates a new scope key and re-encrypts every Tier 1 secret in that scope:

# Rotate your personal scope key
asd vault keys rotate

# Rotate an organisation's scope key
asd vault keys rotate --scope org

During rotation, a backup of the old key is stored temporarily. If re-encryption fails partway through, the old key is preserved and you can retry safely.

Exporting and Importing Keys

Back up your scope key for disaster recovery:

# Export (prints hex to stdout -- pipe to a file or password manager)
asd vault keys export > scope-key-backup.hex

# Import a previously exported key
asd vault keys import "$(cat scope-key-backup.hex)"

Warning: If a scope key is deleted without a backup, all Tier 1 secrets in that scope become permanently irrecoverable. Always keep a backup of your scope key in a secure location.

Web Dashboard — Passphrase Encryption

The web dashboard at /workspace/vault/ supports creating Tier 2 (passphrase-encrypted) secrets directly in your browser:

  1. Navigate to the Vault page and click Create Secret.
  2. Toggle Encrypt with passphrase to enable Tier 2.
  3. Enter and confirm your passphrase (minimum 8 characters).
  4. The secret value is encrypted in your browser using Web Crypto API before being sent to the server.

Passphrase-encrypted secrets created in the browser can be decrypted by the CLI and vice versa — the encryption format is identical.

Tier 1 (scope key) secrets appear in the dashboard with an “Encrypted” badge. To read their values, use asd vault get from the CLI, since scope keys are managed exclusively through the CLI.

Secret Masking in vault run

When you use asd vault run, the injected secret values are automatically masked in the child process output. If a secret value appears in stdout or stderr, it is replaced with *** to prevent accidental exposure in logs or terminal recordings.

Masking works across stdout chunk boundaries — even if a secret value is split across two output chunks, it is still detected and masked.

# Secret values in output are replaced with ***
asd vault run --env-file .env.tpl -- ./my-script.sh
# If the script prints the value of DATABASE_URL, you see *** instead

Tier 2 secrets require --passphrase to be injected:

asd vault run --env-file .env.tpl --passphrase "my-pass" -- ./my-script.sh

Migrating Between Tiers

The vault migrate command batch re-encrypts secrets from one tier to another:

# Encrypt all unencrypted secrets (Tier 0 -> Tier 1)
asd vault migrate --to tier1

# Upgrade to passphrase encryption (any tier -> Tier 2)
asd vault migrate --to tier2 --passphrase "my-strong-pass"

# Remove client-side encryption (any tier -> Tier 0)
asd vault migrate --to tier0

Migration processes each secret individually. If a secret fails to migrate, it is skipped with an error message and the remaining secrets continue.

Troubleshooting

“Not authenticated”

You need to sign in before using Vault. Run asd login and try again.

“Passphrase-encrypted (Tier 2)”

This secret was encrypted with a passphrase. You need to provide it:

asd vault get SECRET_NAME --passphrase "your-passphrase"

If you have forgotten the passphrase, the secret cannot be recovered — this is by design for zero-knowledge encryption.

“Scope key not found”

The scope key for this scope has been deleted or was never created. If you have a backup, import it:

asd vault keys import "your-backup-key-hex"

Without a backup, Tier 1 secrets in this scope are irrecoverable.

“Decryption failed”

The wrong key or passphrase was used, or the ciphertext has been corrupted. Double-check that you are using the correct passphrase or that your scope key has not been rotated since the secret was stored.

“Passphrase cannot be empty”

Both encrypting and decrypting with a passphrase require a non-empty passphrase string. Provide a passphrase with --passphrase "your-pass".

System secrets and plan limits

Internal system secrets (scope keys, backups) do not count against your plan’s secret limit. Only user-created secrets are counted. If you hit your limit, upgrade your plan or add a Vault addon from the billing page.

Related Guides