Github|...

Vault Architecture

The Shared Vault is a team-wide encrypted store that protects your environment variables at rest. All team members on a tenant share the same vault, and each member accesses it with their own passphrase. Every Starter and Pro plan includes a shared vault.

For CLI usage and commands, see Environment Variables. This page explains how the vault works internally and how it is secured.

Overview

Every tenant has a single vault containing an RSA-4096 keypair. Environment variables are encrypted with this keypair and stored in Postgres. The private key is itself encrypted, and each team member holds a personal key to unlock it — protected by their own passphrase.

The vault is initialized the first time any team member runs spky cloud env init. Subsequent members receive access through the invitation flow.

Architecture

Key Hierarchy

Passphrase (client-side only)
 └─ Argon2id ─▶ Derived key (per-member)
     └─ decrypts ─▶ Encryption key (shared)
         └─ decrypts ─▶ RSA private key (per-tenant)

Per variable:
  Random AES key
   ├─ encrypts ─▶ Value (AES-256-GCM)
   └─ wrapped by ─▶ RSA public key (OAEP)

There are three layers of encryption:

  1. Passphrase layer (per-member). Each member’s passphrase is run through Argon2id locally on the CLI to derive a 32-byte key. The passphrase never leaves your machine. This derived key encrypts that member’s copy of the shared encryption key.
  2. Encryption key layer (shared). A single random AES-256 encryption key protects the tenant’s RSA private key. Every member stores their own encrypted copy of this key.
  3. Tenant keypair layer (per-tenant). An RSA-4096 keypair. The public key encrypts environment variable values via hybrid encryption. The private key (encrypted at rest) decrypts them.

How Variables Are Encrypted

When you set a variable:

  1. The CLI sends the plaintext value to the server
  2. The server generates a random AES-256 key, encrypts the value with AES-256-GCM, and encrypts the AES key with the tenant’s RSA public key
  3. The combined ciphertext (encrypted AES key + encrypted value) is stored in Postgres

There is one encrypted copy per variable per environment (dev/prod) — not one per member.

How Variables Are Decrypted

When you load variables:

  1. The CLI derives a key from your passphrase locally using Argon2id — the passphrase never leaves your machine
  2. The CLI sends the derived key to the server
  3. The server uses the derived key to decrypt your copy of the encryption key, decrypts the tenant’s RSA private key, and decrypts each variable
  4. The server returns the plaintext values to the CLI
Server-Side Decryption

Variable decryption happens on the server, not on the client. However, your passphrase never leaves your machine — only the derived key is sent to the server over TLS. The derived key is used only in memory and is never persisted server-side. The encryption protects data at rest in the database, not in transit between the server and CLI (that’s handled by TLS).

Algorithms

LayerAlgorithmPurpose
Passphrase derivationArgon2id (time=1, mem=64 MB, threads=4)Derives a 32-byte key from the member’s passphrase (client-side)
Encryption key wrappingAES-256-GCMEach member’s derived key encrypts their copy of the encryption key
Private key encryptionAES-256-GCMThe encryption key encrypts the tenant’s RSA private key at rest
Value encryptionRSA-4096 OAEP (SHA-256) + AES-256-GCMHybrid encryption of each environment variable value

What Is Stored Where

DataLocationProtection
Tenant RSA public keyServer (Postgres)Plaintext — used to encrypt new values
Tenant RSA private keyServer (Postgres)Encrypted with the encryption key (AES-256-GCM)
Encryption keyServer (Postgres)One copy per member, each encrypted with that member’s passphrase-derived key
Member passphraseNever leaves the clientNever stored on disk; only the derived key is optionally cached at ~/.sp00ky/vault-derived-key
Environment variable valuesServer (Postgres)Hybrid encrypted with tenant public key (one copy per variable)

Sharing Across a Team

