cryptenv is a lightweight, secure, and reusable Go module designed for loading and managing sensitive environment secrets. It ensures that credentials are never stored in cleartext on disk or persistently in memory.
- Memory-Safe Secret Storage: All loaded secrets are stored in memory encrypted with AES-256-GCM. Decryption occurs on-the-fly only when a value is actively requested.
- Pure Go Age Decryption: Supports decrypting
ageencrypted files natively in Go (symmetric scrypt passphrase and asymmetric key-based). No external command line binary (likegpgorage) is required on the server. - Flexible Struct Loading: Built-in struct tag parser supporting
envandenvDefaulttags (similar tocaarlos0/env). - YAML Unmarshaling: Unmarshal YAML strings inside encrypted secrets directly into Go structs.
- Third-Party Integrations: Easily convert secrets to a
map[string]stringfor integration with other configuration libraries.
Add the package to your go.mod file or workspace:
require github.com/nativebpm/cryptenv v0.0.0Initialize a new secure environment using a Master Key (this key is hashed using SHA-256 to derive the 32-byte AES key):
se, err := cryptenv.NewSecureEnv("my-master-password")
if err != nil {
log.Fatalf("Failed to initialize secure env: %v", err)
}Decrypt and parse a .env.age file encrypted symmetrically with age:
err = se.LoadAgeSymmetric("path/to/secrets.env.age", "my-master-password")Decrypt and parse an .env.age file encrypted asymmetrically (e.g., using a server's identity key or standard SSH private key):
identity, err := age.ParseX25519Identity("AGE-SECRET-KEY-...")
err = se.LoadAgeAsymmetric("path/to/secrets.env.age", identity)Retrieve and decrypt a secret value on the fly:
dbPass, err := se.Get("DB_PASSWORD")
if err != nil {
log.Fatalf("Secret not found: %v", err)
}logLevel := se.GetDefault("LOG_LEVEL", "info")Populate a Go struct using env and envDefault tags directly:
type Config struct {
DBUser string `env:"DB_USER"`
DBPass string `env:"DB_PASSWORD"`
DBPort int `env:"DB_PORT" envDefault:"5432"`
SSLMode bool `env:"SSL_MODE"`
}
var cfg Config
err = se.Unmarshal(&cfg)If you store structured YAML blocks inside your secrets, you can unmarshal them directly into structs:
type DatabaseConfig struct {
Host string `yaml:"host"`
Port int `yaml:"port"`
}
var dbCfg DatabaseConfig
err = se.GetYAML("DB_CONFIG_YAML", &dbCfg)You can convert the secure environment variables to a map[string]string to integrate with libraries like caarlos0/env:
import "github.com/caarlos0/env/v11"
envMap, err := se.ToMap()
if err == nil {
env.ParseWithOptions(&cfg, env.Options{Environment: envMap})
}MIT - See LICENSE