Documentation
¶
Overview ¶
Package sanitization provides DD-005 compliant log sanitization utilities.
This package consolidates sanitization logic.
Migration Status (December 2025): - pkg/notification/sanitization/sanitizer.go → MIGRATED ✅ (uses this package) - pkg/gateway/middleware/log_sanitization.go → DELETED ✅ (migrated Dec 9, 2025)
All services MUST use this package for log sanitization to ensure: - Consistent redaction patterns across the codebase - DD-005 compliance (Observability Standards) - Security: No sensitive data in logs (CVSS 5.3)
Usage ¶
For simple string sanitization:
sanitized := sanitization.SanitizeForLog(sensitiveData)
logger.Info("Processing request", "payload", sanitized)
For HTTP middleware:
router.Use(sanitization.NewLoggingMiddleware(logger))
For notification content:
sanitizer := sanitization.NewSanitizer() clean, err := sanitizer.SanitizeWithFallback(content)
Patterns Covered ¶
The sanitizer redacts the following sensitive patterns:
- Passwords: password, passwd, pwd (JSON, URL, plain text)
- API Keys: api_key, apikey, OpenAI (sk-*), AWS keys
- Tokens: Bearer, GitHub (ghp_*), access_token, generic token
- Secrets: secret, client_secret, credential
- Database URLs: PostgreSQL, MySQL, MongoDB connection strings
- Certificates: PEM certificates, private keys
- Kubernetes: Secret data (base64 encoded)
- HTTP Headers: Authorization, Bearer, X-API-Key
DD-005 Compliance ¶
Authority: docs/architecture/decisions/DD-005-OBSERVABILITY-STANDARDS.md
Per DD-005 Lines 519-555:
"Sensitive data MUST be redacted before logging" "Sensitive Fields (MUST be redacted): password, token, api_key, secret, authorization"
Business Requirements ¶
- BR-GATEWAY-078: Redact sensitive data from logs
- BR-GATEWAY-079: Prevent information disclosure through logs
- BR-NOT-055: Graceful degradation for sanitization failures
- BR-STORAGE-XXX: Log sanitization (pending implementation)
Security ¶
- VULN-GATEWAY-004: Prevents sensitive data exposure in logs (CVSS 5.3)
Index ¶
- Constants
- Variables
- func AddSensitiveHeader(headerName string)
- func IsHeaderSensitive(headerName string) bool
- func IsIDLikeSegment(segment string) bool
- func NormalizePath(path string) string
- func NormalizePathWithPlaceholder(path string) string
- func SanitizeForLog(data string) string
- func SanitizeHeaders(headers http.Header) string
- func SanitizeHeadersToMap(headers http.Header) map[string][]string
- type Rule
- type Sanitizer
Constants ¶
const ( PathPlaceholderID = ":id" // For UUIDs and numeric IDs PathPlaceholderUUID = ":uuid" // Specifically for UUIDs PathPlaceholderNum = ":num" // Specifically for numeric IDs )
Path placeholders for normalized segments
const RedactedPlaceholder = "[REDACTED]"
RedactedPlaceholder is the standard replacement for sensitive data. Use this constant for consistency across the codebase.
Variables ¶
var SensitiveHeaderNames = []string{
"authorization",
"x-api-key",
"x-auth-token",
"x-access-token",
"cookie",
"set-cookie",
"proxy-authorization",
"www-authenticate",
"bearer",
"token",
"password",
"secret",
"api_key",
"apikey",
}
SensitiveHeaderNames contains header names that should always be redacted. Case-insensitive matching is used.
Functions ¶
func AddSensitiveHeader ¶
func AddSensitiveHeader(headerName string)
AddSensitiveHeader adds a custom header name to the sensitive list. Use this for service-specific headers that should be redacted.
Example:
sanitization.AddSensitiveHeader("x-custom-secret")
func IsHeaderSensitive ¶
IsHeaderSensitive checks if a header name contains sensitive keywords. Uses case-insensitive matching against known sensitive header patterns.
func IsIDLikeSegment ¶
IsIDLikeSegment checks if a path segment looks like a dynamic ID. Useful for custom normalization logic.
func NormalizePath ¶
NormalizePath replaces dynamic path segments with placeholders. This prevents high-cardinality metrics from overwhelming Prometheus.
DD-005 Compliance: Per lines 689-710, path normalization is MANDATORY for all services exposing HTTP metrics.
Example:
NormalizePath("/api/v1/users/123/orders/abc-def-123")
// Returns: "/api/v1/users/:id/orders/:id"
NormalizePath("/api/v1/events/550e8400-e29b-41d4-a716-446655440000")
// Returns: "/api/v1/events/:id"
func NormalizePathWithPlaceholder ¶
NormalizePathWithPlaceholder normalizes using specific placeholder types. Use this when you need to distinguish between UUIDs and numeric IDs.
Example:
NormalizePathWithPlaceholder("/users/123")
// Returns: "/users/:num"
NormalizePathWithPlaceholder("/users/550e8400-e29b-41d4-a716-446655440000")
// Returns: "/users/:uuid"
func SanitizeForLog ¶
SanitizeForLog is a convenience function for quick sanitization. Use this for one-off sanitization without creating a Sanitizer instance.
Example:
logger.Info("Request", "body", sanitization.SanitizeForLog(body))
func SanitizeHeaders ¶
SanitizeHeaders redacts sensitive information from HTTP headers. Returns a string representation suitable for logging.
Example:
headers := http.Header{"Authorization": {"Bearer secret"}, "Content-Type": {"application/json"}}
sanitized := sanitization.SanitizeHeaders(headers)
// Returns: "Authorization: [REDACTED], Content-Type: application/json"
Types ¶
type Rule ¶
type Rule struct {
Name string // Human-readable name for debugging
Pattern *regexp.Regexp // Regex pattern to match sensitive data
Replacement string // Replacement string (may use capture groups)
Description string // Description of what this rule redacts
}
Rule defines a pattern-based sanitization rule. Each rule matches a specific type of sensitive data and replaces it.
func DefaultRules ¶
func DefaultRules() []*Rule
DefaultRules returns the comprehensive set of sanitization rules. These cover the most common sensitive data patterns.
IMPORTANT: Pattern order matters! Container patterns (generatorURL, annotations) must come FIRST to prevent sub-patterns from corrupting larger structures.
type Sanitizer ¶
type Sanitizer struct {
// contains filtered or unexported fields
}
Sanitizer provides configurable log sanitization. Use NewSanitizer() to create with default patterns, or NewSanitizerWithRules() for custom patterns.
func NewSanitizer ¶
func NewSanitizer() *Sanitizer
NewSanitizer creates a sanitizer with comprehensive default patterns. Covers passwords, API keys, tokens, database URLs, certificates, etc.
func NewSanitizerWithRules ¶
NewSanitizerWithRules creates a sanitizer with custom rules. Use this when you need service-specific patterns.
func (*Sanitizer) SafeFallback ¶
SafeFallback provides simple string-based sanitization without regex. Used when regex engine fails or for ultra-safe processing. Uses simple string matching which cannot panic.
func (*Sanitizer) Sanitize ¶
Sanitize applies all rules to redact sensitive data from content. Returns the sanitized content with sensitive data replaced.
Example:
s := sanitization.NewSanitizer()
clean := s.Sanitize(`{"password":"secret123"}`)
// Returns: `{"password":"[REDACTED]"}`
func (*Sanitizer) SanitizeWithFallback ¶
SanitizeWithFallback sanitizes content with automatic fallback on errors. If regex processing fails (e.g., panic), falls back to simple string matching.
This implements graceful degradation per BR-NOT-055: - When: Redaction logic error, malformed data - Action: Log error, use fallback sanitization - Recovery: Automatic (degraded but safe)
Returns the sanitized content and any error that occurred.