When a member sets a variable, it’s encrypted with the tenant’s public key — every member who has the encryption key (i.e., every member of the tenant) can decrypt it. No manual sharing is needed.

Inviting new members: When you run spky cloud team invite, the CLI prompts for your passphrase if the vault is initialized. Your passphrase decrypts the encryption key, which is re-encrypted with a server-side transit key and included in the invitation. When the new member accepts, they set their own passphrase, and the encryption key is re-encrypted for them. No variables need to be re-encrypted.

Changing your passphrase: Only your copy of the encryption key is re-wrapped. Other members and existing variables are unaffected.

Removing a member: Their copy of the encryption key is deleted from tenant_members and any API keys they created are revoked. The tenant’s keypair and encrypted variables remain unchanged.

Security Model

What the encryption protects

  • Database breach. An attacker who gains access to Postgres sees only ciphertext. Without a member’s passphrase, they cannot derive the encryption key, and without the encryption key, they cannot decrypt the tenant’s private key or any variable values.
  • Unauthorized access. Only authenticated tenant members with a valid passphrase can decrypt variables.

What the encryption does not protect

  • Compromised server. Because variable decryption happens server-side, a compromised server process could observe plaintext values during env load or env set. The encryption is at-rest protection, not end-to-end. However, the passphrase itself never reaches the server — only the derived key.
  • Compromised member machine. If a member caches their derived key at ~/.sp00ky/vault-derived-key, anyone with access to that machine can load variables. The derived key cannot be reversed back to the original passphrase.

Member removal

When a member is removed (spky cloud team remove):

  1. Their copy of the encryption key is deleted from the server
  2. Their API keys are revoked
  3. The tenant keypair and encrypted variables are unaffected

The removed member can no longer decrypt any variables — their path to the tenant’s private key is destroyed. If you suspect a removed member had access to sensitive values, rotate those values with spky cloud env set.

Warning

If all team members lose their passphrases, encrypted environment variables cannot be recovered. The passphrase is never stored on the server. Keep at least one passphrase in a secure location (e.g., a password manager).

Passphrase Management

Changing your passphrase

Bash
spky cloud env change-passphrase

You’ll be prompted for your current passphrase, then a new one with confirmation. Only your copy of the encryption key is re-wrapped — existing variables and other members are unaffected.

Caching

The CLI can cache your derived key locally at ~/.sp00ky/vault-derived-key so you don’t need to enter your passphrase every time. The derived key cannot be reversed back to your passphrase. To clear the cache:

Bash
rm ~/.sp00ky/vault-derived-key

Passphrase Reset

If you forget your vault passphrase, a team admin can approve a reset so you can set a new one.

How it works:

  1. You request a reset — all admins are notified by email
  2. An admin approves the reset by entering their passphrase, which proves they have vault access. The encryption key is temporarily held on the server encrypted with a transit key.
  3. You set a new passphrase — the encryption key is re-encrypted with your new passphrase, and the transit-encrypted copy is deleted.
Bash
# Step 1: Request a reset
spky cloud vault request-reset

# Step 2: Admin approves (enters their passphrase)
spky cloud vault approve-reset alice@example.com

# Step 3: Set your new passphrase
spky cloud vault complete-reset

Admins can list and manage pending requests:

Bash
# List pending requests
spky cloud vault list-resets
Reset Security

Reset requests expire after 7 days. Only one active request per member is allowed at a time. The admin must provide their own passphrase to approve — only someone with vault access can grant it to others.

Best Practices

  • Use strong, unique passphrases. Consider a password manager. Each member’s passphrase should be independent.
  • Rotate variables when compromised. If you suspect a value was leaked, run spky cloud env set with a new value rather than rotating passphrases.
  • Limit team size. Only invite members who need access to production secrets.
  • Audit regularly. Use spky cloud team list to review who has access. Remove members who no longer need it.
  • Keep at least one passphrase safe. If all passphrases are lost, there is no recovery path. Store at least one in a password manager.