Initial commit: Open sourcing all of the Maple Open Technologies code.
This commit is contained in:
commit
755d54a99d
2010 changed files with 448675 additions and 0 deletions
|
|
@ -0,0 +1,10 @@
|
|||
package secureconfig
|
||||
|
||||
import (
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
)
|
||||
|
||||
// ProvideSecureConfigProvider provides a SecureConfigProvider for Wire DI.
|
||||
func ProvideSecureConfigProvider(cfg *config.Config) *SecureConfigProvider {
|
||||
return NewSecureConfigProvider(cfg)
|
||||
}
|
||||
|
|
@ -0,0 +1,187 @@
|
|||
// Package secureconfig provides secure access to configuration secrets.
|
||||
// It wraps sensitive configuration values in memguard-protected buffers
|
||||
// to prevent secret leakage through memory dumps.
|
||||
package secureconfig
|
||||
|
||||
import (
|
||||
"sync"
|
||||
|
||||
"github.com/awnumar/memguard"
|
||||
|
||||
"codeberg.org/mapleopentech/monorepo/cloud/maplefile-backend/config"
|
||||
)
|
||||
|
||||
// SecureConfigProvider provides secure access to configuration secrets.
|
||||
// Secrets are stored in memguard LockedBuffers and wiped when no longer needed.
|
||||
type SecureConfigProvider struct {
|
||||
mu sync.RWMutex
|
||||
|
||||
// Cached secure buffers - created on first access
|
||||
jwtSecret *memguard.LockedBuffer
|
||||
dbPassword *memguard.LockedBuffer
|
||||
cachePassword *memguard.LockedBuffer
|
||||
s3AccessKey *memguard.LockedBuffer
|
||||
s3SecretKey *memguard.LockedBuffer
|
||||
mailgunAPIKey *memguard.LockedBuffer
|
||||
|
||||
// Original config for initial loading
|
||||
cfg *config.Config
|
||||
}
|
||||
|
||||
// NewSecureConfigProvider creates a new secure config provider from the given config.
|
||||
// The original config secrets are copied to secure buffers and should be cleared
|
||||
// from the original config after this call.
|
||||
func NewSecureConfigProvider(cfg *config.Config) *SecureConfigProvider {
|
||||
provider := &SecureConfigProvider{
|
||||
cfg: cfg,
|
||||
}
|
||||
|
||||
// Pre-load secrets into secure buffers
|
||||
provider.loadSecrets()
|
||||
|
||||
return provider
|
||||
}
|
||||
|
||||
// loadSecrets copies secrets from config into memguard buffers.
|
||||
// SECURITY: Original config strings remain in memory but secure buffers provide
|
||||
// additional protection for long-lived secret access.
|
||||
func (p *SecureConfigProvider) loadSecrets() {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
// JWT Secret
|
||||
if p.cfg.JWT.Secret != "" {
|
||||
p.jwtSecret = memguard.NewBufferFromBytes([]byte(p.cfg.JWT.Secret))
|
||||
}
|
||||
|
||||
// Database Password
|
||||
if p.cfg.Database.Password != "" {
|
||||
p.dbPassword = memguard.NewBufferFromBytes([]byte(p.cfg.Database.Password))
|
||||
}
|
||||
|
||||
// Cache Password
|
||||
if p.cfg.Cache.Password != "" {
|
||||
p.cachePassword = memguard.NewBufferFromBytes([]byte(p.cfg.Cache.Password))
|
||||
}
|
||||
|
||||
// S3 Access Key
|
||||
if p.cfg.S3.AccessKey != "" {
|
||||
p.s3AccessKey = memguard.NewBufferFromBytes([]byte(p.cfg.S3.AccessKey))
|
||||
}
|
||||
|
||||
// S3 Secret Key
|
||||
if p.cfg.S3.SecretKey != "" {
|
||||
p.s3SecretKey = memguard.NewBufferFromBytes([]byte(p.cfg.S3.SecretKey))
|
||||
}
|
||||
|
||||
// Mailgun API Key
|
||||
if p.cfg.Mailgun.APIKey != "" {
|
||||
p.mailgunAPIKey = memguard.NewBufferFromBytes([]byte(p.cfg.Mailgun.APIKey))
|
||||
}
|
||||
}
|
||||
|
||||
// JWTSecret returns the JWT secret as a secure byte slice.
|
||||
// The returned bytes should not be stored - use immediately and let GC collect.
|
||||
func (p *SecureConfigProvider) JWTSecret() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.jwtSecret == nil || !p.jwtSecret.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.jwtSecret.Bytes()
|
||||
}
|
||||
|
||||
// DatabasePassword returns the database password as a secure byte slice.
|
||||
func (p *SecureConfigProvider) DatabasePassword() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.dbPassword == nil || !p.dbPassword.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.dbPassword.Bytes()
|
||||
}
|
||||
|
||||
// CachePassword returns the cache password as a secure byte slice.
|
||||
func (p *SecureConfigProvider) CachePassword() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.cachePassword == nil || !p.cachePassword.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.cachePassword.Bytes()
|
||||
}
|
||||
|
||||
// S3AccessKey returns the S3 access key as a secure byte slice.
|
||||
func (p *SecureConfigProvider) S3AccessKey() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.s3AccessKey == nil || !p.s3AccessKey.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.s3AccessKey.Bytes()
|
||||
}
|
||||
|
||||
// S3SecretKey returns the S3 secret key as a secure byte slice.
|
||||
func (p *SecureConfigProvider) S3SecretKey() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.s3SecretKey == nil || !p.s3SecretKey.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.s3SecretKey.Bytes()
|
||||
}
|
||||
|
||||
// MailgunAPIKey returns the Mailgun API key as a secure byte slice.
|
||||
func (p *SecureConfigProvider) MailgunAPIKey() []byte {
|
||||
p.mu.RLock()
|
||||
defer p.mu.RUnlock()
|
||||
|
||||
if p.mailgunAPIKey == nil || !p.mailgunAPIKey.IsAlive() {
|
||||
return nil
|
||||
}
|
||||
return p.mailgunAPIKey.Bytes()
|
||||
}
|
||||
|
||||
// Destroy securely wipes all cached secrets from memory.
|
||||
// Should be called during application shutdown.
|
||||
func (p *SecureConfigProvider) Destroy() {
|
||||
p.mu.Lock()
|
||||
defer p.mu.Unlock()
|
||||
|
||||
if p.jwtSecret != nil && p.jwtSecret.IsAlive() {
|
||||
p.jwtSecret.Destroy()
|
||||
}
|
||||
if p.dbPassword != nil && p.dbPassword.IsAlive() {
|
||||
p.dbPassword.Destroy()
|
||||
}
|
||||
if p.cachePassword != nil && p.cachePassword.IsAlive() {
|
||||
p.cachePassword.Destroy()
|
||||
}
|
||||
if p.s3AccessKey != nil && p.s3AccessKey.IsAlive() {
|
||||
p.s3AccessKey.Destroy()
|
||||
}
|
||||
if p.s3SecretKey != nil && p.s3SecretKey.IsAlive() {
|
||||
p.s3SecretKey.Destroy()
|
||||
}
|
||||
if p.mailgunAPIKey != nil && p.mailgunAPIKey.IsAlive() {
|
||||
p.mailgunAPIKey.Destroy()
|
||||
}
|
||||
|
||||
p.jwtSecret = nil
|
||||
p.dbPassword = nil
|
||||
p.cachePassword = nil
|
||||
p.s3AccessKey = nil
|
||||
p.s3SecretKey = nil
|
||||
p.mailgunAPIKey = nil
|
||||
}
|
||||
|
||||
// Config returns the underlying config for non-secret access.
|
||||
// Prefer using the specific secret accessor methods for sensitive data.
|
||||
func (p *SecureConfigProvider) Config() *config.Config {
|
||||
return p.cfg
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue