dotsecenv

module
v0.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 2, 2026 License: Apache-2.0

README

dotsecenv: Safe Environment Secrets

A complete Go CLI application for securely managing environment secrets with GPG-based encryption, multi-user support, and FIPS 186-5 compliant algorithm defaults.

Quick Start

Store your first secret
# After installation (see below)
dotsecenv init config
dotsecenv init vault -v ~/.local/share/dotsecenv/vault
dotsecenv login <YOUR GPG FINGERPRINT> # gpg --list-public-keys
echo "xyz" | dotsecenv secret put TEST_SECRET
# Subsequently, you can decrypt secrets
# as long as you hold the corresponding secret key in GPG agent
dotsecenv secret get TEST_SECRET # should output "xyz"
Installation
Mise (universal)
mise use github:dotsecenv/dotsecenv
MacOS/Homebrew
brew tap dotsecenv/tap
brew install dotsecenv
Linux package managers

Package repositories for Debian/Ubuntu, RHEL/CentOS/Fedora, and Arch Linux are available at get.dotsecenv.com.

Binary Download

Download the latest release for your platform from the Releases page.

Linux Packages (.deb / .rpm / .archlinux)

Download the appropriate package from the Releases page and install it:

Debian/Ubuntu:

sudo dpkg -i dotsecenv_amd64.deb

RHEL/CentOS/Fedora:

sudo rpm -i dotsecenv_amd64.rpm

Arch Linux:

sudo pacman -U dotsecenv_amd64.pkg.tar.zst
Windows

NOTICE: dotsecenv on Windows is currently WIP. You can follow this issue for updates.

Download the .zip file for your architecture from the Releases page:

  • dotsecenv_vX.X.X_Windows_x86_64.zip for 64-bit Intel/AMD
  • dotsecenv_vX.X.X_Windows_arm64.zip for ARM64

Extract and add the binary location to your PATH.

GPG Requirement: Install Gpg4win for GPG support. If GPG is not in your PATH, dotsecenv init config will attempt to detect it automatically, or you can set gpg_program in your config file.

Build from Source
# Clone the repository
git clone https://github.com/dotsecenv/dotsecenv.git
cd dotsecenv

# Build using make
make build

# Binary will be at bin/dotsecenv
GitHub Action

Use the official GitHub Action to install dotsecenv in your CI/CD workflows:

- uses: dotsecenv/dotsecenv@v0

The action downloads the appropriate binary for your runner's architecture and verifies its integrity.

Inputs

Release binaries achieve SLSA Build Level 3 compliance with verified provenance attestations. Using build-from-source: true or verify-provenance: false bypasses these security guarantees and is generally NOT recommended.

Input Default Description
version latest Version to install (e.g., v1.2.3 or latest)
build-from-source false Build from source instead of downloading a release
verify-provenance true Verify GPG signatures, checksums, and attestations
Outputs
Output Description
version The version of dotsecenv that was installed
binary-path Full path to the installed binary
Examples

Basic usage (latest release):

jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: dotsecenv/dotsecenv@v0
      - run: dotsecenv secret get DATABASE_URL

Pin to a specific version:

- uses: dotsecenv/dotsecenv@v0
  with:
    version: v0.0.1

Build from source:

- uses: dotsecenv/dotsecenv@v0
  with:
    build-from-source: true
Shell Completions

dotsecenv supports shell completions for Bash, Zsh, Fish, and PowerShell.

Bash

Requires the bash-completion package:

# macOS
brew install bash-completion@2

# Debian/Ubuntu
sudo apt install bash-completion

# RHEL/CentOS/Fedora
sudo dnf install bash-completion

# Arch
sudo pacman -S bash-completion

Add to ~/.bashrc or ~/.bash_profile:

# Load bash-completion (macOS with Homebrew)
[[ -r "$(brew --prefix)/etc/profile.d/bash_completion.sh" ]] && . "$(brew --prefix)/etc/profile.d/bash_completion.sh"

# dotsecenv completions
if command -v dotsecenv &> /dev/null; then
  eval "$(dotsecenv completion bash)"
