secenv 0.0.0

Secure environments.
secenv-0.0.0 is not a library.

secenv

Secure Environment Variable Management with PGP Encryption

secenv is a command-line tool for managing environment variables with PGP encryption support. It allows you to store sensitive configuration values encrypted in YAML files and decrypt them on-demand using your system's GPG keys.

Features

  • 🔐 PGP Encryption: Encrypt sensitive values using OpenPGP/GPG
  • 📁 Profile-Based Configuration: Organize variables into different profiles (dev, staging, prod, etc.)
  • 🔑 System GPG Integration: Uses your existing GPG keys and agent
  • 🛡️ Password Protection: Supports password-protected PGP keys with secure prompting
  • 📄 Multiple Value Types: Literal values, environment variables, files, and encrypted values
  • Fast & Lightweight: Written in Rust for performance and safety

Installation

From Source

git clone https://github.com/cchexcode/secenv
cd secenv
cargo build --release

The binary will be available at target/release/secenv.

Quick Start

1. Create a Configuration File

Create a secenv.yaml file with your environment variables:

# Define reusable anchors
.defaultkey: &defaultkey "PGP-KEY-FINGERPRINT"

profiles:
  dev:
    propagate: true
    vars:
      # Literal value
      APP_NAME: !literal "myapp"
      # Environment variable reference
      HOME_DIR: !environment "HOME"
      # File content
      CONFIG_JSON_CONTENT: !file "/etc/myapp/config.json"

      # PGP encrypted value
      DATABASE_PASSWORD: !pgp
        key: *defaultkey
        value: |
          -----BEGIN PGP MESSAGE-----
          ...
          -----END PGP MESSAGE-----
  production:
    propagate: false
    vars:
      APP_NAME: !literal "myapp"
      DATABASE_PASSWORD: !pgp
        key: "PROD_KEY_FINGERPRINT"
        value: |
          -----BEGIN PGP MESSAGE-----
          ...
          -----END PGP MESSAGE-----

2. Encrypt Values

To create encrypted values, use GPG to encrypt your secrets:

# Encrypt a value for a specific key
echo "my-secret-password" | gpg --encrypt --armor --recipient your@email.com

# Or encrypt for a specific key fingerprint
echo "my-secret-password" | gpg --encrypt --armor --recipient 9CD9D9187E17BE27E2F838B7BA59BCD337CEEA1D

Copy the resulting PGP message (including the -----BEGIN PGP MESSAGE----- and -----END PGP MESSAGE----- lines) into your YAML file.

3. Unlock Variables

# Unlock variables from the default profile
secenv unlock

# Unlock variables from a specific profile
secenv unlock --profile production

# Use a different config file
secenv unlock --config /path/to/config.yaml --profile staging

Output format:

APP_NAME=MyApp
DATABASE_PASSWORD=my-secret-password
HOME_DIR=/Users/username

Configuration Format

Profile Structure

profiles:
  <profile-name>:
    propagate: <boolean>  # Whether to propagate to child processes
    vars:
      <variable-name>: <value-provider>

Value Providers

Literal Values

APP_NAME: !literal "MyApplication"

Environment Variables

HOME_DIR: !environment "HOME"
USER_NAME: !environment "USER"

File Contents

CONFIG_DATA: !file "/etc/myapp/config.json"
CERTIFICATE: !file "/etc/ssl/certs/app.crt"

PGP Encrypted Values

SECRET_KEY: !pgp
  key: "9CD9D9187E17BE27E2F838B7BA59BCD337CEEA1D"  # PGP key fingerprint
  value: |
    -----BEGIN PGP MESSAGE-----
    
    hQIMA/nYRg4ylYK0AQ/+K25a1jwIORvRnutLSR4vBuWA1mC8GHDrWRW3k7btX8DD
    ...
    -----END PGP MESSAGE-----

YAML Anchors and References

Use YAML anchors to avoid repeating key fingerprints:

.defaultkey: &defaultkey "9CD9D9187E17BE27E2F838B7BA59BCD337CEEA1D"
.prodkey: &prodkey "ABCD1234567890ABCD1234567890ABCD12345678"

profiles:
  default:
    vars:
      SECRET1: !pgp
        key: *defaultkey
        value: "..."
      SECRET2: !pgp
        key: *defaultkey
        value: "..."
  
  production:
    vars:
      SECRET1: !pgp
        key: *prodkey
        value: "..."

Usage

Commands

unlock

Decrypt and display environment variables from a profile.

secenv unlock [OPTIONS]

Options:
  -c, --config <config>    Configuration file path [default: secenv.yaml]
  -p, --profile <profile>  Profile to unlock [default: default]
  -h, --help              Print help

man

Generate manual pages.

secenv man --out <directory> --format <manpages|markdown>

autocomplete

Generate shell completion scripts.

secenv autocomplete --out <directory> --shell <bash|zsh|fish|elvish|powershell>

Integration Examples

Shell Integration

# Load variables into current shell
eval "$(secenv unlock --profile production)"

# Export to a file
secenv unlock --profile staging > .env

Docker Integration

# In your Dockerfile
COPY secenv.yaml /app/
RUN secenv unlock --profile production > /app/.env

CI/CD Integration

# GitHub Actions example
- name: Load secrets
  run: |
    secenv unlock --profile ci > $GITHUB_ENV

Security Considerations

PGP Key Management

  • Key Storage: Store your PGP private keys securely using your system's keychain or GPG agent
  • Key Rotation: Regularly rotate encryption keys and re-encrypt values
  • Access Control: Use different PGP keys for different environments (dev, staging, prod)

Best Practices

  1. Never commit unencrypted secrets to version control
  2. Use different keys per environment to limit blast radius
  3. Regularly audit who has access to decryption keys
  4. Use strong passphrases for PGP keys
  5. Enable GPG agent for convenient key management
  6. Backup your keys securely

Password-Protected Keys

When using password-protected PGP keys, secenv will:

  1. Attempt decryption without a password first
  2. If that fails, prompt securely for the password
  3. Allow up to 3 retry attempts
  4. Integrate with GPG agent for cached passwords

GPG Setup

Generate a New Key

# Generate a new GPG key
gpg --full-generate-key

# List your keys
gpg --list-secret-keys --keyid-format LONG

# Export public key (for sharing)
gpg --armor --export your@email.com

Import Existing Keys

# Import a private key
gpg --import private-key.asc

# Import a public key
gpg --import public-key.asc

# Trust a key
gpg --edit-key your@email.com
# In GPG prompt: trust -> 5 -> y -> quit

Troubleshooting

Common Issues

"GPG decryption failed"

  • Ensure the correct PGP key is installed: gpg --list-secret-keys
  • Verify the key fingerprint matches the one in your config
  • Check if the key requires a password and GPG agent is running

"Profile not found"

  • Verify the profile name exists in your config file
  • Check YAML syntax with yamllint secenv.yaml

"Failed to read config"

  • Ensure the config file exists and is readable
  • Verify YAML syntax is correct
  • Check file permissions

Debug Mode

For verbose output, set the RUST_LOG environment variable:

RUST_LOG=debug secenv unlock

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

Development Setup

git clone https://github.com/cchexcode/secenv
cd secenv
cargo build
cargo test

Running Tests

# Run all tests
cargo test

# Run with output
cargo test -- --nocapture

# Run specific test
cargo test test_name

License

This project is licensed under the MIT License - see the LICENSE file for details.

Changelog

v0.0.0 (Current)

  • Initial implementation
  • PGP encryption support
  • Profile-based configuration
  • Multiple value providers (literal, environment, file, pgp)
  • GPG integration with password support
  • Shell completion and manual generation

Related Projects

  • sops - Secrets OPerationS
  • age - Simple, modern encryption tool
  • pass - The standard unix password manager