Skip to content

Commit

Permalink
fix: config loaded debug statement logs secrets
Browse files Browse the repository at this point in the history
  • Loading branch information
mustyantsev committed Jun 20, 2024
1 parent 55cc045 commit ce5e138
Show file tree
Hide file tree
Showing 3 changed files with 198 additions and 1 deletion.
5 changes: 4 additions & 1 deletion service/pkg/server/start.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import (
"github.com/opentdf/platform/service/internal/logger"
"github.com/opentdf/platform/service/internal/opa"
"github.com/opentdf/platform/service/internal/server"
"github.com/opentdf/platform/service/pkg/util"
wellknown "github.com/opentdf/platform/service/wellknownconfiguration"
)

Expand Down Expand Up @@ -59,7 +60,9 @@ func Start(f ...StartOptions) error {
// Set default for places we can't pass the logger
slog.SetDefault(logger.Logger)

logger.Debug("config loaded", slog.Any("config", conf))
sensitiveWords := []string{"password", "clientsecret"}
redactedConf := util.RedactSensitiveData(conf, sensitiveWords)
logger.Debug("config loaded", slog.Any("config", redactedConf))

logger.Info("starting opa engine")
eng, err := opa.NewEngine(conf.OPA)
Expand Down
64 changes: 64 additions & 0 deletions service/pkg/util/redact.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package util

import (
"reflect"
"strings"
)

func RedactSensitiveData(i interface{}, sensitiveFields []string) interface{} {
v := reflect.ValueOf(i)
redacted := redact(v, sensitiveFields)
return redacted.Interface()
}

func redact(v reflect.Value, sensitiveFields []string) reflect.Value {
switch v.Kind() {

Check failure on line 15 in service/pkg/util/redact.go

View workflow job for this annotation

GitHub Actions / go (service)

missing cases in switch of type reflect.Kind: reflect.Invalid, reflect.Bool, reflect.Int, reflect.Int8, reflect.Int16, reflect.Int32, reflect.Int64, reflect.Uint, reflect.Uint8, reflect.Uint16, reflect.Uint32, reflect.Uint64, reflect.Uintptr, reflect.Float32, reflect.Float64, reflect.Complex64, reflect.Complex128, reflect.Array, reflect.Chan, reflect.Func, reflect.Interface, reflect.String, reflect.UnsafePointer (exhaustive)
case reflect.Ptr:
if v.IsNil() {
return v
}
redacted := reflect.New(v.Elem().Type())
redacted.Elem().Set(redact(v.Elem(), sensitiveFields))
return redacted
case reflect.Struct:
redacted := reflect.New(v.Type()).Elem()
for i := 0; i < v.NumField(); i++ {
field := v.Field(i)
fieldType := v.Type().Field(i)
if fieldType.Type.Kind() == reflect.String && contains(sensitiveFields, fieldType.Name) {
redacted.Field(i).SetString("REDACTED")
} else {
redacted.Field(i).Set(redact(field, sensitiveFields))
}
}
return redacted
case reflect.Map:
redacted := reflect.MakeMap(v.Type())
for _, key := range v.MapKeys() {
val := v.MapIndex(key)
if key.Kind() == reflect.String && contains(sensitiveFields, key.String()) {
redacted.SetMapIndex(key, reflect.ValueOf("REDACTED"))
} else {
redacted.SetMapIndex(key, redact(val, sensitiveFields))
}
}
return redacted
case reflect.Slice:
redacted := reflect.MakeSlice(v.Type(), v.Len(), v.Cap())
for i := 0; i < v.Len(); i++ {
redacted.Index(i).Set(redact(v.Index(i), sensitiveFields))
}
return redacted
default:
return v
}
}

func contains(slice []string, item string) bool {
for _, a := range slice {
if strings.EqualFold(a, item) {
return true
}
}
return false
}
130 changes: 130 additions & 0 deletions service/pkg/util/redact_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,130 @@
package util

import (
"encoding/json"
"testing"
)

type DBConfig struct {
Host string `json:"host"`
Port int `json:"port"`
Database string `json:"database"`
User string `json:"user"`
Password string `json:"password"`
RunMigrations bool `json:"runMigrations"`
SSLMode string `json:"sslmode"`
Schema string `json:"schema"`
VerifyConnection bool `json:"verifyConnection"`
}

type Config struct {
DevMode bool `json:"devMode"`
DB DBConfig `json:"db"`
Services map[string]struct {
Enabled bool `json:"enabled"`
Remote struct {
Endpoint string `json:"endpoint"`
} `json:"remote"`
ExtraProps map[string]interface{} `json:"extraProps"`
} `json:"services"`
}

func TestRedactSensitiveData_WithSensitiveFieldsInNestedStruct(t *testing.T) {
rawConfig := `{
"DevMode": false,
"DB": {
"Host": "localhost",
"Port": 5432,
"Database": "opentdf",
"User": "postgres",
"Password": "changeme",
"RunMigrations": true,
"SSLMode": "prefer",
"Schema": "opentdf",
"VerifyConnection": true
},
"Services": {
"authorization": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {
"clientid": "tdf-authorization-svc",
"clientsecret": "secret",
"ersurl": "http://localhost:8080/entityresolution/resolve",
"tokenendpoint": "http://localhost:8888/auth/realms/opentdf/protocol/openid-connect/token"
}
},
"entityresolution": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {
"clientid": "tdf-entity-resolution",
"clientsecret": "secret",
"legacykeycloak": true,
"realm": "opentdf",
"url": "http://localhost:8888/auth"
}
},
"health": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {}
},
"kas": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {
"keyring": [
{"alg": "ec:secp256r1", "kid": "e1"},
{"alg": "ec:secp256r1", "kid": "e1", "legacy": true},
{"alg": "rsa:2048", "kid": "r1"},
{"alg": "rsa:2048", "kid": "r1", "legacy": true}
]
}
},
"policy": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {}
},
"wellknown": {
"Enabled": true,
"Remote": {
"Endpoint": ""
},
"ExtraProps": {}
}
}
}`

var config Config
json.Unmarshal([]byte(rawConfig), &config)

Check failure on line 111 in service/pkg/util/redact_test.go

View workflow job for this annotation

GitHub Actions / go (service)

Error return value of `json.Unmarshal` is not checked (errcheck)

sensitiveFields := []string{"Password", "clientsecret"}
redacted := RedactSensitiveData(config, sensitiveFields)

redactedConfig, ok := redacted.(Config)
if !ok {
t.Fatalf("Expected redacted data to be of type Config")
}

if redactedConfig.DB.Password != "REDACTED" {
t.Errorf("Expected DB.Password to be redacted")
}

for _, service := range redactedConfig.Services {
if clientSecret, ok := service.ExtraProps["clientsecret"]; ok && clientSecret != "REDACTED" {

Check failure on line 126 in service/pkg/util/redact_test.go

View workflow job for this annotation

GitHub Actions / go (service)

shadow: declaration of "ok" shadows declaration at line 116 (govet)
t.Errorf("Expected Services.ExtraProps.ClientSecret to be redacted")
}
}
}

0 comments on commit ce5e138

Please sign in to comment.