fi
Zsh

Add to ~/.zshrc:

# dotsecenv completions
if command -v dotsecenv &> /dev/null; then
  eval "$(dotsecenv completion zsh)"
fi
Fish

Add to ~/.config/fish/config.fish:

# dotsecenv completions
if command -v dotsecenv &> /dev/null
  dotsecenv completion fish | source
end
PowerShell

Add to your PowerShell profile ($PROFILE):

# dotsecenv completions
if (Get-Command dotsecenv -ErrorAction SilentlyContinue) {
  dotsecenv completion powershell | Out-String | Invoke-Expression
}
Pre-installed Paths

If you installed via a package manager (Homebrew, deb, rpm, Arch), completions are pre-installed at these paths:

Shell Homebrew (macOS/Linux) Linux Packages (deb/rpm/Arch)
Bash $(brew --prefix)/etc/bash_completion.d/dotsecenv /usr/share/bash-completion/completions/dotsecenv
Zsh $(brew --prefix)/share/zsh/site-functions/_dotsecenv /usr/share/zsh/site-functions/_dotsecenv
Fish $(brew --prefix)/share/fish/vendor_completions.d/dotsecenv.fish /usr/share/fish/vendor_completions.d/dotsecenv.fish
Shell Plugins

Shell plugins that automatically load .env and .secenv files when entering directories are available for zsh, bash, and fish.

For example, given a /path/to/project/.secenv file, e.g.:

A_SECRET={dotsecenv}
ANOTHER_SECRET={dotsecenv/SOME_OTHER_KEY}
MY_NAMESPACED_SECRET={dotsecenv/my::SECRET}

The three keys will be available as environment variables, when cd-ing into /path/to/project/.

Install shell plugins

You can install zsh/bash/fish plugins with:

curl -fsSL https://raw.githubusercontent.com/dotsecenv/plugin/main/install.sh | bash

For plugin manager installation and additional details, see github.com/dotsecenv/plugin#installation.

Basic Usage
# Initialize configuration
## Create default config
dotsecenv init config
## Specify where to store the config
dotsecenv init config -c /path/to/config
## Initialize the config with a single vault
dotsecenv init config -v /path/to/vault
## Customize both the config and the vault location
dotsecenv init config -c ... -v ...
## Skip GPG detection (for systems without GPG installed)
dotsecenv init config --no-gpg-program
## Set GPG program path explicitly (without validation)
dotsecenv init config --gpg-program /usr/local/bin/gpg

# Initialize a vault
## Interactive prompt, asking which vault to initialize
dotsecenv init vault
## Specify which vault to initialize
dotsecenv init vault -v /path/to/vault

# Login with your GPG fingerprint
dotsecenv login <FINGERPRINT>

# Add an identity to the vault
dotsecenv vault identity add <FINGERPRINT>
dotsecenv vault identity add <FINGERPRINT> --all  # Add to all vaults

# Store a secret (reads value from stdin)
echo "secret-value" | dotsecenv secret put MY_SECRET

# Retrieve a secret
dotsecenv secret get MY_SECRET
dotsecenv secret get MY_SECRET --all   # All values across all vaults
dotsecenv secret get MY_SECRET --last  # Most recent value across all vaults
dotsecenv secret get MY_SECRET --json  # Output as JSON

# Share a secret with another identity
dotsecenv secret share MY_SECRET <TARGET_FINGERPRINT>

# Revoke access to a secret
dotsecenv secret revoke MY_SECRET <TARGET_FINGERPRINT>

# List vaults and secrets
dotsecenv vault list
dotsecenv vault list --json

# List identities in vaults
dotsecenv vault identity list
dotsecenv vault identity list --json

# Validate vault and config
dotsecenv validate
dotsecenv validate --fix  # Attempt to fix issues

Command Reference

