Your secrets deserve better than hardcoding. SecretFetch makes secret management a breeze!
You're building a Go application and need to manage secrets. You've got a few options, but none of them are great:
- Hardcode them (Please don't! π)
- Use environment variables (Manual management, no validation, scattered across your codebase)
- Use AWS Secrets Manager directly (Complex API, no caching, lots of boilerplate)
- Write your own solution (Time-consuming, error-prone, reinventing the wheel)
What if you could have:
- The simplicity of environment variables
- The security of AWS Secrets Manager
- Built-in caching and validation
- All with just a few struct tags?
That's where SecretFetch comes in! π
SecretFetch gives you the best of all worlds:
- π― Dead Simple API - Just add struct tags and go!
- π Multi-Source Support - AWS Secrets Manager, env vars, and fallbacks in one place
- π Type Safety - Automatic type conversion for strings, numbers, durations, and more
- β‘ Performance - Built-in caching to reduce AWS API calls
- π‘οΈ Validation - Pattern matching and custom validators to catch issues early
- π§ Flexibility - Transform values, decode base64, parse JSON/YAML
- πββοΈ Zero Config - Works out of the box with sane defaults
- π Testability - Mock AWS Secrets Manager for unit testing
go get github.com/crazywolf132/secretfetch
type Config struct {
// Get from AWS, fallback to env var
APIKey string `secret:"aws=prod/api/key,env=API_KEY"`
// Validate email format
Email string `secret:"env=EMAIL,pattern=^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$"`
// Parse duration with fallback
Timeout time.Duration `secret:"env=TIMEOUT,fallback=30s"`
}
cfg := &Config{}
if err := secretfetch.Fetch(context.Background(), cfg, nil); err != nil {
log.Fatal(err)
}
// Option 1: Parse JSON secrets
type DatabaseConfig struct {
Host string `json:"host"`
Username string `json:"username"`
Password string `json:"password"`
}
type Config struct {
// Parse entire database config from AWS Secrets Manager
DB DatabaseConfig `secret:"aws=prod/db/config,json"`
}
// Option 2: Preload ARNs for better performance
opts := &secretfetch.Options{
PreloadARNs: true, // Enable ARN preloading
AWS: &aws.Config{ // Optional: provide custom AWS config
Region: "us-west-2",
},
}
// Configure ARNs through environment variables
// In development:
os.Setenv("SECRET_ARNS", "arn:aws:secretsmanager:region:account:secret:name1,arn:aws:secretsmanager:region:account:secret:name2")
// or
os.Setenv("SECRET_ARN", "arn:aws:secretsmanager:region:account:secret:name")
// In production (ECS/Docker), configure in your task definition or docker-compose:
/*
# ECS Task Definition
{
"containerDefinitions": [
{
"environment": [
{
"name": "SECRET_ARNS",
"value": "arn:aws:secretsmanager:region:account:secret:name1,arn:aws:secretsmanager:region:account:secret:name2"
}
]
}
]
}
# docker-compose.yml
services:
app:
environment:
- SECRET_ARNS=arn:aws:secretsmanager:region:account:secret:name1,arn:aws:secretsmanager:region:account:secret:name2
*/
type Config struct {
// Validate IP address format
IPAddr string `secret:"env=IP,pattern=((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)"`
// Validate semantic version
Version string `secret:"env=VERSION,pattern=v[0-9]+\\.[0-9]+\\.[0-9]+"`
}
opts := &secretfetch.Options{
Transformers: map[string]secretfetch.TransformFunc{
"API_KEY": func(value string) (string, error) {
return strings.TrimSpace(value), nil
},
},
}
opts := &secretfetch.Options{
CacheDuration: 5 * time.Minute, // Cache secrets for 5 minutes
}
SecretFetch makes testing a breeze with its mock interfaces:
// Mock AWS Secrets Manager client for testing
type mockSecretsManagerClient struct {
getSecretValueFn func(ctx context.Context, params *secretsmanager.GetSecretValueInput, optFns ...func(*secretsmanager.Options)) (*secretsmanager.GetSecretValueOutput, error)
}
func (m *mockSecretsManagerClient) GetSecretValue(ctx context.Context, params *secretsmanager.GetSecretValueInput, optFns ...func(*secretsmanager.Options)) (*secretsmanager.GetSecretValueOutput, error) {
return m.getSecretValueFn(ctx, params, optFns...)
}
// Use in tests
opts := &secretfetch.Options{
SecretsManager: &mockSecretsManagerClient{
getSecretValueFn: func(ctx context.Context, params *secretsmanager.GetSecretValueInput, optFns ...func(*secretsmanager.Options)) (*secretsmanager.GetSecretValueOutput, error) {
return &secretsmanager.GetSecretValueOutput{
SecretString: aws.String("test-secret-value"),
}, nil
},
},
}
SecretFetch is built with enterprise-grade security in mind:
opts := &secretfetch.Options{
SecureCache: true, // Enable secure memory for caching
}
- Zero-copy memory handling
- Automatic memory zeroing
- Thread-safe operations
- Optional secure caching
opts := &secretfetch.Options{
OnSecretAccess: func(ctx context.Context, secretID string) {
audit.Log("Secret accessed", "id", secretID)
},
MetricsCollector: &metrics.SecurityMetrics{
OnSecretAccess: func(metric metrics.SecretAccessMetric) {
prometheus.SecretAccessCounter.Inc()
},
},
}
- Detailed audit logging
- Prometheus metrics integration
- Access tracking
- Compliance reporting
- IAM role support
- VPC endpoint compatibility
- KMS integration
- CloudTrail logging
See our SECURITY.md for detailed security documentation and enterprise compliance information.
- π Less Code - No more AWS boilerplate
- π Built-in Caching - Reduce API calls automatically
- π― Type Safety - Automatic type conversion
- β¨ Validation - Catch issues before they hit production
- π Multi-Source - Use AWS for production, env vars for development
- π‘οΈ Validation - Pattern matching and custom validators
- π Transformation - Process values before use
- π¦ Structured Data - Parse JSON/YAML automatically
- π― Simple API - Just use struct tags
- π Performance - Smart caching built-in
- π§ Flexible - Multiple sources, validation, transformation
- π Well Documented - Comprehensive examples and guides
type Options struct {
// AWS configuration
AWS *aws.Config
// Custom validation functions
Validators map[string]ValidationFunc
// Custom transformation functions
Transformers map[string]TransformFunc
// Cache duration for secrets
CacheDuration time.Duration
// Enable ARN preloading
PreloadARNs bool
// Custom Secrets Manager client for testing
SecretsManager SecretsManagerClient
}
Found a bug? Have a cool idea? Want to make SecretFetch even more awesome? We'd love your help! Feel free to:
- π Open an issue
- π Submit a PR
- π Give us a star
- π Improve our docs
This project is licensed under the MIT License - see the LICENSE file for details.
Made with β€οΈ by Brayden