← README · Identity Setup · Recipient Management · CI/CD Recipes · Seal vs Encrypt · CLI Reference
This guide explains how to configure your gitvault identity — the age identity key used to encrypt and decrypt secrets. Choose the method that best fits your workflow and security requirements.
- Overview
- Option 1: OS Keyring (Recommended)
- Option 2: age Key File
- Option 3: SSH Key File
- Option 4: SSH Agent
- Option 5: Piped FD-based (CI/CD)
- Passphrase Management
- Security Recommendations
Identity is resolved in this order: --identity-stdin → --identity / GITVAULT_IDENTITY_FD → GITVAULT_IDENTITY → OS keyring → SSH agent. → Full resolution table
Quick decision guide:
- Developer workstation → Option 1: OS Keyring
- Keyring unavailable / prefer files → Option 2: age Key File
- Reuse existing SSH key → Option 3: SSH Key File
- Team uses ssh-agent / hardware token → Option 4: SSH Agent
- CI/CD pipelines → Option 5: Piped FD-based
Note:
GITVAULT_IDENTITY_FDand--identityshare priority level 1;GITVAULT_IDENTITY_FDis preferred in CI because the key does not appear in the process environment listing.
The OS keyring stores the age private key in your platform's secure credential store. The key never touches disk unencrypted.
Platform support:
| Platform | Backend |
|---|---|
| macOS | Keychain |
| Linux | Secret Service (requires libsecret / keyutils) |
| Windows | Credential Manager |
# Create a new age identity and store it directly in the OS keyring (default behaviour)
gitvault identity create
# Verify: print the public key of the stored identity
gitvault keyring getThat's it. gitvault will find the key automatically from the keyring on every subsequent command.
# Should print your age public key (age1…)
gitvault identity pubkey# Store the contents of an existing key file in the keyring
gitvault keyring set < ~/.config/gitvault/identity.agegitvault keyring deleteNote: On Linux, the Secret Service backend requires a running secrets daemon such as
gnome-keyring-daemonorkwallet. If the keyring is unavailable, gitvault falls back to the next source in the priority chain. Installlibsecret(Debian/Ubuntu:apt install libsecret-1-0) and ensure a secrets daemon is running.
Note: In headless or container environments the OS keyring is typically unavailable. Use Option 5: Piped FD-based instead.
Store the age private key in a plain file on disk. Use this when the OS keyring is unavailable or when you prefer explicit, file-based credential management.
# Create a new age identity and export it to a file
gitvault identity create --output ~/.config/gitvault/identity.age
# Restrict permissions — gitvault will refuse to load a world-readable key
chmod 600 ~/.config/gitvault/identity.agePoint gitvault at the file using the environment variable or the CLI flag:
# Permanently (add to ~/.bashrc, ~/.zshrc, etc.)
export GITVAULT_IDENTITY=~/.config/gitvault/identity.age
# Per-command
gitvault --identity ~/.config/gitvault/identity.age identity pubkey
# Or pass the raw key string directly (not recommended — exposes the key in shell history)
export GITVAULT_IDENTITY="AGE-SECRET-KEY-1…"gitvault identity pubkey
# age1…Warning: Losing an age key file means losing access to all secrets encrypted to it. Back up the key before adding it as a recipient to any vault.
# Backup: encrypt the key file with a passphrase before storing it
age --passphrase --output identity.age.enc ~/.config/gitvault/identity.age
# Restore: decrypt the backup
age --decrypt --output ~/.config/gitvault/identity.age identity.age.enc
chmod 600 ~/.config/gitvault/identity.ageAlternatively, store the raw AGE-SECRET-KEY-… string in a password manager (e.g. 1Password,
Bitwarden) as a secure note.
Warning: Never commit an age key file to a git repository. Add
*.ageand your key file path to.gitignore.
Use an existing SSH key as a gitvault age identity via the hybrid profile. This is useful when
you already manage SSH keys and want a single credential for both SSH access and secret decryption.
# Create a hybrid SSH-compatible key and export to a file
gitvault identity create --profile hybrid --output ~/.config/gitvault/ssh-identity.age
# Restrict permissions
chmod 600 ~/.config/gitvault/ssh-identity.age
# Point gitvault at the file
export GITVAULT_IDENTITY=~/.config/gitvault/ssh-identity.agegitvault identity pubkeyIf the SSH key has a passphrase, gitvault will prompt interactively by default. To avoid prompts:
Store the passphrase in the OS keyring (recommended):
gitvault keyring set-passphrase
# You will be prompted to enter the passphrase securely
# Verify it is stored
gitvault keyring get-passphrase
# Remove it later if needed
gitvault keyring delete-passphraseSupply via environment variable (CI/automation):
export GITVAULT_IDENTITY_PASSPHRASE="your-passphrase"Supply via file descriptor (most secure for automation):
GITVAULT_IDENTITY_PASSPHRASE_FD=4 gitvault materialize 4<<<"$PASSPHRASE"Delegate identity operations to a running SSH agent. The private key never leaves the agent process, making this suitable for hardware-backed keys (YubiKey, Secretive, 1Password SSH agent).
# Enable via environment variable
export GITVAULT_SSH_AGENT=1
# gitvault will use SSH_AUTH_SOCK automatically if it is set
echo "$SSH_AUTH_SOCK"Note: If
SSH_AUTH_SOCKis not set, start your agent and add your key:eval "$(ssh-agent -s)" ssh-add ~/.ssh/id_ed25519
When more than one key is loaded in the agent, select the right one by fingerprint or comment:
# Via flag
gitvault --identity-selector "my-gitvault-key" identity pubkey
# Via environment variable
export GITVAULT_IDENTITY_SELECTOR="SHA256:abc123…"List loaded keys and their fingerprints:
ssh-add -l| Tool | Notes |
|---|---|
| 1Password SSH agent | Set SSH_AUTH_SOCK to the 1Password socket path; set GITVAULT_SSH_AGENT=1 |
| Secretive (macOS) | Secretive registers as the system SSH agent; SSH_AUTH_SOCK is set automatically |
YubiKey (via gpg-agent) |
Ensure gpg-agent is running with SSH support enabled |
Standard ssh-agent |
Run eval "$(ssh-agent -s)" and ssh-add your key |
- The SSH agent must be running and have the key loaded before gitvault is invoked.
- In headless CI environments, prefer Option 5 unless your CI platform provides an SSH agent socket.
For CI/CD pipelines, pass the identity key without writing it to disk or exposing it in the process environment.
Opens a dedicated FD for the key, keeping it out of /proc/<pid>/environ:
# Bash process substitution / here-string
GITVAULT_IDENTITY_FD=3 gitvault materialize 3<<<"$GITVAULT_KEY"
# Or with a named pipe / subshell
GITVAULT_IDENTITY_FD=3 gitvault run -- my-server 3< <(echo "$GITVAULT_KEY")Store GITVAULT_KEY as a masked/secret CI variable (GitHub Actions secret, GitLab CI variable,
etc.) containing the raw AGE-SECRET-KEY-… string.
echo "$GITVAULT_KEY" | gitvault --identity-stdin materializeNote:
--identity-stdinreads exactly one line from stdin and treats it as the identity key. Any subsequent stdin content is forwarded to the child process unchanged when usinggitvault run.
export GITVAULT_IDENTITY="$GITVAULT_KEY"
gitvault materializeWarning: Setting
GITVAULT_IDENTITYto a raw key string exposes it in the process environment (/proc/<pid>/environon Linux). PreferGITVAULT_IDENTITY_FDfor sensitive pipelines. SetGITVAULT_NO_INLINE_KEY_WARN=1to suppress the inline-key warning if you intentionally use this method.
- name: Materialize secrets
env:
GITVAULT_KEY: ${{ secrets.GITVAULT_IDENTITY }}
run: |
GITVAULT_IDENTITY_FD=3 gitvault materialize 3<<<"$GITVAULT_KEY"materialize:
script:
- GITVAULT_IDENTITY_FD=3 gitvault materialize 3<<<"$GITVAULT_KEY"
variables:
GITVAULT_KEY: $GITVAULT_IDENTITY # masked CI variableSee also: docs/cicd-recipes.md for complete GitHub Actions, Docker, and Kubernetes pipeline recipes using FD-based identity passing.
Applies to SSH key identities (Option 3) that have a passphrase protecting the private key.
All passphrase resolution sources: docs/reference.md § Identity Resolution
# Store (you will be prompted to enter the passphrase)
gitvault keyring set-passphrase
# Verify it is stored
gitvault keyring get-passphrase
# Remove
gitvault keyring delete-passphrase# Via FD (preferred)
GITVAULT_IDENTITY_PASSPHRASE_FD=4 gitvault materialize 4<<<"$PASSPHRASE"
# Via environment variable
export GITVAULT_IDENTITY_PASSPHRASE="$PASSPHRASE"
gitvault materializeStore $PASSPHRASE as a masked secret in your CI platform alongside the identity key.
- Prefer FD-passing over environment variables in CI. File descriptors are not visible in
/proc/<pid>/environand are automatically closed on exec. - Never commit an identity key file to a git repository. Add the path to
.gitignoreand consider adding a pre-commit hook that scans forAGE-SECRET-KEY-patterns. - Restrict key file permissions to
600. gitvault refuses to load a key that is readable by group or world.
- Back up your age key before adding your public key as a vault recipient. Losing the private
key means losing access to all secrets encrypted to it.
- Recommended: encrypt the backup with a passphrase (
age --passphrase) and store it in a password manager. - Alternative: store the raw
AGE-SECRET-KEY-…string directly in your password manager as a secure note.
- Recommended: encrypt the backup with a passphrase (
- Rotate identities annually or immediately after a suspected compromise:
- Generate a new identity:
gitvault identity create --output new-identity.age - Add the new public key as a recipient to all affected vaults.
- Re-encrypt secrets with
gitvault(re-run the encryption step for each vault). - Remove the old public key from the recipients file.
- Delete or securely erase the old key file / keyring entry.
- Generate a new identity:
Warning: Removing a recipient key before re-encrypting secrets will permanently lock you out of those secrets. Always add the new key and verify access before removing the old key.
- The OS keyring is the safest option for developer workstations because the key never touches disk unencrypted and is protected by your login credentials.
- On shared or untrusted machines, prefer piping the key via FD for each invocation rather than persisting it in the keyring.
- Hardware-backed SSH agents (YubiKey, Secretive) provide the strongest protection because the private key never leaves the hardware device.
- Ensure your SSH agent socket path (
SSH_AUTH_SOCK) is not world-writable.
Once your identity is set up, see docs/recipient-management.md for how to add yourself as a recipient and onboard to a vault.
- CLI Reference — Identity Resolution
- CI/CD Recipes — using your identity in pipelines
- Recipient Management — adding yourself as a recipient