Global Flags
Flag Short Description
--config -c Path to config file
--vault -v Path to vault file or vault index (1-based)
--silent -s Silent mode (suppress warnings)
Commands
Command Description
init config [--gpg-program|--no-gpg-program] Initialize configuration file
init vault Initialize vault file(s)
login FINGERPRINT Initialize user identity
secret put SECRET Store an encrypted secret (reads from stdin)
secret get SECRET [--all|--last|--json] Retrieve a secret value
secret share SECRET FINGERPRINT [--all] Share a secret with another identity
secret revoke SECRET FINGERPRINT [--all] Revoke access to a secret
vault list [--json] List configured vaults and their secrets
vault identity add FINGERPRINT [--all] Add an identity to vault(s)
vault identity list [--json] List identities in configured vaults
validate [--fix] Validate vault and config integrity
version Show version information
completion Generate shell completion scripts

Features

  • Explicit Initialization: Safe bootstrapping of configuration and vaults
  • Encrypted at Rest: All secrets are encrypted using AES-256-GCM (RFC 9580)
  • Multi-User Support: Secrets can be encrypted for multiple identities using GPG multi-recipient encryption
  • Portable Vault: The vault file can be safely committed to git and shared between machines
  • Secret Sharing: Share and revoke access to secrets with other team members
  • Append-Only Design: Cryptographic history is preserved for audit trails
  • GPG Agent Integration: Leverages gpg-agent for secure key management
  • XDG Compliance: Respects XDG Base Directory Specification for configuration files
  • SUID Mode Support: Restricted operations when running with elevated privileges
  • JSON Output: Machine-readable output format for scripting

Configuration

Config File Resolution

The configuration file location is determined in the following order of precedence:

  1. -c flag (highest priority): Explicitly specify a config file path
  2. DOTSECENV_CONFIG environment variable: Override the default location
  3. XDG default: $XDG_CONFIG_HOME/dotsecenv/config (typically ~/.config/dotsecenv/config)
  4. SUID mode: /etc/dotsecenv/config (when running with elevated privileges)

When both -c and DOTSECENV_CONFIG are specified, the -c flag takes precedence and a warning is printed to stderr (unless -s silent mode is enabled):

warning: DOTSECENV_CONFIG environment variable ignored because -c flag was specified

In SUID mode, the DOTSECENV_CONFIG environment variable is ignored for security reasons.

Config File Format

Example config:

# Default configuration uses FIPS 186-5 compliant algorithm minimums
approved_algorithms:
  - algo: ECC
    curves:
      - P-384
      - P-521
    min_bits: 384
  - algo: EdDSA
    curves:
      - Ed25519
      - Ed448
    min_bits: 255
  - algo: RSA
    min_bits: 2048
vault:
  - /path/to/vault1
strict: false
gpg:
  program: gpg # Path to GPG executable
GPG Configuration

The gpg.program option specifies the path to the GPG executable. The behavior depends on whether the value is specified and whether strict mode is enabled:

Resolution order:

  1. Explicit configuration: If gpg.program is set, it must be an absolute path to an existing, executable program
  2. PATH inference: If gpg.program is not set (or empty), dotsecenv will look up gpg from your system PATH and print a warning to stderr
  3. Strict mode: In strict mode (strict: true), gpg.program must be explicitly configured - PATH inference is not allowed

Examples:

# Explicit path (recommended for production/strict mode)
gpg:
  program: /usr/bin/gpg

# Not specified - will infer from PATH with a warning
gpg:
  program: ""

# Windows with Gpg4win
gpg:
  program: "C:\\Program Files (x86)\\GnuPG\\bin\\gpg.exe"

Automatic detection: When running dotsecenv init config, dotsecenv will detect available GPG installations and set gpg.program to the detected absolute path. If multiple GPG installations are found, you'll be prompted to choose one.

When to use explicit paths:

  • In strict mode (required)
  • When you have multiple GPG versions installed
  • When GPG is installed in a non-standard location
  • In CI/CD environments where PATH may vary

Vault File Format

Default vault location: $XDG_DATA_HOME/dotsecenv/vault

The vault uses a JSONL (JSON Lines) format for efficient append operations and indexed lookups. Each entry includes a hash and cryptographic signature to prevent against tampering.

Header (Line 1):

