This commit is contained in:
2025-08-23 22:31:47 -04:00
parent 9ca9c53baf
commit e5bccc85c2
22 changed files with 2405 additions and 209 deletions

View File

@ -36,6 +36,9 @@ type ConfigProvider interface {
// GetDatabaseDSN constructs and returns the database connection string
GetDatabaseDSN() string
// GetDatabaseDSNForLogging returns a sanitized database connection string safe for logging
GetDatabaseDSNForLogging() string
// GetServerAddress returns the server address in host:port format
GetServerAddress() string
@ -104,17 +107,20 @@ func (c *Config) setDefaults() {
"RATE_LIMIT_ENABLED": "true",
"RATE_LIMIT_RPS": "100",
"RATE_LIMIT_BURST": "200",
"AUTH_RATE_LIMIT_RPS": "5",
"AUTH_RATE_LIMIT_BURST": "10",
"CACHE_ENABLED": "false",
"CACHE_TTL": "1h",
"JWT_ISSUER": "api-key-service",
"JWT_SECRET": "bootstrap-jwt-secret-change-in-production",
"JWT_SECRET": "", // Must be set via environment variable
"AUTH_PROVIDER": "header", // header or sso
"AUTH_HEADER_USER_EMAIL": "X-User-Email",
"AUTH_SIGNING_KEY": "", // Must be set via environment variable
"SSO_PROVIDER_URL": "",
"SSO_CLIENT_ID": "",
"SSO_CLIENT_SECRET": "",
"INTERNAL_APP_ID": "internal.api-key-service",
"INTERNAL_HMAC_KEY": "bootstrap-hmac-key-change-in-production",
"INTERNAL_HMAC_KEY": "", // Must be set via environment variable
"METRICS_ENABLED": "false",
"METRICS_PORT": "9090",
"REDIS_ENABLED": "false",
@ -131,6 +137,8 @@ func (c *Config) setDefaults() {
"AUTH_FAILURE_WINDOW": "15m",
"IP_BLOCK_DURATION": "1h",
"REQUEST_MAX_AGE": "5m",
"CSRF_TOKEN_MAX_AGE": "1h",
"BCRYPT_COST": "14",
"IP_WHITELIST": "",
"SAML_ENABLED": "false",
"SAML_IDP_METADATA_URL": "",
@ -212,6 +220,7 @@ func (c *Config) Validate() error {
"INTERNAL_APP_ID",
"INTERNAL_HMAC_KEY",
"JWT_SECRET",
"AUTH_SIGNING_KEY",
}
var missing []string
@ -225,6 +234,22 @@ func (c *Config) Validate() error {
return fmt.Errorf("missing required configuration keys: %s", strings.Join(missing, ", "))
}
// Validate that production secrets are not using default values
jwtSecret := c.GetString("JWT_SECRET")
if jwtSecret == "bootstrap-jwt-secret-change-in-production" || len(jwtSecret) < 32 {
return fmt.Errorf("JWT_SECRET must be set to a secure value (minimum 32 characters)")
}
hmacKey := c.GetString("INTERNAL_HMAC_KEY")
if hmacKey == "bootstrap-hmac-key-change-in-production" || len(hmacKey) < 32 {
return fmt.Errorf("INTERNAL_HMAC_KEY must be set to a secure value (minimum 32 characters)")
}
authSigningKey := c.GetString("AUTH_SIGNING_KEY")
if len(authSigningKey) < 32 {
return fmt.Errorf("AUTH_SIGNING_KEY must be set to a secure value (minimum 32 characters)")
}
// Validate specific values
if c.GetInt("DB_PORT") <= 0 || c.GetInt("DB_PORT") > 65535 {
return fmt.Errorf("DB_PORT must be a valid port number")
@ -278,6 +303,27 @@ func (c *Config) GetDatabaseDSN() string {
)
}
// GetDatabaseDSNForLogging returns a sanitized database connection string safe for logging
func (c *Config) GetDatabaseDSNForLogging() string {
password := c.GetString("DB_PASSWORD")
maskedPassword := "***MASKED***"
if len(password) > 0 {
// Show first and last character with masking for debugging
if len(password) >= 4 {
maskedPassword = string(password[0]) + "***" + string(password[len(password)-1])
}
}
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=%s",
c.GetString("DB_HOST"),
c.GetInt("DB_PORT"),
c.GetString("DB_USER"),
maskedPassword,
c.GetString("DB_NAME"),
c.GetString("DB_SSLMODE"),
)
}
// GetServerAddress returns the server address in host:port format
func (c *Config) GetServerAddress() string {
return fmt.Sprintf("%s:%d", c.GetString("SERVER_HOST"), c.GetInt("SERVER_PORT"))