diff --git a/internal/pkg/config/config.go b/internal/pkg/config/config.go index 7bdc0df58..8fe13f60b 100644 --- a/internal/pkg/config/config.go +++ b/internal/pkg/config/config.go @@ -9,6 +9,7 @@ import ( "context" "errors" "slices" + "strings" "sync" "github.com/gofrs/uuid" @@ -171,9 +172,30 @@ func redactOutput(cfg *Config) Output { redacted.Elasticsearch.TLS = &newTLS } + if redacted.Elasticsearch.Headers != nil { + redacted.Elasticsearch.Headers = redactHeaders(redacted.Elasticsearch.Headers) + } + + if redacted.Elasticsearch.ProxyHeaders != nil { + redacted.Elasticsearch.ProxyHeaders = redactHeaders(redacted.Elasticsearch.ProxyHeaders) + } return redacted } +// redactHeaders returns a copy of the passed headers map. +// It will do a best-effort attempt to redact sensitive headers based on header names. +func redactHeaders(headers map[string]string) map[string]string { + redactedHeaders := make(map[string]string) + for k, v := range headers { + redactedHeaders[k] = v + lk := strings.ToLower(k) + if strings.Contains(lk, "auth") || strings.Contains(lk, "token") || strings.Contains(lk, "key") || strings.Contains(lk, "bearer") { + redactedHeaders[k] = kRedacted + } + } + return redactedHeaders +} + func redactServer(cfg *Config) Server { redacted := cfg.Inputs[0].Server @@ -198,6 +220,17 @@ func redactServer(cfg *Config) Server { redacted.Instrumentation.SecretToken = kRedacted } + if redacted.StaticPolicyTokens.PolicyTokens != nil { + policyTokens := make([]PolicyToken, len(redacted.StaticPolicyTokens.PolicyTokens)) + for i := range redacted.StaticPolicyTokens.PolicyTokens { + policyTokens[i] = PolicyToken{ + TokenKey: kRedacted, + PolicyID: redacted.StaticPolicyTokens.PolicyTokens[i].PolicyID, + } + } + redacted.StaticPolicyTokens.PolicyTokens = policyTokens + } + return redacted } diff --git a/internal/pkg/config/config_test.go b/internal/pkg/config/config_test.go index 384030996..3a3a18b52 100644 --- a/internal/pkg/config/config_test.go +++ b/internal/pkg/config/config_test.go @@ -423,6 +423,85 @@ func TestConfigRedact(t *testing.T) { }, }, }, + { + name: "Redact custom output headers", + inputCfg: &Config{ + Inputs: []Input{{}}, + Output: Output{ + Elasticsearch: Elasticsearch{ + Protocol: "https", + Hosts: []string{"localhost:9200"}, + Headers: map[string]string{"X-Authorization": "secretValue", "X-Custom": "value", "X-App-Token": "customToken", "X-App-Key": "secretKey", "X-Custom-Bearer": "secretBearer"}, + ServiceTokenPath: "path/to/file", + }, + }, + }, + redactedCfg: &Config{ + Inputs: []Input{{}}, + Output: Output{ + Elasticsearch: Elasticsearch{ + Protocol: "https", + Hosts: []string{"localhost:9200"}, + Headers: map[string]string{"X-Authorization": kRedacted, "X-Custom": "value", "X-App-Token": kRedacted, "X-App-Key": kRedacted, "X-Custom-Bearer": kRedacted}, + ServiceTokenPath: "path/to/file", + }, + }, + }, + }, + { + name: "Redact proxy authorization output header", + inputCfg: &Config{ + Inputs: []Input{{}}, + Output: Output{ + Elasticsearch: Elasticsearch{ + Protocol: "https", + Hosts: []string{"localhost:9200"}, + ProxyHeaders: map[string]string{"X-Proxy-Authorization": "secretValue"}, + ServiceTokenPath: "path/to/file", + }, + }, + }, + redactedCfg: &Config{ + Inputs: []Input{{}}, + Output: Output{ + Elasticsearch: Elasticsearch{ + Protocol: "https", + Hosts: []string{"localhost:9200"}, + ProxyHeaders: map[string]string{"X-Proxy-Authorization": kRedacted}, + ServiceTokenPath: "path/to/file", + }, + }, + }, + }, + { + name: "redact static tokens", + inputCfg: &Config{ + Inputs: []Input{{ + Server: Server{ + StaticPolicyTokens: StaticPolicyTokens{ + Enabled: true, + PolicyTokens: []PolicyToken{{ + TokenKey: "secretValue", + PolicyID: "testPolicy", + }}, + }, + }, + }}, + }, + redactedCfg: &Config{ + Inputs: []Input{{ + Server: Server{ + StaticPolicyTokens: StaticPolicyTokens{ + Enabled: true, + PolicyTokens: []PolicyToken{{ + TokenKey: kRedacted, + PolicyID: "testPolicy", + }}, + }, + }, + }}, + }, + }, } for _, tt := range testcases {