{
  "version": 1,
  "identities": [
    ["FINGERPRINT1", 2],
    ["FINGERPRINT2", 3]
  ],
  "secrets": { "SECRET_KEY": { "secret": 4, "values": [5, 6] } }
}

Identity Entry:

{
  "type": "identity",
  "data": {
    "added_at": "2024-11-09T12:00:00Z",
    "algorithm": "ECC",
    "algorithm_bits": 521,
    "curve": "P-521",
    "created_at": "2024-10-01T10:00:00Z",
    "fingerprint": "1E378219F90018AB2102B2131C238966B12A6F21",
    "hash": "sha256:...",
    "public_key": "base64...",
    "signed_by": "1E378219F90018AB2102B2131C238966B12A6F21",
    "signature": "base64...",
    "uid": "user@example.com"
  }
}

Secret Definition Entry:

{
  "type": "secret",
  "data": {
    "added_at": "2024-11-09T12:05:00Z",
    "hash": "sha256:...",
    "key": "DATABASE_URL",
    "signature": "base64...",
    "signed_by": "1E378219F90018AB2102B2131C238966B12A6F21"
  }
}

Secret Value Entry:

{
  "type": "value",
  "secret": "DATABASE_URL",
  "data": {
    "added_at": "2024-11-09T12:05:00Z",
    "available_to": ["1E378219F90018AB2102B2131C238966B12A6F21"],
    "hash": "sha256:...",
    "signature": "base64...",
    "signed_by": "1E378219F90018AB2102B2131C238966B12A6F21",
    "value": "base64-encrypted-value"
  }
}

Security Features

  • RFC 9580 OpenPGP compliance: Modern OpenPGP standard with mandatory AEAD encryption
  • AES-256-GCM symmetric encryption: NIST-approved authenticated encryption (SP 800-38D)
  • FIPS 186-5 digital signatures: RSA, ECDSA, and EdDSA signature schemes for vault entry authenticity and non-repudiation
  • FIPS 186-5 compliant defaults: Algorithm minimums meet the Digital Signature Standard requirements
  • FIPS 140-3 Crypto: Release binaries are built with Go's native FIPS 140-3 cryptographic module (GOFIPS140=v1.0.0) for NIST-validated cryptographic primitives on all platforms
  • Multi-recipient PGP encryption with hybrid cryptography
  • Hash-based integrity checking (SHA-256/SHA-512)
  • GPG agent integration for secure key management
  • Full secret encryption/decryption lifecycle
  • Validation logic with optional auto-fix
  • SUID mode restrictions for elevated privilege protection
  • SLSA Build Level 3: Release binaries include verifiable provenance attestations generated via GitHub's attest-build-provenance action on hardened GitHub-hosted runners
SUID Mode Restrictions

When running with SUID privileges, the following restrictions apply:

  • -c and -v flags are blocked
  • DOTSECENV_CONFIG and DOTSECENV_FINGERPRINT environment variables are ignored
  • Config defaults to /etc/dotsecenv/config
  • Write operations are blocked: login, init config, init vault, secret put, secret share, secret revoke, vault identity add

This prevents privilege escalation attacks when the binary is installed with elevated permissions.

Exit Codes

Code Name Description
0 Success Operation completed successfully
1 General Error Unspecified error
2 Config Error Configuration file issue
3 Vault Error Vault file issue
4 GPG Error GPG operation failed
5 Auth Error Authentication failed
6 Validation Error Validation failed
7 Fingerprint Required No fingerprint configured
8 Access Denied Permission denied
9 Algorithm Not Allowed Algorithm not in allow-list

Environment Variables

Variable Description
DOTSECENV_CONFIG Override config file path (ignored in SUID mode)
DOTSECENV_FINGERPRINT Override fingerprint from config (ignored in SUID mode)
XDG_CONFIG_HOME Override config directory (defaults to: ~/.config)
XDG_DATA_HOME Override data directory (defaults to: ~/.local/share)

Known Limitations

Ed448 Keys (GnuPG v5 Format)

Ed448 keys generated by GnuPG 2.4+ use the OpenPGP v5 key format, which is not yet fully supported by the underlying cryptographic library (gopenpgp/go-crypto). This results in a parsing error when trying to add Ed448 identities:

