Skip to content

Team Vault Setup

You are the team lead. You want to initialize a vault that, from the very first secret, is encrypted for every member of your team. Each secret store call should produce ciphertext that any teammate can decrypt with their own GPG key, no follow-up secret share needed.

  • dotsecenv installed
  • Your own GPG key (run dotsecenv identity create if you do not have one)
  • The GPG public key fingerprint of every team member who needs access on day one
  1. Collect public keys from every team member

    Each teammate exports their public key:

    Terminal window
    # Each teammate runs:
    gpg --armor --export them@example.com > them.asc

    They send you them.asc over a channel you trust. Public keys are safe to share publicly — the encryption only requires their public key, never their private key.

  2. Verify each fingerprint out-of-band

    Import and inspect each key:

    Terminal window
    gpg --import alice.asc
    gpg --fingerprint alice@example.com
    # Read the 40-character fingerprint aloud and confirm with Alice.

    Repeat for every teammate. Make a list of the verified fingerprints.

  3. Initialize your config and vault

    Terminal window
    dotsecenv init config --login YOUR_FINGERPRINT
    dotsecenv init vault

    init config stores your fingerprint as the default identity. init vault creates a fresh vault file at the XDG data path and writes its location into your config. See dotsecenv init for path overrides.

  4. Add every teammate’s identity to the vault

    The team-lead pattern is a shell loop over your verified fingerprints:

    Terminal window
    TEAM_FPS=(
    "ABC123DEF456...ALICE"
    "789ABC012DEF...BOB"
    "FED654CBA321...CAROL"
    )
    for fp in "${TEAM_FPS[@]}"; do
    gpg --fingerprint "$fp" >/dev/null || { echo "Missing key: $fp"; exit 1; }
    dotsecenv identity add "$fp"
    done

    Each identity add writes a signed identity entry to the vault. The pre-flight gpg --fingerprint call fails fast if a public key is missing from your keyring before any vault changes happen.

  5. Store your first secret

    Terminal window
    echo "super-secret-db-password" | dotsecenv secret store DATABASE_PASSWORD

    The store command encrypts the value with a fresh AES-256-GCM session key, then encrypts that session key once for each registered identity. Every teammate is in available_to from the very first version — no follow-up secret share needed.

  6. Verify the access list

    Terminal window
    dotsecenv vault describe

    You should see every team member listed under Identities, and DATABASE_PASSWORD listed under Secrets. The JSON form shows the per-secret access list explicitly:

    Terminal window
    dotsecenv vault describe --json | jq '.[].secrets'
    # [
    # {
    # "key": "DATABASE_PASSWORD",
    # "available_to": ["ALICE_FP", "BOB_FP", "CAROL_FP", "YOUR_FP"]
    # }
    # ]
  7. Confirm the GPG environment is healthy

    Terminal window
    dotsecenv vault doctor

    doctor checks that gpg-agent is reachable, the vault format is current, and the vault is not fragmented. A green run here means the workflow will Just Work for teammates with the same GPG hygiene.

  8. Commit the vault to version control

    The vault file is encrypted — committing it to a private repo is the standard distribution mechanism.

    Terminal window
    git add path/to/vault
    git commit -m "Initialize team vault with N members"
    git push

    Each teammate now follows Team Onboarding on their machine: pull the vault, dotsecenv login, and secret get DATABASE_PASSWORD to confirm access.

After this tutorial:

  • One vault file holds one signed identity entry per team member plus one signed value entry for DATABASE_PASSWORD.
  • Every team member can decrypt every future secret store write into this vault.
  • New team members join via Team Onboarding or Share a Secret, without re-initializing the vault.

Run init vault once per environment, then add identities with --all:

Terminal window
dotsecenv init vault -v ~/.config/dotsecenv/vault-dev
dotsecenv init vault -v ~/.config/dotsecenv/vault-prod
for fp in "${TEAM_FPS[@]}"; do
dotsecenv identity add "$fp" --all
done

--all adds the identity to every configured vault in one call.

If only some teammates should access prod, register only their fingerprints in the prod vault:

Terminal window
PROD_FPS=("YOUR_FP" "ALICE_FP") # smaller subset
for fp in "${PROD_FPS[@]}"; do
dotsecenv identity add "$fp" -v ~/.config/dotsecenv/vault-prod
done

Generate a dedicated CI key and register its fingerprint as a team member. See GitHub Action integration for the full CI pattern.

gpg: error reading key: No public key

You ran identity add against a fingerprint whose public key you have not imported. Re-import that teammate’s .asc and verify with gpg --fingerprint FP.

secret store fails with access denied

The latest value of an existing secret was encrypted to a fingerprint set you no longer hold. This typically means a teammate stored a value before adding you back. Either ask them to share the secret with your fingerprint, or rotate the value at its source and secret store again.

Teammate cannot decrypt after pulling the vault

Check the access list with dotsecenv vault describe --json and confirm their fingerprint appears in available_to. If not, run dotsecenv secret share SECRET THEIR_FP --all and push again.