failed to get public key: failed to parse public key: gopenpgp: error in reading key ring: openpgp: invalid data: first packet was not a public/private key

Workaround: Use Ed25519 keys instead, which are fully supported and provide equivalent security for most use cases. Ed25519 keys use the OpenPGP v4 format which has full library support.

Status: This limitation will be resolved when:

  • GnuPG adopts RFC 9580 v6 format for Ed448 keys, OR
  • go-crypto adds compatibility for GnuPG's v5 Ed448 format

Ed448 is included in the approved algorithms configuration to ensure readiness when support becomes available.

FAQ

How do I generate a GPG key?
# Generate a new GPG key and choose sensible defaults, i.e.:
# - (9) ECC (sign and encrypt)
# - (1) Curve 25519
# - Key expiration: 1y
gpg --full-generate-key
agent_genkey failed: No pinentry

If you are unable to generate a key due to this error, install pinentry:

# macOS
brew install pinentry-mac

# Linux
sudo apt-get install pinentry
sudo dnf install pinentry-tty
sudo yum install pinentry-tty
sudo pacman -S pinentry-tty
# etc.

In rare cases you may need to add a pinentry-program line to your ~/.gnupg/gpg-agent.conf and restart the gpg-agent (killall gpg-agent).

gpg: signing failed: Inappropriate ioctl for device

This error occurs when GPG cannot find the terminal for pinentry input. Add the following to your shell profile (~/.bashrc, ~/.zshrc):

export GPG_TTY=$(tty)

Or for fish shell, add the following to ~/.config/fish/config.fish:

set -gx GPG_TTY (tty)

Then restart your shell or run the command directly.

gpg: decryption failed

If you encounter this error, first try to define GPG_TTY (see above) before searching for other possible solutions.

$ dotsecenv secret get bla
failed to decrypt secret: failed to decrypt with gpg-agent: exit status 2
GPG error: gpg: decryption failed: No secret key

Development

Setup
# Install all development tools (lefthook, golangci-lint, syft, goreleaser)
make install-tools
Building
# Build with FIPS 140-3 crypto (no CGO required)
make build

The default make build uses Go's native FIPS 140-3 cryptographic module (GOFIPS140=v1.0.0), which provides NIST-validated cryptographic primitives on all platforms without requiring CGO. See go.dev/blog/fips140 for details.

Testing
# Run all tests
make test

# Run tests with race condition detection
make test-race

# Run end-to-end tests
make e2e
Linting
# Run linting (installs golangci-lint if needed)
make lint
Releasing

Releases are triggered by pushing a signed semver tag. Following GitHub Actions conventions, a major version tag (e.g., v0) should also be maintained to allow users to pin to a major version.

The releasetools-cli simplifies this process:

rt git::release --major --sign --force --push v0.1.2

This creates both v0.1.2 and v0 tags pointing to the same commit, signs them, and pushes to the remote.

Security Considerations

What dotsecenv Protects Against
  • Accidental exposure of unencrypted secrets in version control
  • Secrets stored in plaintext on disk
  • Access to secrets by unauthorized users without GPG keys
  • Tampering with vault entries (signature verification)
  • Privilege escalation via SUID binaries
What dotsecenv DOES NOT Protect Against
  • Operating system-level access (root/admin can always read memory)
  • Compromised GPG private keys
  • Quantum computing attacks (future consideration)
  • Side-channel attacks
  • Physical memory dumps
  • Environment snooping
Recommendations
  1. Private Keys: Never commit GPG private keys to repositories
  2. Key Management: Use gpg-agent with passphrase protection
  3. Vault Files: Can be committed to git, technically safe in public repositories, but not recommended
  4. Multi-User Systems: Use strong user isolation and file permissions
  5. Monitoring: Audit all secret access in production environments
  6. Rotation: Periodically rotate encryption keys by updating and then re-encrypting secrets

License

Apache 2.0 License. See LICENSE file for details.

Acknowledgments

Directories

Path Synopsis
cmd
dotsecenv command
internal
cli
xdg
pkg

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL